exercism-analysis 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/exercism-analysis.gemspec +30 -0
- data/lib/exercism-analysis.rb +38 -0
- data/lib/exercism-analysis/adapters/adapter.rb +23 -0
- data/lib/exercism-analysis/adapters/clojure.rb +13 -0
- data/lib/exercism-analysis/adapters/go.rb +19 -0
- data/lib/exercism-analysis/adapters/javascript.rb +13 -0
- data/lib/exercism-analysis/adapters/python.rb +13 -0
- data/lib/exercism-analysis/adapters/ruby.rb +19 -0
- data/lib/exercism-analysis/analysis.rb +18 -0
- data/lib/exercism-analysis/analyzers/analyzer.rb +54 -0
- data/lib/exercism-analysis/analyzers/clojure/kibit.rb +25 -0
- data/lib/exercism-analysis/analyzers/go/golint.rb +23 -0
- data/lib/exercism-analysis/analyzers/javascript/jslint.rb +24 -0
- data/lib/exercism-analysis/analyzers/python/pylint.rb +24 -0
- data/lib/exercism-analysis/analyzers/ruby/control_flow.rb +21 -0
- data/lib/exercism-analysis/analyzers/ruby/enumerable_condition.rb +21 -0
- data/lib/exercism-analysis/analyzers/ruby/for_loop.rb +29 -0
- data/lib/exercism-analysis/analyzers/ruby/indentation.rb +21 -0
- data/lib/exercism-analysis/analyzers/ruby/iter_mutation.rb +37 -0
- data/lib/exercism-analysis/analyzers/ruby/output.rb +20 -0
- data/lib/exercism-analysis/analyzers/ruby/range.rb +28 -0
- data/lib/exercism-analysis/analyzers/ruby/roodi.rb +19 -0
- data/lib/exercism-analysis/analyzers/ruby/send.rb +25 -0
- data/lib/exercism-analysis/analyzers/ruby/shebang.rb +23 -0
- data/lib/exercism-analysis/analyzers/ruby/tab.rb +38 -0
- data/lib/exercism-analysis/processors/call_processor.rb +39 -0
- data/lib/exercism-analysis/processors/control_flow_processor.rb +27 -0
- data/lib/exercism-analysis/processors/enumerable_condition_processor.rb +31 -0
- data/lib/exercism-analysis/processors/for_loop_processor.rb +21 -0
- data/lib/exercism-analysis/processors/indentation_processor.rb +69 -0
- data/lib/exercism-analysis/processors/iter_mutation_processor.rb +50 -0
- data/lib/exercism-analysis/processors/processor.rb +34 -0
- data/lib/exercism-analysis/processors/range_processor.rb +23 -0
- data/lib/exercism-analysis/processors/send_processor.rb +23 -0
- data/lib/exercism-analysis/templates/each_to_map.rb +29 -0
- data/lib/exercism-analysis/templates/each_to_select.rb +31 -0
- data/lib/exercism-analysis/templates/range_exclusive.rb +19 -0
- data/lib/exercism-analysis/templates/template.rb +29 -0
- data/vendor/clojure/kibit-runner/LICENSE +214 -0
- data/vendor/clojure/kibit-runner/project.clj +10 -0
- data/vendor/clojure/kibit-runner/src/kibit_runner/core.clj +17 -0
- data/vendor/clojure/kibit-runner/target/kibit-runner-0.1.0-SNAPSHOT-standalone.jar +0 -0
- data/vendor/clojure/kibit-runner/target/kibit-runner-0.1.0-SNAPSHOT.jar +0 -0
- data/vendor/clojure/kibit-runner/target/stale/extract-native.dependencies +1 -0
- data/vendor/go/src/github.com/golang/lint/LICENSE +27 -0
- data/vendor/go/src/github.com/golang/lint/README +59 -0
- data/vendor/go/src/github.com/golang/lint/golint/golint.go +67 -0
- data/vendor/go/src/github.com/golang/lint/lint.go +1061 -0
- data/vendor/go/src/runner/golint_runner.go +23 -0
- data/vendor/javascript/jshint_runner.js +6 -0
- data/vendor/javascript/node_modules/jshint/README.md +47 -0
- data/vendor/javascript/node_modules/jshint/bin/apply +6 -0
- data/vendor/javascript/node_modules/jshint/bin/build +36 -0
- data/vendor/javascript/node_modules/jshint/bin/changelog +36 -0
- data/vendor/javascript/node_modules/jshint/bin/jshint +3 -0
- data/vendor/javascript/node_modules/jshint/bin/land +34 -0
- data/vendor/javascript/node_modules/jshint/data/ascii-identifier-data.js +22 -0
- data/vendor/javascript/node_modules/jshint/data/non-ascii-identifier-part-only.js +1570 -0
- data/vendor/javascript/node_modules/jshint/data/non-ascii-identifier-start.js +48477 -0
- data/vendor/javascript/node_modules/jshint/dist/jshint-rhino.js +60642 -0
- data/vendor/javascript/node_modules/jshint/dist/jshint.js +60525 -0
- data/vendor/javascript/node_modules/jshint/node_modules/cli/README.md +196 -0
- data/vendor/javascript/node_modules/jshint/node_modules/cli/cli.js +1139 -0
- data/vendor/javascript/node_modules/jshint/node_modules/cli/examples/cat.js +17 -0
- data/vendor/javascript/node_modules/jshint/node_modules/cli/examples/command.js +16 -0
- data/vendor/javascript/node_modules/jshint/node_modules/cli/examples/echo.js +54 -0
- data/vendor/javascript/node_modules/jshint/node_modules/cli/examples/glob.js +6 -0
- data/vendor/javascript/node_modules/jshint/node_modules/cli/examples/long_desc.js +20 -0
- data/vendor/javascript/node_modules/jshint/node_modules/cli/examples/progress.js +11 -0
- data/vendor/javascript/node_modules/jshint/node_modules/cli/examples/sort.js +18 -0
- data/vendor/javascript/node_modules/jshint/node_modules/cli/examples/spinner.js +9 -0
- data/vendor/javascript/node_modules/jshint/node_modules/cli/examples/static.coffee +27 -0
- data/vendor/javascript/node_modules/jshint/node_modules/cli/examples/static.js +25 -0
- data/vendor/javascript/node_modules/jshint/node_modules/cli/index.js +1 -0
- data/vendor/javascript/node_modules/jshint/node_modules/cli/node_modules/glob/LICENSE +27 -0
- data/vendor/javascript/node_modules/jshint/node_modules/cli/node_modules/glob/README.md +250 -0
- data/vendor/javascript/node_modules/jshint/node_modules/cli/node_modules/glob/examples/g.js +9 -0
- data/vendor/javascript/node_modules/jshint/node_modules/cli/node_modules/glob/examples/usr-local.js +9 -0
- data/vendor/javascript/node_modules/jshint/node_modules/cli/node_modules/glob/glob.js +728 -0
- data/vendor/javascript/node_modules/jshint/node_modules/cli/node_modules/glob/node_modules/inherits/LICENSE +16 -0
- data/vendor/javascript/node_modules/jshint/node_modules/cli/node_modules/glob/node_modules/inherits/README.md +42 -0
- data/vendor/javascript/node_modules/jshint/node_modules/cli/node_modules/glob/node_modules/inherits/inherits.js +1 -0
- data/vendor/javascript/node_modules/jshint/node_modules/cli/node_modules/glob/node_modules/inherits/inherits_browser.js +23 -0
- data/vendor/javascript/node_modules/jshint/node_modules/cli/node_modules/glob/node_modules/inherits/package.json +51 -0
- data/vendor/javascript/node_modules/jshint/node_modules/cli/node_modules/glob/node_modules/inherits/test.js +25 -0
- data/vendor/javascript/node_modules/jshint/node_modules/cli/node_modules/glob/package.json +58 -0
- data/vendor/javascript/node_modules/jshint/node_modules/cli/node_modules/glob/test/00-setup.js +176 -0
- data/vendor/javascript/node_modules/jshint/node_modules/cli/node_modules/glob/test/bash-comparison.js +63 -0
- data/vendor/javascript/node_modules/jshint/node_modules/cli/node_modules/glob/test/bash-results.json +351 -0
- data/vendor/javascript/node_modules/jshint/node_modules/cli/node_modules/glob/test/cwd-test.js +55 -0
- data/vendor/javascript/node_modules/jshint/node_modules/cli/node_modules/glob/test/globstar-match.js +19 -0
- data/vendor/javascript/node_modules/jshint/node_modules/cli/node_modules/glob/test/mark.js +118 -0
- data/vendor/javascript/node_modules/jshint/node_modules/cli/node_modules/glob/test/new-glob-optional-options.js +10 -0
- data/vendor/javascript/node_modules/jshint/node_modules/cli/node_modules/glob/test/nocase-nomagic.js +113 -0
- data/vendor/javascript/node_modules/jshint/node_modules/cli/node_modules/glob/test/pause-resume.js +73 -0
- data/vendor/javascript/node_modules/jshint/node_modules/cli/node_modules/glob/test/readme-issue.js +36 -0
- data/vendor/javascript/node_modules/jshint/node_modules/cli/node_modules/glob/test/root-nomount.js +39 -0
- data/vendor/javascript/node_modules/jshint/node_modules/cli/node_modules/glob/test/root.js +46 -0
- data/vendor/javascript/node_modules/jshint/node_modules/cli/node_modules/glob/test/stat.js +32 -0
- data/vendor/javascript/node_modules/jshint/node_modules/cli/node_modules/glob/test/zz-cleanup.js +11 -0
- data/vendor/javascript/node_modules/jshint/node_modules/cli/package.json +70 -0
- data/vendor/javascript/node_modules/jshint/node_modules/console-browserify/LICENCE +19 -0
- data/vendor/javascript/node_modules/jshint/node_modules/console-browserify/README.md +33 -0
- data/vendor/javascript/node_modules/jshint/node_modules/console-browserify/index.js +86 -0
- data/vendor/javascript/node_modules/jshint/node_modules/console-browserify/node_modules/date-now/LICENCE +19 -0
- data/vendor/javascript/node_modules/jshint/node_modules/console-browserify/node_modules/date-now/README.md +45 -0
- data/vendor/javascript/node_modules/jshint/node_modules/console-browserify/node_modules/date-now/index.js +5 -0
- data/vendor/javascript/node_modules/jshint/node_modules/console-browserify/node_modules/date-now/package.json +89 -0
- data/vendor/javascript/node_modules/jshint/node_modules/console-browserify/node_modules/date-now/seed.js +16 -0
- data/vendor/javascript/node_modules/jshint/node_modules/console-browserify/node_modules/date-now/test/index.js +28 -0
- data/vendor/javascript/node_modules/jshint/node_modules/console-browserify/node_modules/date-now/test/static/index.html +10 -0
- data/vendor/javascript/node_modules/jshint/node_modules/console-browserify/package.json +88 -0
- data/vendor/javascript/node_modules/jshint/node_modules/console-browserify/test/index.js +67 -0
- data/vendor/javascript/node_modules/jshint/node_modules/console-browserify/test/static/index.html +12 -0
- data/vendor/javascript/node_modules/jshint/node_modules/console-browserify/test/static/test-adapter.js +53 -0
- data/vendor/javascript/node_modules/jshint/node_modules/exit/Gruntfile.js +48 -0
- data/vendor/javascript/node_modules/jshint/node_modules/exit/LICENSE-MIT +22 -0
- data/vendor/javascript/node_modules/jshint/node_modules/exit/README.md +75 -0
- data/vendor/javascript/node_modules/jshint/node_modules/exit/lib/exit.js +41 -0
- data/vendor/javascript/node_modules/jshint/node_modules/exit/package.json +69 -0
- data/vendor/javascript/node_modules/jshint/node_modules/exit/test/exit_test.js +121 -0
- data/vendor/javascript/node_modules/jshint/node_modules/exit/test/fixtures/10-stderr.txt +10 -0
- data/vendor/javascript/node_modules/jshint/node_modules/exit/test/fixtures/10-stdout-stderr.txt +20 -0
- data/vendor/javascript/node_modules/jshint/node_modules/exit/test/fixtures/10-stdout.txt +10 -0
- data/vendor/javascript/node_modules/jshint/node_modules/exit/test/fixtures/100-stderr.txt +100 -0
- data/vendor/javascript/node_modules/jshint/node_modules/exit/test/fixtures/100-stdout-stderr.txt +200 -0
- data/vendor/javascript/node_modules/jshint/node_modules/exit/test/fixtures/100-stdout.txt +100 -0
- data/vendor/javascript/node_modules/jshint/node_modules/exit/test/fixtures/1000-stderr.txt +1000 -0
- data/vendor/javascript/node_modules/jshint/node_modules/exit/test/fixtures/1000-stdout-stderr.txt +2000 -0
- data/vendor/javascript/node_modules/jshint/node_modules/exit/test/fixtures/1000-stdout.txt +1000 -0
- data/vendor/javascript/node_modules/jshint/node_modules/exit/test/fixtures/create-files.sh +8 -0
- data/vendor/javascript/node_modules/jshint/node_modules/exit/test/fixtures/log-broken.js +23 -0
- data/vendor/javascript/node_modules/jshint/node_modules/exit/test/fixtures/log.js +25 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/LICENSE +18 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/README.md +83 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/lib/CollectingHandler.js +55 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/lib/FeedHandler.js +95 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/lib/Parser.js +337 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/lib/ProxyHandler.js +27 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/lib/Stream.js +35 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/lib/Tokenizer.js +891 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/lib/WritableStream.js +21 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/lib/index.js +68 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/domelementtype/LICENSE +11 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/domelementtype/index.js +14 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/domelementtype/package.json +40 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/domelementtype/readme.md +1 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/domhandler/LICENSE +11 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/domhandler/index.js +211 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/domhandler/package.json +68 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/domhandler/readme.md +102 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/domhandler/test/cases/01-basic.json +57 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/domhandler/test/cases/02-single_tag_1.json +21 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/domhandler/test/cases/03-single_tag_2.json +21 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/domhandler/test/cases/04-unescaped_in_script.json +27 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/domhandler/test/cases/05-tags_in_comment.json +18 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/domhandler/test/cases/06-comment_in_script.json +18 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/domhandler/test/cases/07-unescaped_in_style.json +20 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/domhandler/test/cases/08-extra_spaces_in_tag.json +20 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/domhandler/test/cases/09-unquoted_attrib.json +20 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/domhandler/test/cases/10-singular_attribute.json +15 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/domhandler/test/cases/11-text_outside_tags.json +40 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/domhandler/test/cases/12-text_only.json +11 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/domhandler/test/cases/13-comment_in_text.json +19 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/domhandler/test/cases/14-comment_in_text_in_script.json +18 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/domhandler/test/cases/15-non-verbose.json +22 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/domhandler/test/cases/16-normalize_whitespace.json +47 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/domhandler/test/cases/17-xml_namespace.json +18 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/domhandler/test/cases/18-enforce_empty_tags.json +16 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/domhandler/test/cases/19-ignore_empty_tags.json +20 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/domhandler/test/cases/20-template_script_tags.json +20 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/domhandler/test/cases/21-conditional_comments.json +15 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/domhandler/test/cases/22-lowercase_tags.json +41 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/domhandler/test/cases/23-dom-lvl1.json +121 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/domhandler/test/tests.js +58 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/domutils/LICENSE +11 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/domutils/index.js +14 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/domutils/lib/helpers.js +141 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/domutils/lib/legacy.js +87 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/domutils/lib/manipulation.js +77 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/domutils/lib/querying.js +94 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/domutils/lib/stringify.js +93 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/domutils/lib/traversal.js +24 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/domutils/package.json +71 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/domutils/readme.md +1 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/domutils/test/fixture.js +6 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/domutils/test/tests/helpers.js +89 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/domutils/test/tests/legacy.js +119 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/domutils/test/utils.js +9 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/entities/LICENSE +11 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/entities/index.js +31 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/entities/lib/decode.js +72 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/entities/lib/decode_codepoint.js +26 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/entities/lib/encode.js +48 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/entities/maps/decode.json +1 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/entities/maps/entities.json +1 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/entities/maps/legacy.json +1 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/entities/maps/xml.json +1 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/entities/package.json +79 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/entities/readme.md +31 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/entities/test/mocha.opts +2 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/entities/test/test.js +150 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/readable-stream/LICENSE +18 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/readable-stream/README.md +15 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/readable-stream/duplex.js +1 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/readable-stream/float.patch +923 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/readable-stream/lib/_stream_duplex.js +89 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/readable-stream/lib/_stream_passthrough.js +46 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/readable-stream/lib/_stream_readable.js +944 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/readable-stream/lib/_stream_transform.js +209 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/readable-stream/lib/_stream_writable.js +472 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/readable-stream/node_modules/core-util-is/README.md +3 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/readable-stream/node_modules/core-util-is/float.patch +604 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/readable-stream/node_modules/core-util-is/lib/util.js +107 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/readable-stream/node_modules/core-util-is/package.json +53 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/readable-stream/node_modules/core-util-is/util.js +106 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/readable-stream/node_modules/inherits/LICENSE +16 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/readable-stream/node_modules/inherits/README.md +42 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/readable-stream/node_modules/inherits/inherits.js +1 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/readable-stream/node_modules/inherits/inherits_browser.js +23 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/readable-stream/node_modules/inherits/package.json +51 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/readable-stream/node_modules/inherits/test.js +25 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/readable-stream/node_modules/isarray/README.md +54 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/readable-stream/node_modules/isarray/build/build.js +209 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/readable-stream/node_modules/isarray/component.json +19 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/readable-stream/node_modules/isarray/index.js +3 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/readable-stream/node_modules/isarray/package.json +54 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/readable-stream/node_modules/string_decoder/LICENSE +20 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/readable-stream/node_modules/string_decoder/README.md +7 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/readable-stream/node_modules/string_decoder/index.js +200 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/readable-stream/node_modules/string_decoder/package.json +53 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/readable-stream/package.json +68 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/readable-stream/passthrough.js +1 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/readable-stream/readable.js +7 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/readable-stream/transform.js +1 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/node_modules/readable-stream/writable.js +1 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/package.json +90 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/test/01-events.js +9 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/test/02-stream.js +23 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/test/03-feed.js +19 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/test/Documents/Atom_Example.xml +25 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/test/Documents/Attributes.html +16 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/test/Documents/Basic.html +1 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/test/Documents/RDF_Example.xml +63 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/test/Documents/RSS_Example.xml +48 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/test/Events/01-simple.json +44 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/test/Events/02-template.json +63 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/test/Events/03-lowercase_tags.json +46 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/test/Events/04-cdata.json +50 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/test/Events/05-cdata-special.json +35 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/test/Events/06-leading-lt.json +16 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/test/Events/07-self-closing.json +67 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/test/Events/08-implicit-close-tags.json +59 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/test/Events/09-attributes.json +68 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/test/Events/10-crazy-attrib.json +52 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/test/Events/11-script_in_script.json +54 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/test/Events/12-long-comment-end.json +20 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/test/Events/13-long-cdata-end.json +22 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/test/Events/14-implicit-open-tags.json +27 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/test/Events/15-lt-whitespace.json +16 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/test/Events/16-double_attribs.json +45 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/test/Events/17-numeric_entities.json +16 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/test/Events/18-legacy_entities.json +16 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/test/Events/19-named_entities.json +16 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/test/Events/20-xml_entities.json +16 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/test/Events/21-entity_in_attribute.json +38 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/test/Events/22-double_brackets.json +41 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/test/Events/23-legacy_entity_fail.json +16 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/test/Events/24-special_special.json +133 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/test/Events/25-empty_tag_name.json +13 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/test/Events/26-not-quite-closed.json +35 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/test/Events/27-entities_in_attributes.json +62 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/test/Events/28-cdata_in_html.json +9 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/test/Events/29-comment_edge-cases.json +18 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/test/Events/30-cdata_edge-cases.json +22 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/test/Feeds/01-rss.js +34 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/test/Feeds/02-atom.js +18 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/test/Feeds/03-rdf.js +20 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/test/Stream/01-basic.json +83 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/test/Stream/02-RSS.json +1093 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/test/Stream/03-Atom.json +644 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/test/Stream/04-RDF.json +1399 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/test/Stream/05-Attributes.json +354 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/test/api.js +63 -0
- data/vendor/javascript/node_modules/jshint/node_modules/htmlparser2/test/test-helper.js +83 -0
- data/vendor/javascript/node_modules/jshint/node_modules/minimatch/LICENSE +23 -0
- data/vendor/javascript/node_modules/jshint/node_modules/minimatch/README.md +218 -0
- data/vendor/javascript/node_modules/jshint/node_modules/minimatch/minimatch.js +1061 -0
- data/vendor/javascript/node_modules/jshint/node_modules/minimatch/node_modules/lru-cache/CONTRIBUTORS +14 -0
- data/vendor/javascript/node_modules/jshint/node_modules/minimatch/node_modules/lru-cache/LICENSE +23 -0
- data/vendor/javascript/node_modules/jshint/node_modules/minimatch/node_modules/lru-cache/README.md +97 -0
- data/vendor/javascript/node_modules/jshint/node_modules/minimatch/node_modules/lru-cache/lib/lru-cache.js +252 -0
- data/vendor/javascript/node_modules/jshint/node_modules/minimatch/node_modules/lru-cache/package.json +50 -0
- data/vendor/javascript/node_modules/jshint/node_modules/minimatch/node_modules/lru-cache/test/basic.js +369 -0
- data/vendor/javascript/node_modules/jshint/node_modules/minimatch/node_modules/lru-cache/test/foreach.js +52 -0
- data/vendor/javascript/node_modules/jshint/node_modules/minimatch/node_modules/lru-cache/test/memory-leak.js +50 -0
- data/vendor/javascript/node_modules/jshint/node_modules/minimatch/node_modules/sigmund/LICENSE +27 -0
- data/vendor/javascript/node_modules/jshint/node_modules/minimatch/node_modules/sigmund/README.md +53 -0
- data/vendor/javascript/node_modules/jshint/node_modules/minimatch/node_modules/sigmund/bench.js +283 -0
- data/vendor/javascript/node_modules/jshint/node_modules/minimatch/node_modules/sigmund/package.json +58 -0
- data/vendor/javascript/node_modules/jshint/node_modules/minimatch/node_modules/sigmund/sigmund.js +39 -0
- data/vendor/javascript/node_modules/jshint/node_modules/minimatch/node_modules/sigmund/test/basic.js +24 -0
- data/vendor/javascript/node_modules/jshint/node_modules/minimatch/package.json +57 -0
- data/vendor/javascript/node_modules/jshint/node_modules/minimatch/test/basic.js +399 -0
- data/vendor/javascript/node_modules/jshint/node_modules/minimatch/test/brace-expand.js +33 -0
- data/vendor/javascript/node_modules/jshint/node_modules/minimatch/test/caching.js +14 -0
- data/vendor/javascript/node_modules/jshint/node_modules/minimatch/test/defaults.js +274 -0
- data/vendor/javascript/node_modules/jshint/node_modules/minimatch/test/extglob-ending-with-state-char.js +8 -0
- data/vendor/javascript/node_modules/jshint/node_modules/shelljs/LICENSE +26 -0
- data/vendor/javascript/node_modules/jshint/node_modules/shelljs/README.md +569 -0
- data/vendor/javascript/node_modules/jshint/node_modules/shelljs/bin/shjs +51 -0
- data/vendor/javascript/node_modules/jshint/node_modules/shelljs/global.js +3 -0
- data/vendor/javascript/node_modules/jshint/node_modules/shelljs/make.js +47 -0
- data/vendor/javascript/node_modules/jshint/node_modules/shelljs/package.json +61 -0
- data/vendor/javascript/node_modules/jshint/node_modules/shelljs/scripts/generate-docs.js +21 -0
- data/vendor/javascript/node_modules/jshint/node_modules/shelljs/scripts/run-tests.js +50 -0
- data/vendor/javascript/node_modules/jshint/node_modules/shelljs/shell.js +157 -0
- data/vendor/javascript/node_modules/jshint/node_modules/shelljs/src/cat.js +43 -0
- data/vendor/javascript/node_modules/jshint/node_modules/shelljs/src/cd.js +19 -0
- data/vendor/javascript/node_modules/jshint/node_modules/shelljs/src/chmod.js +208 -0
- data/vendor/javascript/node_modules/jshint/node_modules/shelljs/src/common.js +203 -0
- data/vendor/javascript/node_modules/jshint/node_modules/shelljs/src/cp.js +201 -0
- data/vendor/javascript/node_modules/jshint/node_modules/shelljs/src/dirs.js +191 -0
- data/vendor/javascript/node_modules/jshint/node_modules/shelljs/src/echo.js +20 -0
- data/vendor/javascript/node_modules/jshint/node_modules/shelljs/src/error.js +10 -0
- data/vendor/javascript/node_modules/jshint/node_modules/shelljs/src/exec.js +181 -0
- data/vendor/javascript/node_modules/jshint/node_modules/shelljs/src/find.js +51 -0
- data/vendor/javascript/node_modules/jshint/node_modules/shelljs/src/grep.js +52 -0
- data/vendor/javascript/node_modules/jshint/node_modules/shelljs/src/ln.js +53 -0
- data/vendor/javascript/node_modules/jshint/node_modules/shelljs/src/ls.js +126 -0
- data/vendor/javascript/node_modules/jshint/node_modules/shelljs/src/mkdir.js +68 -0
- data/vendor/javascript/node_modules/jshint/node_modules/shelljs/src/mv.js +80 -0
- data/vendor/javascript/node_modules/jshint/node_modules/shelljs/src/popd.js +1 -0
- data/vendor/javascript/node_modules/jshint/node_modules/shelljs/src/pushd.js +1 -0
- data/vendor/javascript/node_modules/jshint/node_modules/shelljs/src/pwd.js +11 -0
- data/vendor/javascript/node_modules/jshint/node_modules/shelljs/src/rm.js +145 -0
- data/vendor/javascript/node_modules/jshint/node_modules/shelljs/src/sed.js +43 -0
- data/vendor/javascript/node_modules/jshint/node_modules/shelljs/src/tempdir.js +56 -0
- data/vendor/javascript/node_modules/jshint/node_modules/shelljs/src/test.js +85 -0
- data/vendor/javascript/node_modules/jshint/node_modules/shelljs/src/to.js +29 -0
- data/vendor/javascript/node_modules/jshint/node_modules/shelljs/src/toEnd.js +29 -0
- data/vendor/javascript/node_modules/jshint/node_modules/shelljs/src/which.js +83 -0
- data/vendor/javascript/node_modules/jshint/node_modules/strip-json-comments/cli.js +41 -0
- data/vendor/javascript/node_modules/jshint/node_modules/strip-json-comments/package.json +76 -0
- data/vendor/javascript/node_modules/jshint/node_modules/strip-json-comments/readme.md +74 -0
- data/vendor/javascript/node_modules/jshint/node_modules/strip-json-comments/strip-json-comments.js +64 -0
- data/vendor/javascript/node_modules/jshint/node_modules/underscore/LICENSE +23 -0
- data/vendor/javascript/node_modules/jshint/node_modules/underscore/README.md +22 -0
- data/vendor/javascript/node_modules/jshint/node_modules/underscore/package.json +66 -0
- data/vendor/javascript/node_modules/jshint/node_modules/underscore/underscore-min.js +6 -0
- data/vendor/javascript/node_modules/jshint/node_modules/underscore/underscore.js +1343 -0
- data/vendor/javascript/node_modules/jshint/package.json +80 -0
- data/vendor/javascript/node_modules/jshint/src/cli.js +731 -0
- data/vendor/javascript/node_modules/jshint/src/jshint.js +5023 -0
- data/vendor/javascript/node_modules/jshint/src/lex.js +1650 -0
- data/vendor/javascript/node_modules/jshint/src/messages.js +223 -0
- data/vendor/javascript/node_modules/jshint/src/platforms/rhino.js +115 -0
- data/vendor/javascript/node_modules/jshint/src/reg.js +38 -0
- data/vendor/javascript/node_modules/jshint/src/reporters/checkstyle.js +81 -0
- data/vendor/javascript/node_modules/jshint/src/reporters/default.js +34 -0
- data/vendor/javascript/node_modules/jshint/src/reporters/jslint_xml.js +57 -0
- data/vendor/javascript/node_modules/jshint/src/reporters/non_error.js +52 -0
- data/vendor/javascript/node_modules/jshint/src/state.js +28 -0
- data/vendor/javascript/node_modules/jshint/src/style.js +143 -0
- data/vendor/javascript/node_modules/jshint/src/vars.js +658 -0
- data/vendor/python/astroid/COPYING +339 -0
- data/vendor/python/astroid/COPYING.LESSER +510 -0
- data/vendor/python/astroid/ChangeLog +574 -0
- data/vendor/python/astroid/MANIFEST.in +9 -0
- data/vendor/python/astroid/README +56 -0
- data/vendor/python/astroid/README.Python3 +26 -0
- data/vendor/python/astroid/__init__.py +118 -0
- data/vendor/python/astroid/__init__.pyc +0 -0
- data/vendor/python/astroid/__pkginfo__.py +48 -0
- data/vendor/python/astroid/__pkginfo__.pyc +0 -0
- data/vendor/python/astroid/announce.txt +23 -0
- data/vendor/python/astroid/as_string.py +496 -0
- data/vendor/python/astroid/as_string.pyc +0 -0
- data/vendor/python/astroid/bases.py +618 -0
- data/vendor/python/astroid/bases.pyc +0 -0
- data/vendor/python/astroid/brain/py2gi.py +159 -0
- data/vendor/python/astroid/brain/py2gi.pyc +0 -0
- data/vendor/python/astroid/brain/py2mechanize.py +20 -0
- data/vendor/python/astroid/brain/py2mechanize.pyc +0 -0
- data/vendor/python/astroid/brain/py2qt4.py +25 -0
- data/vendor/python/astroid/brain/py2qt4.pyc +0 -0
- data/vendor/python/astroid/brain/py2stdlib.py +252 -0
- data/vendor/python/astroid/brain/py2stdlib.pyc +0 -0
- data/vendor/python/astroid/builder.py +238 -0
- data/vendor/python/astroid/builder.pyc +0 -0
- data/vendor/python/astroid/exceptions.py +51 -0
- data/vendor/python/astroid/exceptions.pyc +0 -0
- data/vendor/python/astroid/inference.py +393 -0
- data/vendor/python/astroid/inference.pyc +0 -0
- data/vendor/python/astroid/inspector.py +275 -0
- data/vendor/python/astroid/manager.py +336 -0
- data/vendor/python/astroid/manager.pyc +0 -0
- data/vendor/python/astroid/mixins.py +122 -0
- data/vendor/python/astroid/mixins.pyc +0 -0
- data/vendor/python/astroid/node_classes.py +928 -0
- data/vendor/python/astroid/node_classes.pyc +0 -0
- data/vendor/python/astroid/nodes.py +73 -0
- data/vendor/python/astroid/nodes.pyc +0 -0
- data/vendor/python/astroid/protocols.py +322 -0
- data/vendor/python/astroid/protocols.pyc +0 -0
- data/vendor/python/astroid/raw_building.py +361 -0
- data/vendor/python/astroid/raw_building.pyc +0 -0
- data/vendor/python/astroid/rebuilder.py +954 -0
- data/vendor/python/astroid/rebuilder.pyc +0 -0
- data/vendor/python/astroid/scoped_nodes.py +1118 -0
- data/vendor/python/astroid/scoped_nodes.pyc +0 -0
- data/vendor/python/astroid/setup.py +184 -0
- data/vendor/python/astroid/tox.ini +10 -0
- data/vendor/python/astroid/utils.py +236 -0
- data/vendor/python/astroid/utils.pyc +0 -0
- data/vendor/python/logilab/__init__.py +0 -0
- data/vendor/python/logilab/__init__.pyc +0 -0
- data/vendor/python/logilab/common/COPYING +339 -0
- data/vendor/python/logilab/common/COPYING.LESSER +510 -0
- data/vendor/python/logilab/common/ChangeLog +1517 -0
- data/vendor/python/logilab/common/MANIFEST.in +13 -0
- data/vendor/python/logilab/common/README +185 -0
- data/vendor/python/logilab/common/README.Python3 +29 -0
- data/vendor/python/logilab/common/__init__.py +171 -0
- data/vendor/python/logilab/common/__init__.pyc +0 -0
- data/vendor/python/logilab/common/__pkginfo__.py +53 -0
- data/vendor/python/logilab/common/__pkginfo__.pyc +0 -0
- data/vendor/python/logilab/common/announce.txt +25 -0
- data/vendor/python/logilab/common/bin/pytest +7 -0
- data/vendor/python/logilab/common/bin/pytest.bat +17 -0
- data/vendor/python/logilab/common/cache.py +114 -0
- data/vendor/python/logilab/common/changelog.py +236 -0
- data/vendor/python/logilab/common/changelog.pyc +0 -0
- data/vendor/python/logilab/common/clcommands.py +332 -0
- data/vendor/python/logilab/common/cli.py +208 -0
- data/vendor/python/logilab/common/compat.py +243 -0
- data/vendor/python/logilab/common/compat.pyc +0 -0
- data/vendor/python/logilab/common/configuration.py +1094 -0
- data/vendor/python/logilab/common/configuration.pyc +0 -0
- data/vendor/python/logilab/common/contexts.py +5 -0
- data/vendor/python/logilab/common/corbautils.py +117 -0
- data/vendor/python/logilab/common/daemon.py +100 -0
- data/vendor/python/logilab/common/date.py +333 -0
- data/vendor/python/logilab/common/dbf.py +229 -0
- data/vendor/python/logilab/common/debugger.py +210 -0
- data/vendor/python/logilab/common/decorators.py +281 -0
- data/vendor/python/logilab/common/decorators.pyc +0 -0
- data/vendor/python/logilab/common/deprecation.py +188 -0
- data/vendor/python/logilab/common/deprecation.pyc +0 -0
- data/vendor/python/logilab/common/fileutils.py +402 -0
- data/vendor/python/logilab/common/graph.py +276 -0
- data/vendor/python/logilab/common/graph.pyc +0 -0
- data/vendor/python/logilab/common/hg.py +130 -0
- data/vendor/python/logilab/common/interface.py +71 -0
- data/vendor/python/logilab/common/interface.pyc +0 -0
- data/vendor/python/logilab/common/logging_ext.py +193 -0
- data/vendor/python/logilab/common/modutils.py +695 -0
- data/vendor/python/logilab/common/modutils.pyc +0 -0
- data/vendor/python/logilab/common/optik_ext.py +391 -0
- data/vendor/python/logilab/common/optik_ext.pyc +0 -0
- data/vendor/python/logilab/common/optparser.py +90 -0
- data/vendor/python/logilab/common/proc.py +277 -0
- data/vendor/python/logilab/common/pyro_ext.py +180 -0
- data/vendor/python/logilab/common/pytest.py +1177 -0
- data/vendor/python/logilab/common/python-logilab-common.spec +184 -0
- data/vendor/python/logilab/common/registry.py +1113 -0
- data/vendor/python/logilab/common/setup.cfg +3 -0
- data/vendor/python/logilab/common/setup.py +189 -0
- data/vendor/python/logilab/common/shellutils.py +455 -0
- data/vendor/python/logilab/common/sphinx_ext.py +87 -0
- data/vendor/python/logilab/common/sphinxutils.py +122 -0
- data/vendor/python/logilab/common/table.py +925 -0
- data/vendor/python/logilab/common/tasksqueue.py +100 -0
- data/vendor/python/logilab/common/textutils.py +534 -0
- data/vendor/python/logilab/common/textutils.pyc +0 -0
- data/vendor/python/logilab/common/tree.py +369 -0
- data/vendor/python/logilab/common/tree.pyc +0 -0
- data/vendor/python/logilab/common/umessage.py +190 -0
- data/vendor/python/logilab/common/ureports/__init__.py +174 -0
- data/vendor/python/logilab/common/ureports/__init__.pyc +0 -0
- data/vendor/python/logilab/common/ureports/docbook_writer.py +139 -0
- data/vendor/python/logilab/common/ureports/html_writer.py +131 -0
- data/vendor/python/logilab/common/ureports/html_writer.pyc +0 -0
- data/vendor/python/logilab/common/ureports/nodes.py +201 -0
- data/vendor/python/logilab/common/ureports/nodes.pyc +0 -0
- data/vendor/python/logilab/common/ureports/text_writer.py +140 -0
- data/vendor/python/logilab/common/ureports/text_writer.pyc +0 -0
- data/vendor/python/logilab/common/urllib2ext.py +87 -0
- data/vendor/python/logilab/common/vcgutils.py +216 -0
- data/vendor/python/logilab/common/visitor.py +107 -0
- data/vendor/python/logilab/common/visitor.pyc +0 -0
- data/vendor/python/logilab/common/xmlrpcutils.py +131 -0
- data/vendor/python/logilab/common/xmlutils.py +61 -0
- data/vendor/python/pylint/CONTRIBUTORS.txt +38 -0
- data/vendor/python/pylint/COPYING +340 -0
- data/vendor/python/pylint/ChangeLog +1437 -0
- data/vendor/python/pylint/DEPENDS +3 -0
- data/vendor/python/pylint/MANIFEST.in +14 -0
- data/vendor/python/pylint/README +50 -0
- data/vendor/python/pylint/README.Python3 +37 -0
- data/vendor/python/pylint/__init__.py +44 -0
- data/vendor/python/pylint/__init__.pyc +0 -0
- data/vendor/python/pylint/__main__.py +3 -0
- data/vendor/python/pylint/__pkginfo__.py +74 -0
- data/vendor/python/pylint/__pkginfo__.pyc +0 -0
- data/vendor/python/pylint/bin/epylint +3 -0
- data/vendor/python/pylint/bin/epylint.bat +5 -0
- data/vendor/python/pylint/bin/pylint +3 -0
- data/vendor/python/pylint/bin/pylint-gui +3 -0
- data/vendor/python/pylint/bin/pylint-gui.bat +5 -0
- data/vendor/python/pylint/bin/pylint.bat +5 -0
- data/vendor/python/pylint/bin/pyreverse +3 -0
- data/vendor/python/pylint/bin/pyreverse.bat +5 -0
- data/vendor/python/pylint/bin/symilar +3 -0
- data/vendor/python/pylint/bin/symilar.bat +5 -0
- data/vendor/python/pylint/checkers/__init__.py +145 -0
- data/vendor/python/pylint/checkers/__init__.pyc +0 -0
- data/vendor/python/pylint/checkers/base.py +1141 -0
- data/vendor/python/pylint/checkers/base.pyc +0 -0
- data/vendor/python/pylint/checkers/classes.py +792 -0
- data/vendor/python/pylint/checkers/classes.pyc +0 -0
- data/vendor/python/pylint/checkers/design_analysis.py +367 -0
- data/vendor/python/pylint/checkers/design_analysis.pyc +0 -0
- data/vendor/python/pylint/checkers/exceptions.py +306 -0
- data/vendor/python/pylint/checkers/exceptions.pyc +0 -0
- data/vendor/python/pylint/checkers/format.py +943 -0
- data/vendor/python/pylint/checkers/format.pyc +0 -0
- data/vendor/python/pylint/checkers/imports.py +394 -0
- data/vendor/python/pylint/checkers/imports.pyc +0 -0
- data/vendor/python/pylint/checkers/logging.py +213 -0
- data/vendor/python/pylint/checkers/logging.pyc +0 -0
- data/vendor/python/pylint/checkers/misc.py +90 -0
- data/vendor/python/pylint/checkers/misc.pyc +0 -0
- data/vendor/python/pylint/checkers/newstyle.py +151 -0
- data/vendor/python/pylint/checkers/newstyle.pyc +0 -0
- data/vendor/python/pylint/checkers/raw_metrics.py +129 -0
- data/vendor/python/pylint/checkers/raw_metrics.pyc +0 -0
- data/vendor/python/pylint/checkers/similar.py +365 -0
- data/vendor/python/pylint/checkers/similar.pyc +0 -0
- data/vendor/python/pylint/checkers/stdlib.py +69 -0
- data/vendor/python/pylint/checkers/stdlib.pyc +0 -0
- data/vendor/python/pylint/checkers/strings.py +304 -0
- data/vendor/python/pylint/checkers/strings.pyc +0 -0
- data/vendor/python/pylint/checkers/typecheck.py +451 -0
- data/vendor/python/pylint/checkers/typecheck.pyc +0 -0
- data/vendor/python/pylint/checkers/utils.py +416 -0
- data/vendor/python/pylint/checkers/utils.pyc +0 -0
- data/vendor/python/pylint/checkers/variables.py +741 -0
- data/vendor/python/pylint/checkers/variables.pyc +0 -0
- data/vendor/python/pylint/config.py +156 -0
- data/vendor/python/pylint/config.pyc +0 -0
- data/vendor/python/pylint/epylint.py +175 -0
- data/vendor/python/pylint/gui.py +508 -0
- data/vendor/python/pylint/interfaces.py +72 -0
- data/vendor/python/pylint/interfaces.pyc +0 -0
- data/vendor/python/pylint/lint.py +1106 -0
- data/vendor/python/pylint/lint.pyc +0 -0
- data/vendor/python/pylint/pyreverse/__init__.py +5 -0
- data/vendor/python/pylint/pyreverse/diadefslib.py +233 -0
- data/vendor/python/pylint/pyreverse/diagrams.py +247 -0
- data/vendor/python/pylint/pyreverse/main.py +124 -0
- data/vendor/python/pylint/pyreverse/utils.py +131 -0
- data/vendor/python/pylint/pyreverse/writer.py +199 -0
- data/vendor/python/pylint/reporters/__init__.py +138 -0
- data/vendor/python/pylint/reporters/__init__.pyc +0 -0
- data/vendor/python/pylint/reporters/guireporter.py +28 -0
- data/vendor/python/pylint/reporters/guireporter.pyc +0 -0
- data/vendor/python/pylint/reporters/html.py +70 -0
- data/vendor/python/pylint/reporters/html.pyc +0 -0
- data/vendor/python/pylint/reporters/text.py +143 -0
- data/vendor/python/pylint/reporters/text.pyc +0 -0
- data/vendor/python/pylint/setup.cfg +3 -0
- data/vendor/python/pylint/setup.py +203 -0
- data/vendor/python/pylint/tox.ini +10 -0
- data/vendor/python/pylint/utils.py +744 -0
- data/vendor/python/pylint/utils.pyc +0 -0
- data/vendor/python/pylint_runner.py +22 -0
- metadata +675 -0
@@ -0,0 +1,14 @@
|
|
1
|
+
include ChangeLog
|
2
|
+
include COPYING
|
3
|
+
include DEPENDS
|
4
|
+
include README README.Python3
|
5
|
+
include bin/*
|
6
|
+
include examples/*.py examples/pylintrc examples/pylintrc_camelcase
|
7
|
+
include elisp/startup elisp/*.el
|
8
|
+
include man/*.1
|
9
|
+
recursive-include doc *.rst *.jpeg Makefile *.html *.py
|
10
|
+
recursive-include test *.py *.txt *.dot *.sh
|
11
|
+
include test/input/similar*
|
12
|
+
include test/input/noext
|
13
|
+
include test/data/ascript
|
14
|
+
|
@@ -0,0 +1,50 @@
|
|
1
|
+
README for Pylint - http://www.pylint.org/
|
2
|
+
==========================================
|
3
|
+
|
4
|
+
Pylint is a Python source code analyzer which looks for programming errors,
|
5
|
+
helps enforcing a coding standard and sniffs for some code smells (as defined in
|
6
|
+
Martin Fowler's Refactoring book).
|
7
|
+
|
8
|
+
Pylint has many rules enabled by default, way too much to silence them all on a
|
9
|
+
minimally sized program. It's highly configurable and handle pragmas to control
|
10
|
+
it from within your code. Additionally, it is possible to write plugins to add
|
11
|
+
your own checks.
|
12
|
+
|
13
|
+
It's a free software distributed under the GNU Public Licence.
|
14
|
+
|
15
|
+
Development is hosted on bitbucket: https://bitbucket.org/logilab/pylint/
|
16
|
+
|
17
|
+
You can use the code-quality@python.org mailing list to discuss about
|
18
|
+
Pylint. Subscribe at https://mail.python.org/mailman/listinfo/code-quality/
|
19
|
+
or read the archives at https://mail.python.org/pipermail/code-quality/
|
20
|
+
|
21
|
+
Install
|
22
|
+
-------
|
23
|
+
|
24
|
+
Pylint requires the astroid (the later the better; formerly known as
|
25
|
+
logilab-astng) and logilab-common (version >= 0.53) packages.
|
26
|
+
|
27
|
+
* https://bitbucket.org/logilab/astroid
|
28
|
+
* http://www.logilab.org/projects/common
|
29
|
+
|
30
|
+
From the source distribution, extract the tarball and run ::
|
31
|
+
|
32
|
+
python setup.py install
|
33
|
+
|
34
|
+
You'll have to install dependencies in a similar way. For debian and
|
35
|
+
rpm packages, use your usual tools according to your Linux distribution.
|
36
|
+
|
37
|
+
More information about installation and available distribution format
|
38
|
+
may be found in the user manual in the *doc* subdirectory.
|
39
|
+
|
40
|
+
Documentation
|
41
|
+
-------------
|
42
|
+
|
43
|
+
Look in the doc/ subdirectory or at http://docs.pylint.org
|
44
|
+
|
45
|
+
Pylint is shipped with following additional commands:
|
46
|
+
|
47
|
+
* pyreverse: an UML diagram generator
|
48
|
+
* symilar: an independent similarities checker
|
49
|
+
* epylint: Emacs and Flymake compatible Pylint
|
50
|
+
* pylint-gui: a graphical interface
|
@@ -0,0 +1,37 @@
|
|
1
|
+
Python3
|
2
|
+
=======
|
3
|
+
|
4
|
+
Compatibility
|
5
|
+
-------------
|
6
|
+
|
7
|
+
Please, consider python3 >= 3.2 only.
|
8
|
+
|
9
|
+
|
10
|
+
Approach
|
11
|
+
--------
|
12
|
+
|
13
|
+
We maintain a Python 2 base and use 2to3 to generate Python 3 code.
|
14
|
+
|
15
|
+
2to3 is integrated into the distutils installation process and will be run as a
|
16
|
+
build step when invoked by the python3 interpreter::
|
17
|
+
|
18
|
+
NO_SETUPTOOLS=1 python3 setup.py install --no-compile
|
19
|
+
|
20
|
+
In order to run pylint locally, you have to install the dependencies::
|
21
|
+
|
22
|
+
easy_install-3.2 logilab-common
|
23
|
+
easy_install-3.2 astroid
|
24
|
+
|
25
|
+
|
26
|
+
Debian
|
27
|
+
------
|
28
|
+
|
29
|
+
For the Debian packaging, you can use the debian.py3k/ content against
|
30
|
+
the debian/ folder::
|
31
|
+
|
32
|
+
cp debian.py3k/* debian/
|
33
|
+
|
34
|
+
|
35
|
+
Resources
|
36
|
+
---------
|
37
|
+
http://wiki.python.org/moin/PortingPythonToPy3k
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# Copyright (c) 2003-2012 LOGILAB S.A. (Paris, FRANCE).
|
2
|
+
# http://www.logilab.fr/ -- mailto:contact@logilab.fr
|
3
|
+
#
|
4
|
+
# This program is free software; you can redistribute it and/or modify it under
|
5
|
+
# the terms of the GNU General Public License as published by the Free Software
|
6
|
+
# Foundation; either version 2 of the License, or (at your option) any later
|
7
|
+
# version.
|
8
|
+
#
|
9
|
+
# This program is distributed in the hope that it will be useful, but WITHOUT
|
10
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
11
|
+
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License along with
|
14
|
+
# this program; if not, write to the Free Software Foundation, Inc.,
|
15
|
+
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
16
|
+
import sys
|
17
|
+
|
18
|
+
def run_pylint():
|
19
|
+
"""run pylint"""
|
20
|
+
from pylint.lint import Run
|
21
|
+
Run(sys.argv[1:])
|
22
|
+
|
23
|
+
def run_pylint_gui():
|
24
|
+
"""run pylint-gui"""
|
25
|
+
try:
|
26
|
+
from pylint.gui import Run
|
27
|
+
Run(sys.argv[1:])
|
28
|
+
except ImportError:
|
29
|
+
sys.exit('tkinter is not available')
|
30
|
+
|
31
|
+
def run_epylint():
|
32
|
+
"""run pylint"""
|
33
|
+
from pylint.epylint import Run
|
34
|
+
Run()
|
35
|
+
|
36
|
+
def run_pyreverse():
|
37
|
+
"""run pyreverse"""
|
38
|
+
from pylint.pyreverse.main import Run
|
39
|
+
Run(sys.argv[1:])
|
40
|
+
|
41
|
+
def run_symilar():
|
42
|
+
"""run symilar"""
|
43
|
+
from pylint.checkers.similar import Run
|
44
|
+
Run(sys.argv[1:])
|
Binary file
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# pylint: disable=W0622,C0103
|
2
|
+
# Copyright (c) 2003-2014 LOGILAB S.A. (Paris, FRANCE).
|
3
|
+
# http://www.logilab.fr/ -- mailto:contact@logilab.fr
|
4
|
+
#
|
5
|
+
# This program is free software; you can redistribute it and/or modify it under
|
6
|
+
# the terms of the GNU General Public License as published by the Free Software
|
7
|
+
# Foundation; either version 2 of the License, or (at your option) any later
|
8
|
+
# version.
|
9
|
+
#
|
10
|
+
# This program is distributed in the hope that it will be useful, but WITHOUT
|
11
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
12
|
+
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU General Public License along with
|
15
|
+
# this program; if not, write to the Free Software Foundation, Inc.,
|
16
|
+
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
17
|
+
"""pylint packaging information"""
|
18
|
+
import sys
|
19
|
+
|
20
|
+
modname = distname = 'pylint'
|
21
|
+
|
22
|
+
numversion = (1, 2, 1)
|
23
|
+
version = '.'.join([str(num) for num in numversion])
|
24
|
+
|
25
|
+
if sys.version_info < (2, 6):
|
26
|
+
install_requires = ['logilab-common >= 0.53.0', 'astroid >= 1.1',
|
27
|
+
'StringFormat']
|
28
|
+
else:
|
29
|
+
install_requires = ['logilab-common >= 0.53.0', 'astroid >= 1.1']
|
30
|
+
|
31
|
+
license = 'GPL'
|
32
|
+
description = "python code static checker"
|
33
|
+
web = 'http://www.pylint.org'
|
34
|
+
mailinglist = "mailto://code-quality@python.org"
|
35
|
+
author = 'Logilab'
|
36
|
+
author_email = 'python-projects@lists.logilab.org'
|
37
|
+
|
38
|
+
classifiers = ['Development Status :: 4 - Beta',
|
39
|
+
'Environment :: Console',
|
40
|
+
'Intended Audience :: Developers',
|
41
|
+
'License :: OSI Approved :: GNU General Public License (GPL)',
|
42
|
+
'Operating System :: OS Independent',
|
43
|
+
'Programming Language :: Python',
|
44
|
+
'Programming Language :: Python :: 2',
|
45
|
+
'Programming Language :: Python :: 3',
|
46
|
+
'Topic :: Software Development :: Debuggers',
|
47
|
+
'Topic :: Software Development :: Quality Assurance',
|
48
|
+
'Topic :: Software Development :: Testing'
|
49
|
+
]
|
50
|
+
|
51
|
+
|
52
|
+
long_desc = """\
|
53
|
+
Pylint is a Python source code analyzer which looks for programming
|
54
|
+
errors, helps enforcing a coding standard and sniffs for some code
|
55
|
+
smells (as defined in Martin Fowler's Refactoring book)
|
56
|
+
.
|
57
|
+
Pylint can be seen as another PyChecker since nearly all tests you
|
58
|
+
can do with PyChecker can also be done with Pylint. However, Pylint
|
59
|
+
offers some more features, like checking length of lines of code,
|
60
|
+
checking if variable names are well-formed according to your coding
|
61
|
+
standard, or checking if declared interfaces are truly implemented,
|
62
|
+
and much more.
|
63
|
+
.
|
64
|
+
Additionally, it is possible to write plugins to add your own checks.
|
65
|
+
.
|
66
|
+
Pylint is shipped with "pylint-gui", "pyreverse" (UML diagram generator)
|
67
|
+
and "symilar" (an independent similarities checker)."""
|
68
|
+
|
69
|
+
from os.path import join
|
70
|
+
scripts = [join('bin', filename)
|
71
|
+
for filename in ('pylint', 'pylint-gui', "symilar", "epylint",
|
72
|
+
"pyreverse")]
|
73
|
+
|
74
|
+
include_dirs = ['test']
|
Binary file
|
@@ -0,0 +1,145 @@
|
|
1
|
+
# Copyright (c) 2003-2013 LOGILAB S.A. (Paris, FRANCE).
|
2
|
+
# http://www.logilab.fr/ -- mailto:contact@logilab.fr
|
3
|
+
#
|
4
|
+
# This program is free software; you can redistribute it and/or modify it under
|
5
|
+
# the terms of the GNU General Public License as published by the Free Software
|
6
|
+
# Foundation; either version 2 of the License, or (at your option) any later
|
7
|
+
# version.
|
8
|
+
#
|
9
|
+
# This program is distributed in the hope that it will be useful, but WITHOUT
|
10
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
11
|
+
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License along with
|
14
|
+
# this program; if not, write to the Free Software Foundation, Inc.,
|
15
|
+
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
16
|
+
"""utilities methods and classes for checkers
|
17
|
+
|
18
|
+
Base id of standard checkers (used in msg and report ids):
|
19
|
+
01: base
|
20
|
+
02: classes
|
21
|
+
03: format
|
22
|
+
04: import
|
23
|
+
05: misc
|
24
|
+
06: variables
|
25
|
+
07: exceptions
|
26
|
+
08: similar
|
27
|
+
09: design_analysis
|
28
|
+
10: newstyle
|
29
|
+
11: typecheck
|
30
|
+
12: logging
|
31
|
+
13: string_format
|
32
|
+
14: string_constant
|
33
|
+
15-50: not yet used: reserved for future internal checkers.
|
34
|
+
51-99: perhaps used: reserved for external checkers
|
35
|
+
|
36
|
+
The raw_metrics checker has no number associated since it doesn't emit any
|
37
|
+
messages nor reports. XXX not true, emit a 07 report !
|
38
|
+
|
39
|
+
"""
|
40
|
+
|
41
|
+
import sys
|
42
|
+
import tokenize
|
43
|
+
import warnings
|
44
|
+
|
45
|
+
from astroid.utils import ASTWalker
|
46
|
+
from logilab.common.configuration import OptionsProviderMixIn
|
47
|
+
|
48
|
+
from pylint.reporters import diff_string
|
49
|
+
from pylint.utils import register_plugins
|
50
|
+
|
51
|
+
def table_lines_from_stats(stats, old_stats, columns):
|
52
|
+
"""get values listed in <columns> from <stats> and <old_stats>,
|
53
|
+
and return a formated list of values, designed to be given to a
|
54
|
+
ureport.Table object
|
55
|
+
"""
|
56
|
+
lines = []
|
57
|
+
for m_type in columns:
|
58
|
+
new = stats[m_type]
|
59
|
+
format = str
|
60
|
+
if isinstance(new, float):
|
61
|
+
format = lambda num: '%.3f' % num
|
62
|
+
old = old_stats.get(m_type)
|
63
|
+
if old is not None:
|
64
|
+
diff_str = diff_string(old, new)
|
65
|
+
old = format(old)
|
66
|
+
else:
|
67
|
+
old, diff_str = 'NC', 'NC'
|
68
|
+
lines += (m_type.replace('_', ' '), format(new), old, diff_str)
|
69
|
+
return lines
|
70
|
+
|
71
|
+
|
72
|
+
class BaseChecker(OptionsProviderMixIn, ASTWalker):
|
73
|
+
"""base class for checkers"""
|
74
|
+
# checker name (you may reuse an existing one)
|
75
|
+
name = None
|
76
|
+
# options level (0 will be displaying in --help, 1 in --long-help)
|
77
|
+
level = 1
|
78
|
+
# ordered list of options to control the ckecker behaviour
|
79
|
+
options = ()
|
80
|
+
# messages issued by this checker
|
81
|
+
msgs = {}
|
82
|
+
# reports issued by this checker
|
83
|
+
reports = ()
|
84
|
+
|
85
|
+
def __init__(self, linter=None):
|
86
|
+
"""checker instances should have the linter as argument
|
87
|
+
|
88
|
+
linter is an object implementing ILinter
|
89
|
+
"""
|
90
|
+
ASTWalker.__init__(self, self)
|
91
|
+
self.name = self.name.lower()
|
92
|
+
OptionsProviderMixIn.__init__(self)
|
93
|
+
self.linter = linter
|
94
|
+
|
95
|
+
def add_message(self, msg_id, line=None, node=None, args=None):
|
96
|
+
"""add a message of a given type"""
|
97
|
+
self.linter.add_message(msg_id, line, node, args)
|
98
|
+
|
99
|
+
# dummy methods implementing the IChecker interface
|
100
|
+
|
101
|
+
def open(self):
|
102
|
+
"""called before visiting project (i.e set of modules)"""
|
103
|
+
|
104
|
+
def close(self):
|
105
|
+
"""called after visiting project (i.e set of modules)"""
|
106
|
+
|
107
|
+
|
108
|
+
class BaseRawChecker(BaseChecker):
|
109
|
+
"""base class for raw checkers"""
|
110
|
+
|
111
|
+
def process_module(self, node):
|
112
|
+
"""process a module
|
113
|
+
|
114
|
+
the module's content is accessible via the stream object
|
115
|
+
|
116
|
+
stream must implement the readline method
|
117
|
+
"""
|
118
|
+
warnings.warn("Modules that need access to the tokens should "
|
119
|
+
"use the ITokenChecker interface.",
|
120
|
+
DeprecationWarning)
|
121
|
+
stream = node.file_stream
|
122
|
+
stream.seek(0) # XXX may be removed with astroid > 0.23
|
123
|
+
if sys.version_info <= (3, 0):
|
124
|
+
self.process_tokens(tokenize.generate_tokens(stream.readline))
|
125
|
+
else:
|
126
|
+
self.process_tokens(tokenize.tokenize(stream.readline))
|
127
|
+
|
128
|
+
def process_tokens(self, tokens):
|
129
|
+
"""should be overridden by subclasses"""
|
130
|
+
raise NotImplementedError()
|
131
|
+
|
132
|
+
|
133
|
+
class BaseTokenChecker(BaseChecker):
|
134
|
+
"""Base class for checkers that want to have access to the token stream."""
|
135
|
+
|
136
|
+
def process_tokens(self, tokens):
|
137
|
+
"""Should be overridden by subclasses."""
|
138
|
+
raise NotImplementedError()
|
139
|
+
|
140
|
+
|
141
|
+
def initialize(linter):
|
142
|
+
"""initialize linter with checkers in this package """
|
143
|
+
register_plugins(linter, __path__[0])
|
144
|
+
|
145
|
+
__all__ = ('BaseChecker', 'initialize')
|
Binary file
|
@@ -0,0 +1,1141 @@
|
|
1
|
+
# Copyright (c) 2003-2013 LOGILAB S.A. (Paris, FRANCE).
|
2
|
+
# http://www.logilab.fr/ -- mailto:contact@logilab.fr
|
3
|
+
# Copyright (c) 2009-2010 Arista Networks, Inc.
|
4
|
+
#
|
5
|
+
# This program is free software; you can redistribute it and/or modify it under
|
6
|
+
# the terms of the GNU General Public License as published by the Free Software
|
7
|
+
# Foundation; either version 2 of the License, or (at your option) any later
|
8
|
+
# version.
|
9
|
+
#
|
10
|
+
# This program is distributed in the hope that it will be useful, but WITHOUT
|
11
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
12
|
+
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU General Public License along with
|
15
|
+
# this program; if not, write to the Free Software Foundation, Inc.,
|
16
|
+
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
17
|
+
"""basic checker for Python code"""
|
18
|
+
|
19
|
+
import sys
|
20
|
+
import astroid
|
21
|
+
from logilab.common.ureports import Table
|
22
|
+
from astroid import are_exclusive, InferenceError
|
23
|
+
import astroid.bases
|
24
|
+
|
25
|
+
from pylint.interfaces import IAstroidChecker
|
26
|
+
from pylint.utils import EmptyReport
|
27
|
+
from pylint.reporters import diff_string
|
28
|
+
from pylint.checkers import BaseChecker
|
29
|
+
from pylint.checkers.utils import (
|
30
|
+
check_messages,
|
31
|
+
clobber_in_except,
|
32
|
+
is_builtin_object,
|
33
|
+
is_inside_except,
|
34
|
+
overrides_a_method,
|
35
|
+
safe_infer,
|
36
|
+
get_argument_from_call,
|
37
|
+
NoSuchArgumentError,
|
38
|
+
)
|
39
|
+
|
40
|
+
|
41
|
+
import re
|
42
|
+
|
43
|
+
# regex for class/function/variable/constant name
|
44
|
+
CLASS_NAME_RGX = re.compile('[A-Z_][a-zA-Z0-9]+$')
|
45
|
+
MOD_NAME_RGX = re.compile('(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$')
|
46
|
+
CONST_NAME_RGX = re.compile('(([A-Z_][A-Z0-9_]*)|(__.*__))$')
|
47
|
+
COMP_VAR_RGX = re.compile('[A-Za-z_][A-Za-z0-9_]*$')
|
48
|
+
DEFAULT_NAME_RGX = re.compile('[a-z_][a-z0-9_]{2,30}$')
|
49
|
+
CLASS_ATTRIBUTE_RGX = re.compile(r'([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$')
|
50
|
+
# do not require a doc string on system methods
|
51
|
+
NO_REQUIRED_DOC_RGX = re.compile('__.*__')
|
52
|
+
REVERSED_METHODS = (('__getitem__', '__len__'),
|
53
|
+
('__reversed__', ))
|
54
|
+
|
55
|
+
PY33 = sys.version_info >= (3, 3)
|
56
|
+
BAD_FUNCTIONS = ['map', 'filter', 'apply']
|
57
|
+
if sys.version_info < (3, 0):
|
58
|
+
BAD_FUNCTIONS.append('input')
|
59
|
+
BAD_FUNCTIONS.append('file')
|
60
|
+
|
61
|
+
# Name categories that are always consistent with all naming conventions.
|
62
|
+
EXEMPT_NAME_CATEGORIES = set(('exempt', 'ignore'))
|
63
|
+
|
64
|
+
del re
|
65
|
+
|
66
|
+
def in_loop(node):
|
67
|
+
"""return True if the node is inside a kind of for loop"""
|
68
|
+
parent = node.parent
|
69
|
+
while parent is not None:
|
70
|
+
if isinstance(parent, (astroid.For, astroid.ListComp, astroid.SetComp,
|
71
|
+
astroid.DictComp, astroid.GenExpr)):
|
72
|
+
return True
|
73
|
+
parent = parent.parent
|
74
|
+
return False
|
75
|
+
|
76
|
+
def in_nested_list(nested_list, obj):
|
77
|
+
"""return true if the object is an element of <nested_list> or of a nested
|
78
|
+
list
|
79
|
+
"""
|
80
|
+
for elmt in nested_list:
|
81
|
+
if isinstance(elmt, (list, tuple)):
|
82
|
+
if in_nested_list(elmt, obj):
|
83
|
+
return True
|
84
|
+
elif elmt == obj:
|
85
|
+
return True
|
86
|
+
return False
|
87
|
+
|
88
|
+
def _loop_exits_early(loop):
|
89
|
+
"""Returns true if a loop has a break statement in its body."""
|
90
|
+
loop_nodes = (astroid.For, astroid.While)
|
91
|
+
# Loop over body explicitly to avoid matching break statements
|
92
|
+
# in orelse.
|
93
|
+
for child in loop.body:
|
94
|
+
if isinstance(child, loop_nodes):
|
95
|
+
# break statement may be in orelse of child loop.
|
96
|
+
for orelse in (child.orelse or ()):
|
97
|
+
for _ in orelse.nodes_of_class(astroid.Break, skip_klass=loop_nodes):
|
98
|
+
return True
|
99
|
+
continue
|
100
|
+
for _ in child.nodes_of_class(astroid.Break, skip_klass=loop_nodes):
|
101
|
+
return True
|
102
|
+
return False
|
103
|
+
|
104
|
+
if sys.version_info < (3, 0):
|
105
|
+
PROPERTY_CLASSES = set(('__builtin__.property', 'abc.abstractproperty'))
|
106
|
+
else:
|
107
|
+
PROPERTY_CLASSES = set(('builtins.property', 'abc.abstractproperty'))
|
108
|
+
ABC_METHODS = set(('abc.abstractproperty', 'abc.abstractmethod',
|
109
|
+
'abc.abstractclassmethod', 'abc.abstractstaticmethod'))
|
110
|
+
|
111
|
+
def _determine_function_name_type(node):
|
112
|
+
"""Determine the name type whose regex the a function's name should match.
|
113
|
+
|
114
|
+
:param node: A function node.
|
115
|
+
:returns: One of ('function', 'method', 'attr')
|
116
|
+
"""
|
117
|
+
if not node.is_method():
|
118
|
+
return 'function'
|
119
|
+
if node.decorators:
|
120
|
+
decorators = node.decorators.nodes
|
121
|
+
else:
|
122
|
+
decorators = []
|
123
|
+
for decorator in decorators:
|
124
|
+
# If the function is a property (decorated with @property
|
125
|
+
# or @abc.abstractproperty), the name type is 'attr'.
|
126
|
+
if (isinstance(decorator, astroid.Name) or
|
127
|
+
(isinstance(decorator, astroid.Getattr) and
|
128
|
+
decorator.attrname == 'abstractproperty')):
|
129
|
+
infered = safe_infer(decorator)
|
130
|
+
if infered and infered.qname() in PROPERTY_CLASSES:
|
131
|
+
return 'attr'
|
132
|
+
# If the function is decorated using the prop_method.{setter,getter}
|
133
|
+
# form, treat it like an attribute as well.
|
134
|
+
elif (isinstance(decorator, astroid.Getattr) and
|
135
|
+
decorator.attrname in ('setter', 'deleter')):
|
136
|
+
return 'attr'
|
137
|
+
return 'method'
|
138
|
+
|
139
|
+
def decorated_with_abc(func):
|
140
|
+
""" Determine if the `func` node is decorated
|
141
|
+
with `abc` decorators (abstractmethod et co.)
|
142
|
+
"""
|
143
|
+
if func.decorators:
|
144
|
+
for node in func.decorators.nodes:
|
145
|
+
try:
|
146
|
+
infered = node.infer().next()
|
147
|
+
except InferenceError:
|
148
|
+
continue
|
149
|
+
if infered and infered.qname() in ABC_METHODS:
|
150
|
+
return True
|
151
|
+
|
152
|
+
def has_abstract_methods(node):
|
153
|
+
""" Determine if the given `node` has
|
154
|
+
abstract methods, defined with `abc` module.
|
155
|
+
"""
|
156
|
+
return any(decorated_with_abc(meth)
|
157
|
+
for meth in node.mymethods())
|
158
|
+
|
159
|
+
def report_by_type_stats(sect, stats, old_stats):
|
160
|
+
"""make a report of
|
161
|
+
|
162
|
+
* percentage of different types documented
|
163
|
+
* percentage of different types with a bad name
|
164
|
+
"""
|
165
|
+
# percentage of different types documented and/or with a bad name
|
166
|
+
nice_stats = {}
|
167
|
+
for node_type in ('module', 'class', 'method', 'function'):
|
168
|
+
try:
|
169
|
+
total = stats[node_type]
|
170
|
+
except KeyError:
|
171
|
+
raise EmptyReport()
|
172
|
+
nice_stats[node_type] = {}
|
173
|
+
if total != 0:
|
174
|
+
try:
|
175
|
+
documented = total - stats['undocumented_'+node_type]
|
176
|
+
percent = (documented * 100.) / total
|
177
|
+
nice_stats[node_type]['percent_documented'] = '%.2f' % percent
|
178
|
+
except KeyError:
|
179
|
+
nice_stats[node_type]['percent_documented'] = 'NC'
|
180
|
+
try:
|
181
|
+
percent = (stats['badname_'+node_type] * 100.) / total
|
182
|
+
nice_stats[node_type]['percent_badname'] = '%.2f' % percent
|
183
|
+
except KeyError:
|
184
|
+
nice_stats[node_type]['percent_badname'] = 'NC'
|
185
|
+
lines = ('type', 'number', 'old number', 'difference',
|
186
|
+
'%documented', '%badname')
|
187
|
+
for node_type in ('module', 'class', 'method', 'function'):
|
188
|
+
new = stats[node_type]
|
189
|
+
old = old_stats.get(node_type, None)
|
190
|
+
if old is not None:
|
191
|
+
diff_str = diff_string(old, new)
|
192
|
+
else:
|
193
|
+
old, diff_str = 'NC', 'NC'
|
194
|
+
lines += (node_type, str(new), str(old), diff_str,
|
195
|
+
nice_stats[node_type].get('percent_documented', '0'),
|
196
|
+
nice_stats[node_type].get('percent_badname', '0'))
|
197
|
+
sect.append(Table(children=lines, cols=6, rheaders=1))
|
198
|
+
|
199
|
+
def redefined_by_decorator(node):
|
200
|
+
"""return True if the object is a method redefined via decorator.
|
201
|
+
|
202
|
+
For example:
|
203
|
+
@property
|
204
|
+
def x(self): return self._x
|
205
|
+
@x.setter
|
206
|
+
def x(self, value): self._x = value
|
207
|
+
"""
|
208
|
+
if node.decorators:
|
209
|
+
for decorator in node.decorators.nodes:
|
210
|
+
if (isinstance(decorator, astroid.Getattr) and
|
211
|
+
getattr(decorator.expr, 'name', None) == node.name):
|
212
|
+
return True
|
213
|
+
return False
|
214
|
+
|
215
|
+
class _BasicChecker(BaseChecker):
|
216
|
+
__implements__ = IAstroidChecker
|
217
|
+
name = 'basic'
|
218
|
+
|
219
|
+
class BasicErrorChecker(_BasicChecker):
|
220
|
+
msgs = {
|
221
|
+
'E0100': ('__init__ method is a generator',
|
222
|
+
'init-is-generator',
|
223
|
+
'Used when the special class method __init__ is turned into a '
|
224
|
+
'generator by a yield in its body.'),
|
225
|
+
'E0101': ('Explicit return in __init__',
|
226
|
+
'return-in-init',
|
227
|
+
'Used when the special class method __init__ has an explicit \
|
228
|
+
return value.'),
|
229
|
+
'E0102': ('%s already defined line %s',
|
230
|
+
'function-redefined',
|
231
|
+
'Used when a function / class / method is redefined.'),
|
232
|
+
'E0103': ('%r not properly in loop',
|
233
|
+
'not-in-loop',
|
234
|
+
'Used when break or continue keywords are used outside a loop.'),
|
235
|
+
|
236
|
+
'E0104': ('Return outside function',
|
237
|
+
'return-outside-function',
|
238
|
+
'Used when a "return" statement is found outside a function or '
|
239
|
+
'method.'),
|
240
|
+
'E0105': ('Yield outside function',
|
241
|
+
'yield-outside-function',
|
242
|
+
'Used when a "yield" statement is found outside a function or '
|
243
|
+
'method.'),
|
244
|
+
'E0106': ('Return with argument inside generator',
|
245
|
+
'return-arg-in-generator',
|
246
|
+
'Used when a "return" statement with an argument is found '
|
247
|
+
'outside in a generator function or method (e.g. with some '
|
248
|
+
'"yield" statements).',
|
249
|
+
{'maxversion': (3, 3)}),
|
250
|
+
'E0107': ("Use of the non-existent %s operator",
|
251
|
+
'nonexistent-operator',
|
252
|
+
"Used when you attempt to use the C-style pre-increment or"
|
253
|
+
"pre-decrement operator -- and ++, which doesn't exist in Python."),
|
254
|
+
'E0108': ('Duplicate argument name %s in function definition',
|
255
|
+
'duplicate-argument-name',
|
256
|
+
'Duplicate argument names in function definitions are syntax'
|
257
|
+
' errors.'),
|
258
|
+
'E0110': ('Abstract class with abstract methods instantiated',
|
259
|
+
'abstract-class-instantiated',
|
260
|
+
'Used when an abstract class with `abc.ABCMeta` as metaclass '
|
261
|
+
'has abstract methods and is instantiated.',
|
262
|
+
{'minversion': (3, 0)}),
|
263
|
+
'W0120': ('Else clause on loop without a break statement',
|
264
|
+
'useless-else-on-loop',
|
265
|
+
'Loops should only have an else clause if they can exit early '
|
266
|
+
'with a break statement, otherwise the statements under else '
|
267
|
+
'should be on the same scope as the loop itself.'),
|
268
|
+
}
|
269
|
+
|
270
|
+
def __init__(self, linter):
|
271
|
+
_BasicChecker.__init__(self, linter)
|
272
|
+
|
273
|
+
@check_messages('function-redefined')
|
274
|
+
def visit_class(self, node):
|
275
|
+
self._check_redefinition('class', node)
|
276
|
+
|
277
|
+
@check_messages('init-is-generator', 'return-in-init',
|
278
|
+
'function-redefined', 'return-arg-in-generator',
|
279
|
+
'duplicate-argument-name')
|
280
|
+
def visit_function(self, node):
|
281
|
+
if not redefined_by_decorator(node):
|
282
|
+
self._check_redefinition(node.is_method() and 'method' or 'function', node)
|
283
|
+
# checks for max returns, branch, return in __init__
|
284
|
+
returns = node.nodes_of_class(astroid.Return,
|
285
|
+
skip_klass=(astroid.Function, astroid.Class))
|
286
|
+
if node.is_method() and node.name == '__init__':
|
287
|
+
if node.is_generator():
|
288
|
+
self.add_message('init-is-generator', node=node)
|
289
|
+
else:
|
290
|
+
values = [r.value for r in returns]
|
291
|
+
# Are we returning anything but None from constructors
|
292
|
+
if [v for v in values if
|
293
|
+
not (v is None or
|
294
|
+
(isinstance(v, astroid.Const) and v.value is None) or
|
295
|
+
(isinstance(v, astroid.Name) and v.name == 'None')
|
296
|
+
)]:
|
297
|
+
self.add_message('return-in-init', node=node)
|
298
|
+
elif node.is_generator():
|
299
|
+
# make sure we don't mix non-None returns and yields
|
300
|
+
if not PY33:
|
301
|
+
for retnode in returns:
|
302
|
+
if isinstance(retnode.value, astroid.Const) and \
|
303
|
+
retnode.value.value is not None:
|
304
|
+
self.add_message('return-arg-in-generator', node=node,
|
305
|
+
line=retnode.fromlineno)
|
306
|
+
# Check for duplicate names
|
307
|
+
args = set()
|
308
|
+
for name in node.argnames():
|
309
|
+
if name in args:
|
310
|
+
self.add_message('duplicate-argument-name', node=node, args=(name,))
|
311
|
+
else:
|
312
|
+
args.add(name)
|
313
|
+
|
314
|
+
|
315
|
+
@check_messages('return-outside-function')
|
316
|
+
def visit_return(self, node):
|
317
|
+
if not isinstance(node.frame(), astroid.Function):
|
318
|
+
self.add_message('return-outside-function', node=node)
|
319
|
+
|
320
|
+
@check_messages('yield-outside-function')
|
321
|
+
def visit_yield(self, node):
|
322
|
+
if not isinstance(node.frame(), (astroid.Function, astroid.Lambda)):
|
323
|
+
self.add_message('yield-outside-function', node=node)
|
324
|
+
|
325
|
+
@check_messages('not-in-loop')
|
326
|
+
def visit_continue(self, node):
|
327
|
+
self._check_in_loop(node, 'continue')
|
328
|
+
|
329
|
+
@check_messages('not-in-loop')
|
330
|
+
def visit_break(self, node):
|
331
|
+
self._check_in_loop(node, 'break')
|
332
|
+
|
333
|
+
@check_messages('useless-else-on-loop')
|
334
|
+
def visit_for(self, node):
|
335
|
+
self._check_else_on_loop(node)
|
336
|
+
|
337
|
+
@check_messages('useless-else-on-loop')
|
338
|
+
def visit_while(self, node):
|
339
|
+
self._check_else_on_loop(node)
|
340
|
+
|
341
|
+
@check_messages('nonexistent-operator')
|
342
|
+
def visit_unaryop(self, node):
|
343
|
+
"""check use of the non-existent ++ and -- operator operator"""
|
344
|
+
if ((node.op in '+-') and
|
345
|
+
isinstance(node.operand, astroid.UnaryOp) and
|
346
|
+
(node.operand.op == node.op)):
|
347
|
+
self.add_message('nonexistent-operator', node=node, args=node.op*2)
|
348
|
+
|
349
|
+
@check_messages('abstract-class-instantiated')
|
350
|
+
def visit_callfunc(self, node):
|
351
|
+
""" Check instantiating abstract class with
|
352
|
+
abc.ABCMeta as metaclass.
|
353
|
+
"""
|
354
|
+
try:
|
355
|
+
infered = node.func.infer().next()
|
356
|
+
except astroid.InferenceError:
|
357
|
+
return
|
358
|
+
if not isinstance(infered, astroid.Class):
|
359
|
+
return
|
360
|
+
# __init__ was called
|
361
|
+
metaclass = infered.metaclass()
|
362
|
+
if metaclass is None:
|
363
|
+
# Python 3.4 has `abc.ABC`, which won't be detected
|
364
|
+
# by ClassNode.metaclass()
|
365
|
+
for ancestor in infered.ancestors():
|
366
|
+
if (ancestor.qname() == 'abc.ABC' and
|
367
|
+
has_abstract_methods(infered)):
|
368
|
+
|
369
|
+
self.add_message('abstract-class-instantiated', node=node)
|
370
|
+
break
|
371
|
+
return
|
372
|
+
if (metaclass.qname() == 'abc.ABCMeta' and
|
373
|
+
has_abstract_methods(infered)):
|
374
|
+
|
375
|
+
self.add_message('abstract-class-instantiated', node=node)
|
376
|
+
|
377
|
+
def _check_else_on_loop(self, node):
|
378
|
+
"""Check that any loop with an else clause has a break statement."""
|
379
|
+
if node.orelse and not _loop_exits_early(node):
|
380
|
+
self.add_message('useless-else-on-loop', node=node,
|
381
|
+
# This is not optimal, but the line previous
|
382
|
+
# to the first statement in the else clause
|
383
|
+
# will usually be the one that contains the else:.
|
384
|
+
line=node.orelse[0].lineno - 1)
|
385
|
+
|
386
|
+
def _check_in_loop(self, node, node_name):
|
387
|
+
"""check that a node is inside a for or while loop"""
|
388
|
+
_node = node.parent
|
389
|
+
while _node:
|
390
|
+
if isinstance(_node, (astroid.For, astroid.While)):
|
391
|
+
break
|
392
|
+
_node = _node.parent
|
393
|
+
else:
|
394
|
+
self.add_message('not-in-loop', node=node, args=node_name)
|
395
|
+
|
396
|
+
def _check_redefinition(self, redeftype, node):
|
397
|
+
"""check for redefinition of a function / method / class name"""
|
398
|
+
defined_self = node.parent.frame()[node.name]
|
399
|
+
if defined_self is not node and not are_exclusive(node, defined_self):
|
400
|
+
self.add_message('function-redefined', node=node,
|
401
|
+
args=(redeftype, defined_self.fromlineno))
|
402
|
+
|
403
|
+
|
404
|
+
|
405
|
+
class BasicChecker(_BasicChecker):
|
406
|
+
"""checks for :
|
407
|
+
* doc strings
|
408
|
+
* number of arguments, local variables, branches, returns and statements in
|
409
|
+
functions, methods
|
410
|
+
* required module attributes
|
411
|
+
* dangerous default values as arguments
|
412
|
+
* redefinition of function / method / class
|
413
|
+
* uses of the global statement
|
414
|
+
"""
|
415
|
+
|
416
|
+
__implements__ = IAstroidChecker
|
417
|
+
|
418
|
+
name = 'basic'
|
419
|
+
msgs = {
|
420
|
+
'W0101': ('Unreachable code',
|
421
|
+
'unreachable',
|
422
|
+
'Used when there is some code behind a "return" or "raise" \
|
423
|
+
statement, which will never be accessed.'),
|
424
|
+
'W0102': ('Dangerous default value %s as argument',
|
425
|
+
'dangerous-default-value',
|
426
|
+
'Used when a mutable value as list or dictionary is detected in \
|
427
|
+
a default value for an argument.'),
|
428
|
+
'W0104': ('Statement seems to have no effect',
|
429
|
+
'pointless-statement',
|
430
|
+
'Used when a statement doesn\'t have (or at least seems to) \
|
431
|
+
any effect.'),
|
432
|
+
'W0105': ('String statement has no effect',
|
433
|
+
'pointless-string-statement',
|
434
|
+
'Used when a string is used as a statement (which of course \
|
435
|
+
has no effect). This is a particular case of W0104 with its \
|
436
|
+
own message so you can easily disable it if you\'re using \
|
437
|
+
those strings as documentation, instead of comments.'),
|
438
|
+
'W0106': ('Expression "%s" is assigned to nothing',
|
439
|
+
'expression-not-assigned',
|
440
|
+
'Used when an expression that is not a function call is assigned\
|
441
|
+
to nothing. Probably something else was intended.'),
|
442
|
+
'W0108': ('Lambda may not be necessary',
|
443
|
+
'unnecessary-lambda',
|
444
|
+
'Used when the body of a lambda expression is a function call \
|
445
|
+
on the same argument list as the lambda itself; such lambda \
|
446
|
+
expressions are in all but a few cases replaceable with the \
|
447
|
+
function being called in the body of the lambda.'),
|
448
|
+
'W0109': ("Duplicate key %r in dictionary",
|
449
|
+
'duplicate-key',
|
450
|
+
"Used when a dictionary expression binds the same key multiple \
|
451
|
+
times."),
|
452
|
+
'W0122': ('Use of exec',
|
453
|
+
'exec-used',
|
454
|
+
'Used when you use the "exec" statement (function for Python 3), to discourage its \
|
455
|
+
usage. That doesn\'t mean you can not use it !'),
|
456
|
+
'W0123': ('Use of eval',
|
457
|
+
'eval-used',
|
458
|
+
'Used when you use the "eval" function, to discourage its '
|
459
|
+
'usage. Consider using `ast.literal_eval` for safely evaluating '
|
460
|
+
'strings containing Python expressions '
|
461
|
+
'from untrusted sources. '),
|
462
|
+
'W0141': ('Used builtin function %r',
|
463
|
+
'bad-builtin',
|
464
|
+
'Used when a black listed builtin function is used (see the '
|
465
|
+
'bad-function option). Usual black listed functions are the ones '
|
466
|
+
'like map, or filter , where Python offers now some cleaner '
|
467
|
+
'alternative like list comprehension.'),
|
468
|
+
'W0142': ('Used * or ** magic',
|
469
|
+
'star-args',
|
470
|
+
'Used when a function or method is called using `*args` or '
|
471
|
+
'`**kwargs` to dispatch arguments. This doesn\'t improve '
|
472
|
+
'readability and should be used with care.'),
|
473
|
+
'W0150': ("%s statement in finally block may swallow exception",
|
474
|
+
'lost-exception',
|
475
|
+
"Used when a break or a return statement is found inside the \
|
476
|
+
finally clause of a try...finally block: the exceptions raised \
|
477
|
+
in the try clause will be silently swallowed instead of being \
|
478
|
+
re-raised."),
|
479
|
+
'W0199': ('Assert called on a 2-uple. Did you mean \'assert x,y\'?',
|
480
|
+
'assert-on-tuple',
|
481
|
+
'A call of assert on a tuple will always evaluate to true if '
|
482
|
+
'the tuple is not empty, and will always evaluate to false if '
|
483
|
+
'it is.'),
|
484
|
+
'W0121': ('Use raise ErrorClass(args) instead of raise ErrorClass, args.',
|
485
|
+
'old-raise-syntax',
|
486
|
+
"Used when the alternate raise syntax 'raise foo, bar' is used "
|
487
|
+
"instead of 'raise foo(bar)'.",
|
488
|
+
{'maxversion': (3, 0)}),
|
489
|
+
|
490
|
+
'C0121': ('Missing required attribute "%s"', # W0103
|
491
|
+
'missing-module-attribute',
|
492
|
+
'Used when an attribute required for modules is missing.'),
|
493
|
+
|
494
|
+
'E0109': ('Missing argument to reversed()',
|
495
|
+
'missing-reversed-argument',
|
496
|
+
'Used when reversed() builtin didn\'t receive an argument.'),
|
497
|
+
'E0111': ('The first reversed() argument is not a sequence',
|
498
|
+
'bad-reversed-sequence',
|
499
|
+
'Used when the first argument to reversed() builtin '
|
500
|
+
'isn\'t a sequence (does not implement __reversed__, '
|
501
|
+
'nor __getitem__ and __len__'),
|
502
|
+
|
503
|
+
}
|
504
|
+
|
505
|
+
options = (('required-attributes',
|
506
|
+
{'default' : (), 'type' : 'csv',
|
507
|
+
'metavar' : '<attributes>',
|
508
|
+
'help' : 'Required attributes for module, separated by a '
|
509
|
+
'comma'}
|
510
|
+
),
|
511
|
+
('bad-functions',
|
512
|
+
{'default' : BAD_FUNCTIONS,
|
513
|
+
'type' :'csv', 'metavar' : '<builtin function names>',
|
514
|
+
'help' : 'List of builtins function names that should not be '
|
515
|
+
'used, separated by a comma'}
|
516
|
+
),
|
517
|
+
)
|
518
|
+
reports = (('RP0101', 'Statistics by type', report_by_type_stats),)
|
519
|
+
|
520
|
+
def __init__(self, linter):
|
521
|
+
_BasicChecker.__init__(self, linter)
|
522
|
+
self.stats = None
|
523
|
+
self._tryfinallys = None
|
524
|
+
|
525
|
+
def open(self):
|
526
|
+
"""initialize visit variables and statistics
|
527
|
+
"""
|
528
|
+
self._tryfinallys = []
|
529
|
+
self.stats = self.linter.add_stats(module=0, function=0,
|
530
|
+
method=0, class_=0)
|
531
|
+
@check_messages('missing-module-attribute')
|
532
|
+
def visit_module(self, node):
|
533
|
+
"""check module name, docstring and required arguments
|
534
|
+
"""
|
535
|
+
self.stats['module'] += 1
|
536
|
+
for attr in self.config.required_attributes:
|
537
|
+
if attr not in node:
|
538
|
+
self.add_message('missing-module-attribute', node=node, args=attr)
|
539
|
+
|
540
|
+
def visit_class(self, node):
|
541
|
+
"""check module name, docstring and redefinition
|
542
|
+
increment branch counter
|
543
|
+
"""
|
544
|
+
self.stats['class'] += 1
|
545
|
+
|
546
|
+
@check_messages('pointless-statement', 'pointless-string-statement',
|
547
|
+
'expression-not-assigned')
|
548
|
+
def visit_discard(self, node):
|
549
|
+
"""check for various kind of statements without effect"""
|
550
|
+
expr = node.value
|
551
|
+
if isinstance(expr, astroid.Const) and isinstance(expr.value,
|
552
|
+
basestring):
|
553
|
+
# treat string statement in a separated message
|
554
|
+
self.add_message('pointless-string-statement', node=node)
|
555
|
+
return
|
556
|
+
# ignore if this is :
|
557
|
+
# * a direct function call
|
558
|
+
# * the unique child of a try/except body
|
559
|
+
# * a yield (which are wrapped by a discard node in _ast XXX)
|
560
|
+
# warn W0106 if we have any underlying function call (we can't predict
|
561
|
+
# side effects), else pointless-statement
|
562
|
+
if (isinstance(expr, (astroid.Yield, astroid.CallFunc)) or
|
563
|
+
(isinstance(node.parent, astroid.TryExcept) and
|
564
|
+
node.parent.body == [node])):
|
565
|
+
return
|
566
|
+
if any(expr.nodes_of_class(astroid.CallFunc)):
|
567
|
+
self.add_message('expression-not-assigned', node=node, args=expr.as_string())
|
568
|
+
else:
|
569
|
+
self.add_message('pointless-statement', node=node)
|
570
|
+
|
571
|
+
@check_messages('unnecessary-lambda')
|
572
|
+
def visit_lambda(self, node):
|
573
|
+
"""check whether or not the lambda is suspicious
|
574
|
+
"""
|
575
|
+
# if the body of the lambda is a call expression with the same
|
576
|
+
# argument list as the lambda itself, then the lambda is
|
577
|
+
# possibly unnecessary and at least suspicious.
|
578
|
+
if node.args.defaults:
|
579
|
+
# If the arguments of the lambda include defaults, then a
|
580
|
+
# judgment cannot be made because there is no way to check
|
581
|
+
# that the defaults defined by the lambda are the same as
|
582
|
+
# the defaults defined by the function called in the body
|
583
|
+
# of the lambda.
|
584
|
+
return
|
585
|
+
call = node.body
|
586
|
+
if not isinstance(call, astroid.CallFunc):
|
587
|
+
# The body of the lambda must be a function call expression
|
588
|
+
# for the lambda to be unnecessary.
|
589
|
+
return
|
590
|
+
# XXX are lambda still different with astroid >= 0.18 ?
|
591
|
+
# *args and **kwargs need to be treated specially, since they
|
592
|
+
# are structured differently between the lambda and the function
|
593
|
+
# call (in the lambda they appear in the args.args list and are
|
594
|
+
# indicated as * and ** by two bits in the lambda's flags, but
|
595
|
+
# in the function call they are omitted from the args list and
|
596
|
+
# are indicated by separate attributes on the function call node).
|
597
|
+
ordinary_args = list(node.args.args)
|
598
|
+
if node.args.kwarg:
|
599
|
+
if (not call.kwargs
|
600
|
+
or not isinstance(call.kwargs, astroid.Name)
|
601
|
+
or node.args.kwarg != call.kwargs.name):
|
602
|
+
return
|
603
|
+
elif call.kwargs:
|
604
|
+
return
|
605
|
+
if node.args.vararg:
|
606
|
+
if (not call.starargs
|
607
|
+
or not isinstance(call.starargs, astroid.Name)
|
608
|
+
or node.args.vararg != call.starargs.name):
|
609
|
+
return
|
610
|
+
elif call.starargs:
|
611
|
+
return
|
612
|
+
# The "ordinary" arguments must be in a correspondence such that:
|
613
|
+
# ordinary_args[i].name == call.args[i].name.
|
614
|
+
if len(ordinary_args) != len(call.args):
|
615
|
+
return
|
616
|
+
for i in xrange(len(ordinary_args)):
|
617
|
+
if not isinstance(call.args[i], astroid.Name):
|
618
|
+
return
|
619
|
+
if node.args.args[i].name != call.args[i].name:
|
620
|
+
return
|
621
|
+
self.add_message('unnecessary-lambda', line=node.fromlineno, node=node)
|
622
|
+
|
623
|
+
@check_messages('dangerous-default-value')
|
624
|
+
def visit_function(self, node):
|
625
|
+
"""check function name, docstring, arguments, redefinition,
|
626
|
+
variable names, max locals
|
627
|
+
"""
|
628
|
+
self.stats[node.is_method() and 'method' or 'function'] += 1
|
629
|
+
# check for dangerous default values as arguments
|
630
|
+
for default in node.args.defaults:
|
631
|
+
try:
|
632
|
+
value = default.infer().next()
|
633
|
+
except astroid.InferenceError:
|
634
|
+
continue
|
635
|
+
builtins = astroid.bases.BUILTINS
|
636
|
+
if (isinstance(value, astroid.Instance) and
|
637
|
+
value.qname() in ['.'.join([builtins, x]) for x in ('set', 'dict', 'list')]):
|
638
|
+
if value is default:
|
639
|
+
msg = default.as_string()
|
640
|
+
elif type(value) is astroid.Instance:
|
641
|
+
msg = '%s (%s)' % (default.as_string(), value.qname())
|
642
|
+
else:
|
643
|
+
msg = '%s (%s)' % (default.as_string(), value.as_string())
|
644
|
+
self.add_message('dangerous-default-value', node=node, args=(msg,))
|
645
|
+
|
646
|
+
@check_messages('unreachable', 'lost-exception')
|
647
|
+
def visit_return(self, node):
|
648
|
+
"""1 - check is the node has a right sibling (if so, that's some
|
649
|
+
unreachable code)
|
650
|
+
2 - check is the node is inside the finally clause of a try...finally
|
651
|
+
block
|
652
|
+
"""
|
653
|
+
self._check_unreachable(node)
|
654
|
+
# Is it inside final body of a try...finally bloc ?
|
655
|
+
self._check_not_in_finally(node, 'return', (astroid.Function,))
|
656
|
+
|
657
|
+
@check_messages('unreachable')
|
658
|
+
def visit_continue(self, node):
|
659
|
+
"""check is the node has a right sibling (if so, that's some unreachable
|
660
|
+
code)
|
661
|
+
"""
|
662
|
+
self._check_unreachable(node)
|
663
|
+
|
664
|
+
@check_messages('unreachable', 'lost-exception')
|
665
|
+
def visit_break(self, node):
|
666
|
+
"""1 - check is the node has a right sibling (if so, that's some
|
667
|
+
unreachable code)
|
668
|
+
2 - check is the node is inside the finally clause of a try...finally
|
669
|
+
block
|
670
|
+
"""
|
671
|
+
# 1 - Is it right sibling ?
|
672
|
+
self._check_unreachable(node)
|
673
|
+
# 2 - Is it inside final body of a try...finally bloc ?
|
674
|
+
self._check_not_in_finally(node, 'break', (astroid.For, astroid.While,))
|
675
|
+
|
676
|
+
@check_messages('unreachable', 'old-raise-syntax')
|
677
|
+
def visit_raise(self, node):
|
678
|
+
"""check if the node has a right sibling (if so, that's some unreachable
|
679
|
+
code)
|
680
|
+
"""
|
681
|
+
self._check_unreachable(node)
|
682
|
+
if sys.version_info >= (3, 0):
|
683
|
+
return
|
684
|
+
if node.exc is not None and node.inst is not None and node.tback is None:
|
685
|
+
self.add_message('old-raise-syntax', node=node)
|
686
|
+
|
687
|
+
@check_messages('exec-used')
|
688
|
+
def visit_exec(self, node):
|
689
|
+
"""just print a warning on exec statements"""
|
690
|
+
self.add_message('exec-used', node=node)
|
691
|
+
|
692
|
+
@check_messages('bad-builtin', 'star-args', 'eval-used',
|
693
|
+
'exec-used', 'missing-reversed-argument',
|
694
|
+
'bad-reversed-sequence')
|
695
|
+
def visit_callfunc(self, node):
|
696
|
+
"""visit a CallFunc node -> check if this is not a blacklisted builtin
|
697
|
+
call and check for * or ** use
|
698
|
+
"""
|
699
|
+
if isinstance(node.func, astroid.Name):
|
700
|
+
name = node.func.name
|
701
|
+
# ignore the name if it's not a builtin (i.e. not defined in the
|
702
|
+
# locals nor globals scope)
|
703
|
+
if not (name in node.frame() or
|
704
|
+
name in node.root()):
|
705
|
+
if name == 'exec':
|
706
|
+
self.add_message('exec-used', node=node)
|
707
|
+
elif name == 'reversed':
|
708
|
+
self._check_reversed(node)
|
709
|
+
elif name == 'eval':
|
710
|
+
self.add_message('eval-used', node=node)
|
711
|
+
if name in self.config.bad_functions:
|
712
|
+
self.add_message('bad-builtin', node=node, args=name)
|
713
|
+
if node.starargs or node.kwargs:
|
714
|
+
scope = node.scope()
|
715
|
+
if isinstance(scope, astroid.Function):
|
716
|
+
toprocess = [(n, vn) for (n, vn) in ((node.starargs, scope.args.vararg),
|
717
|
+
(node.kwargs, scope.args.kwarg)) if n]
|
718
|
+
if toprocess:
|
719
|
+
for cfnode, fargname in toprocess[:]:
|
720
|
+
if getattr(cfnode, 'name', None) == fargname:
|
721
|
+
toprocess.remove((cfnode, fargname))
|
722
|
+
if not toprocess:
|
723
|
+
return # star-args can be skipped
|
724
|
+
self.add_message('star-args', node=node.func)
|
725
|
+
|
726
|
+
@check_messages('assert-on-tuple')
|
727
|
+
def visit_assert(self, node):
|
728
|
+
"""check the use of an assert statement on a tuple."""
|
729
|
+
if node.fail is None and isinstance(node.test, astroid.Tuple) and \
|
730
|
+
len(node.test.elts) == 2:
|
731
|
+
self.add_message('assert-on-tuple', node=node)
|
732
|
+
|
733
|
+
@check_messages('duplicate-key')
|
734
|
+
def visit_dict(self, node):
|
735
|
+
"""check duplicate key in dictionary"""
|
736
|
+
keys = set()
|
737
|
+
for k, _ in node.items:
|
738
|
+
if isinstance(k, astroid.Const):
|
739
|
+
key = k.value
|
740
|
+
if key in keys:
|
741
|
+
self.add_message('duplicate-key', node=node, args=key)
|
742
|
+
keys.add(key)
|
743
|
+
|
744
|
+
def visit_tryfinally(self, node):
|
745
|
+
"""update try...finally flag"""
|
746
|
+
self._tryfinallys.append(node)
|
747
|
+
|
748
|
+
def leave_tryfinally(self, node):
|
749
|
+
"""update try...finally flag"""
|
750
|
+
self._tryfinallys.pop()
|
751
|
+
|
752
|
+
def _check_unreachable(self, node):
|
753
|
+
"""check unreachable code"""
|
754
|
+
unreach_stmt = node.next_sibling()
|
755
|
+
if unreach_stmt is not None:
|
756
|
+
self.add_message('unreachable', node=unreach_stmt)
|
757
|
+
|
758
|
+
def _check_not_in_finally(self, node, node_name, breaker_classes=()):
|
759
|
+
"""check that a node is not inside a finally clause of a
|
760
|
+
try...finally statement.
|
761
|
+
If we found before a try...finally bloc a parent which its type is
|
762
|
+
in breaker_classes, we skip the whole check."""
|
763
|
+
# if self._tryfinallys is empty, we're not a in try...finally bloc
|
764
|
+
if not self._tryfinallys:
|
765
|
+
return
|
766
|
+
# the node could be a grand-grand...-children of the try...finally
|
767
|
+
_parent = node.parent
|
768
|
+
_node = node
|
769
|
+
while _parent and not isinstance(_parent, breaker_classes):
|
770
|
+
if hasattr(_parent, 'finalbody') and _node in _parent.finalbody:
|
771
|
+
self.add_message('lost-exception', node=node, args=node_name)
|
772
|
+
return
|
773
|
+
_node = _parent
|
774
|
+
_parent = _node.parent
|
775
|
+
|
776
|
+
def _check_reversed(self, node):
|
777
|
+
""" check that the argument to `reversed` is a sequence """
|
778
|
+
try:
|
779
|
+
argument = safe_infer(get_argument_from_call(node, position=0))
|
780
|
+
except NoSuchArgumentError:
|
781
|
+
self.add_message('missing-reversed-argument', node=node)
|
782
|
+
else:
|
783
|
+
if argument is astroid.YES:
|
784
|
+
return
|
785
|
+
if argument is None:
|
786
|
+
# nothing was infered
|
787
|
+
# try to see if we have iter()
|
788
|
+
if isinstance(node.args[0], astroid.CallFunc):
|
789
|
+
try:
|
790
|
+
func = node.args[0].func.infer().next()
|
791
|
+
except InferenceError:
|
792
|
+
return
|
793
|
+
if (getattr(func, 'name', None) == 'iter' and
|
794
|
+
is_builtin_object(func)):
|
795
|
+
self.add_message('bad-reversed-sequence', node=node)
|
796
|
+
return
|
797
|
+
|
798
|
+
if isinstance(argument, astroid.Instance):
|
799
|
+
if (argument._proxied.name == 'dict' and
|
800
|
+
is_builtin_object(argument._proxied)):
|
801
|
+
self.add_message('bad-reversed-sequence', node=node)
|
802
|
+
return
|
803
|
+
elif any(ancestor.name == 'dict' and is_builtin_object(ancestor)
|
804
|
+
for ancestor in argument._proxied.ancestors()):
|
805
|
+
# mappings aren't accepted by reversed()
|
806
|
+
self.add_message('bad-reversed-sequence', node=node)
|
807
|
+
return
|
808
|
+
|
809
|
+
for methods in REVERSED_METHODS:
|
810
|
+
for meth in methods:
|
811
|
+
try:
|
812
|
+
argument.getattr(meth)
|
813
|
+
except astroid.NotFoundError:
|
814
|
+
break
|
815
|
+
else:
|
816
|
+
break
|
817
|
+
else:
|
818
|
+
# check if it is a .deque. It doesn't seem that
|
819
|
+
# we can retrieve special methods
|
820
|
+
# from C implemented constructs
|
821
|
+
if argument._proxied.qname().endswith(".deque"):
|
822
|
+
return
|
823
|
+
self.add_message('bad-reversed-sequence', node=node)
|
824
|
+
elif not isinstance(argument, (astroid.List, astroid.Tuple)):
|
825
|
+
# everything else is not a proper sequence for reversed()
|
826
|
+
self.add_message('bad-reversed-sequence', node=node)
|
827
|
+
|
828
|
+
_NAME_TYPES = {
|
829
|
+
'module': (MOD_NAME_RGX, 'module'),
|
830
|
+
'const': (CONST_NAME_RGX, 'constant'),
|
831
|
+
'class': (CLASS_NAME_RGX, 'class'),
|
832
|
+
'function': (DEFAULT_NAME_RGX, 'function'),
|
833
|
+
'method': (DEFAULT_NAME_RGX, 'method'),
|
834
|
+
'attr': (DEFAULT_NAME_RGX, 'attribute'),
|
835
|
+
'argument': (DEFAULT_NAME_RGX, 'argument'),
|
836
|
+
'variable': (DEFAULT_NAME_RGX, 'variable'),
|
837
|
+
'class_attribute': (CLASS_ATTRIBUTE_RGX, 'class attribute'),
|
838
|
+
'inlinevar': (COMP_VAR_RGX, 'inline iteration'),
|
839
|
+
}
|
840
|
+
|
841
|
+
def _create_naming_options():
|
842
|
+
name_options = []
|
843
|
+
for name_type, (rgx, human_readable_name) in _NAME_TYPES.iteritems():
|
844
|
+
name_type = name_type.replace('_', '-')
|
845
|
+
name_options.append((
|
846
|
+
'%s-rgx' % (name_type,),
|
847
|
+
{'default': rgx, 'type': 'regexp', 'metavar': '<regexp>',
|
848
|
+
'help': 'Regular expression matching correct %s names' % (human_readable_name,)}))
|
849
|
+
name_options.append((
|
850
|
+
'%s-name-hint' % (name_type,),
|
851
|
+
{'default': rgx.pattern, 'type': 'string', 'metavar': '<string>',
|
852
|
+
'help': 'Naming hint for %s names' % (human_readable_name,)}))
|
853
|
+
|
854
|
+
return tuple(name_options)
|
855
|
+
|
856
|
+
class NameChecker(_BasicChecker):
|
857
|
+
msgs = {
|
858
|
+
'C0102': ('Black listed name "%s"',
|
859
|
+
'blacklisted-name',
|
860
|
+
'Used when the name is listed in the black list (unauthorized \
|
861
|
+
names).'),
|
862
|
+
'C0103': ('Invalid %s name "%s"%s',
|
863
|
+
'invalid-name',
|
864
|
+
'Used when the name doesn\'t match the regular expression \
|
865
|
+
associated to its type (constant, variable, class...).'),
|
866
|
+
}
|
867
|
+
|
868
|
+
options = (# XXX use set
|
869
|
+
('good-names',
|
870
|
+
{'default' : ('i', 'j', 'k', 'ex', 'Run', '_'),
|
871
|
+
'type' :'csv', 'metavar' : '<names>',
|
872
|
+
'help' : 'Good variable names which should always be accepted,'
|
873
|
+
' separated by a comma'}
|
874
|
+
),
|
875
|
+
('bad-names',
|
876
|
+
{'default' : ('foo', 'bar', 'baz', 'toto', 'tutu', 'tata'),
|
877
|
+
'type' :'csv', 'metavar' : '<names>',
|
878
|
+
'help' : 'Bad variable names which should always be refused, '
|
879
|
+
'separated by a comma'}
|
880
|
+
),
|
881
|
+
('name-group',
|
882
|
+
{'default' : (),
|
883
|
+
'type' :'csv', 'metavar' : '<name1:name2>',
|
884
|
+
'help' : ('Colon-delimited sets of names that determine each'
|
885
|
+
' other\'s naming style when the name regexes'
|
886
|
+
' allow several styles.')}
|
887
|
+
),
|
888
|
+
('include-naming-hint',
|
889
|
+
{'default': False, 'type' : 'yn', 'metavar' : '<y_or_n>',
|
890
|
+
'help': 'Include a hint for the correct naming format with invalid-name'}
|
891
|
+
),
|
892
|
+
) + _create_naming_options()
|
893
|
+
|
894
|
+
|
895
|
+
def __init__(self, linter):
|
896
|
+
_BasicChecker.__init__(self, linter)
|
897
|
+
self._name_category = {}
|
898
|
+
self._name_group = {}
|
899
|
+
|
900
|
+
def open(self):
|
901
|
+
self.stats = self.linter.add_stats(badname_module=0,
|
902
|
+
badname_class=0, badname_function=0,
|
903
|
+
badname_method=0, badname_attr=0,
|
904
|
+
badname_const=0,
|
905
|
+
badname_variable=0,
|
906
|
+
badname_inlinevar=0,
|
907
|
+
badname_argument=0,
|
908
|
+
badname_class_attribute=0)
|
909
|
+
for group in self.config.name_group:
|
910
|
+
for name_type in group.split(':'):
|
911
|
+
self._name_group[name_type] = 'group_%s' % (group,)
|
912
|
+
|
913
|
+
@check_messages('blacklisted-name', 'invalid-name')
|
914
|
+
def visit_module(self, node):
|
915
|
+
self._check_name('module', node.name.split('.')[-1], node)
|
916
|
+
|
917
|
+
@check_messages('blacklisted-name', 'invalid-name')
|
918
|
+
def visit_class(self, node):
|
919
|
+
self._check_name('class', node.name, node)
|
920
|
+
for attr, anodes in node.instance_attrs.iteritems():
|
921
|
+
if not list(node.instance_attr_ancestors(attr)):
|
922
|
+
self._check_name('attr', attr, anodes[0])
|
923
|
+
|
924
|
+
@check_messages('blacklisted-name', 'invalid-name')
|
925
|
+
def visit_function(self, node):
|
926
|
+
# Do not emit any warnings if the method is just an implementation
|
927
|
+
# of a base class method.
|
928
|
+
if node.is_method() and overrides_a_method(node.parent.frame(), node.name):
|
929
|
+
return
|
930
|
+
self._check_name(_determine_function_name_type(node),
|
931
|
+
node.name, node)
|
932
|
+
# Check argument names
|
933
|
+
args = node.args.args
|
934
|
+
if args is not None:
|
935
|
+
self._recursive_check_names(args, node)
|
936
|
+
|
937
|
+
@check_messages('blacklisted-name', 'invalid-name')
|
938
|
+
def visit_global(self, node):
|
939
|
+
for name in node.names:
|
940
|
+
self._check_name('const', name, node)
|
941
|
+
|
942
|
+
@check_messages('blacklisted-name', 'invalid-name')
|
943
|
+
def visit_assname(self, node):
|
944
|
+
"""check module level assigned names"""
|
945
|
+
frame = node.frame()
|
946
|
+
ass_type = node.ass_type()
|
947
|
+
if isinstance(ass_type, astroid.Comprehension):
|
948
|
+
self._check_name('inlinevar', node.name, node)
|
949
|
+
elif isinstance(frame, astroid.Module):
|
950
|
+
if isinstance(ass_type, astroid.Assign) and not in_loop(ass_type):
|
951
|
+
if isinstance(safe_infer(ass_type.value), astroid.Class):
|
952
|
+
self._check_name('class', node.name, node)
|
953
|
+
else:
|
954
|
+
self._check_name('const', node.name, node)
|
955
|
+
elif isinstance(ass_type, astroid.ExceptHandler):
|
956
|
+
self._check_name('variable', node.name, node)
|
957
|
+
elif isinstance(frame, astroid.Function):
|
958
|
+
# global introduced variable aren't in the function locals
|
959
|
+
if node.name in frame and node.name not in frame.argnames():
|
960
|
+
self._check_name('variable', node.name, node)
|
961
|
+
elif isinstance(frame, astroid.Class):
|
962
|
+
if not list(frame.local_attr_ancestors(node.name)):
|
963
|
+
self._check_name('class_attribute', node.name, node)
|
964
|
+
|
965
|
+
def _recursive_check_names(self, args, node):
|
966
|
+
"""check names in a possibly recursive list <arg>"""
|
967
|
+
for arg in args:
|
968
|
+
if isinstance(arg, astroid.AssName):
|
969
|
+
self._check_name('argument', arg.name, node)
|
970
|
+
else:
|
971
|
+
self._recursive_check_names(arg.elts, node)
|
972
|
+
|
973
|
+
def _find_name_group(self, node_type):
|
974
|
+
return self._name_group.get(node_type, node_type)
|
975
|
+
|
976
|
+
def _is_multi_naming_match(self, match):
|
977
|
+
return (match is not None and
|
978
|
+
match.lastgroup is not None and
|
979
|
+
match.lastgroup not in EXEMPT_NAME_CATEGORIES)
|
980
|
+
|
981
|
+
def _check_name(self, node_type, name, node):
|
982
|
+
"""check for a name using the type's regexp"""
|
983
|
+
if is_inside_except(node):
|
984
|
+
clobbering, _ = clobber_in_except(node)
|
985
|
+
if clobbering:
|
986
|
+
return
|
987
|
+
if name in self.config.good_names:
|
988
|
+
return
|
989
|
+
if name in self.config.bad_names:
|
990
|
+
self.stats['badname_' + node_type] += 1
|
991
|
+
self.add_message('blacklisted-name', node=node, args=name)
|
992
|
+
return
|
993
|
+
regexp = getattr(self.config, node_type + '_rgx')
|
994
|
+
match = regexp.match(name)
|
995
|
+
|
996
|
+
if self._is_multi_naming_match(match):
|
997
|
+
name_group = self._find_name_group(node_type)
|
998
|
+
if name_group not in self._name_category:
|
999
|
+
self._name_category[name_group] = match.lastgroup
|
1000
|
+
elif self._name_category[name_group] != match.lastgroup:
|
1001
|
+
match = None
|
1002
|
+
|
1003
|
+
if match is None:
|
1004
|
+
type_label = _NAME_TYPES[node_type][1]
|
1005
|
+
hint = ''
|
1006
|
+
if self.config.include_naming_hint:
|
1007
|
+
hint = ' (hint: %s)' % (getattr(self.config, node_type + '_name_hint'))
|
1008
|
+
self.add_message('invalid-name', node=node, args=(type_label, name, hint))
|
1009
|
+
self.stats['badname_' + node_type] += 1
|
1010
|
+
|
1011
|
+
|
1012
|
+
class DocStringChecker(_BasicChecker):
|
1013
|
+
msgs = {
|
1014
|
+
'C0111': ('Missing %s docstring', # W0131
|
1015
|
+
'missing-docstring',
|
1016
|
+
'Used when a module, function, class or method has no docstring.\
|
1017
|
+
Some special methods like __init__ doesn\'t necessary require a \
|
1018
|
+
docstring.'),
|
1019
|
+
'C0112': ('Empty %s docstring', # W0132
|
1020
|
+
'empty-docstring',
|
1021
|
+
'Used when a module, function, class or method has an empty \
|
1022
|
+
docstring (it would be too easy ;).'),
|
1023
|
+
}
|
1024
|
+
options = (('no-docstring-rgx',
|
1025
|
+
{'default' : NO_REQUIRED_DOC_RGX,
|
1026
|
+
'type' : 'regexp', 'metavar' : '<regexp>',
|
1027
|
+
'help' : 'Regular expression which should only match '
|
1028
|
+
'function or class names that do not require a '
|
1029
|
+
'docstring.'}
|
1030
|
+
),
|
1031
|
+
('docstring-min-length',
|
1032
|
+
{'default' : -1,
|
1033
|
+
'type' : 'int', 'metavar' : '<int>',
|
1034
|
+
'help': ('Minimum line length for functions/classes that'
|
1035
|
+
' require docstrings, shorter ones are exempt.')}
|
1036
|
+
),
|
1037
|
+
)
|
1038
|
+
|
1039
|
+
|
1040
|
+
def open(self):
|
1041
|
+
self.stats = self.linter.add_stats(undocumented_module=0,
|
1042
|
+
undocumented_function=0,
|
1043
|
+
undocumented_method=0,
|
1044
|
+
undocumented_class=0)
|
1045
|
+
@check_messages('missing-docstring', 'empty-docstring')
|
1046
|
+
def visit_module(self, node):
|
1047
|
+
self._check_docstring('module', node)
|
1048
|
+
|
1049
|
+
@check_messages('missing-docstring', 'empty-docstring')
|
1050
|
+
def visit_class(self, node):
|
1051
|
+
if self.config.no_docstring_rgx.match(node.name) is None:
|
1052
|
+
self._check_docstring('class', node)
|
1053
|
+
@check_messages('missing-docstring', 'empty-docstring')
|
1054
|
+
def visit_function(self, node):
|
1055
|
+
if self.config.no_docstring_rgx.match(node.name) is None:
|
1056
|
+
ftype = node.is_method() and 'method' or 'function'
|
1057
|
+
if isinstance(node.parent.frame(), astroid.Class):
|
1058
|
+
overridden = False
|
1059
|
+
# check if node is from a method overridden by its ancestor
|
1060
|
+
for ancestor in node.parent.frame().ancestors():
|
1061
|
+
if node.name in ancestor and \
|
1062
|
+
isinstance(ancestor[node.name], astroid.Function):
|
1063
|
+
overridden = True
|
1064
|
+
break
|
1065
|
+
self._check_docstring(ftype, node,
|
1066
|
+
report_missing=not overridden)
|
1067
|
+
else:
|
1068
|
+
self._check_docstring(ftype, node)
|
1069
|
+
|
1070
|
+
def _check_docstring(self, node_type, node, report_missing=True):
|
1071
|
+
"""check the node has a non empty docstring"""
|
1072
|
+
docstring = node.doc
|
1073
|
+
if docstring is None:
|
1074
|
+
if not report_missing:
|
1075
|
+
return
|
1076
|
+
if node.body:
|
1077
|
+
lines = node.body[-1].lineno - node.body[0].lineno + 1
|
1078
|
+
else:
|
1079
|
+
lines = 0
|
1080
|
+
max_lines = self.config.docstring_min_length
|
1081
|
+
|
1082
|
+
if node_type != 'module' and max_lines > -1 and lines < max_lines:
|
1083
|
+
return
|
1084
|
+
self.stats['undocumented_'+node_type] += 1
|
1085
|
+
self.add_message('missing-docstring', node=node, args=(node_type,))
|
1086
|
+
elif not docstring.strip():
|
1087
|
+
self.stats['undocumented_'+node_type] += 1
|
1088
|
+
self.add_message('empty-docstring', node=node, args=(node_type,))
|
1089
|
+
|
1090
|
+
|
1091
|
+
class PassChecker(_BasicChecker):
|
1092
|
+
"""check if the pass statement is really necessary"""
|
1093
|
+
msgs = {'W0107': ('Unnecessary pass statement',
|
1094
|
+
'unnecessary-pass',
|
1095
|
+
'Used when a "pass" statement that can be avoided is '
|
1096
|
+
'encountered.'),
|
1097
|
+
}
|
1098
|
+
@check_messages('unnecessary-pass')
|
1099
|
+
def visit_pass(self, node):
|
1100
|
+
if len(node.parent.child_sequence(node)) > 1:
|
1101
|
+
self.add_message('unnecessary-pass', node=node)
|
1102
|
+
|
1103
|
+
|
1104
|
+
class LambdaForComprehensionChecker(_BasicChecker):
|
1105
|
+
"""check for using a lambda where a comprehension would do.
|
1106
|
+
|
1107
|
+
See <http://www.artima.com/weblogs/viewpost.jsp?thread=98196>
|
1108
|
+
where GvR says comprehensions would be clearer.
|
1109
|
+
"""
|
1110
|
+
|
1111
|
+
msgs = {'W0110': ('map/filter on lambda could be replaced by comprehension',
|
1112
|
+
'deprecated-lambda',
|
1113
|
+
'Used when a lambda is the first argument to "map" or '
|
1114
|
+
'"filter". It could be clearer as a list '
|
1115
|
+
'comprehension or generator expression.',
|
1116
|
+
{'maxversion': (3, 0)}),
|
1117
|
+
}
|
1118
|
+
|
1119
|
+
@check_messages('deprecated-lambda')
|
1120
|
+
def visit_callfunc(self, node):
|
1121
|
+
"""visit a CallFunc node, check if map or filter are called with a
|
1122
|
+
lambda
|
1123
|
+
"""
|
1124
|
+
if not node.args:
|
1125
|
+
return
|
1126
|
+
if not isinstance(node.args[0], astroid.Lambda):
|
1127
|
+
return
|
1128
|
+
infered = safe_infer(node.func)
|
1129
|
+
if (is_builtin_object(infered)
|
1130
|
+
and infered.name in ['map', 'filter']):
|
1131
|
+
self.add_message('deprecated-lambda', node=node)
|
1132
|
+
|
1133
|
+
|
1134
|
+
def register(linter):
|
1135
|
+
"""required method to auto register this checker"""
|
1136
|
+
linter.register_checker(BasicErrorChecker(linter))
|
1137
|
+
linter.register_checker(BasicChecker(linter))
|
1138
|
+
linter.register_checker(NameChecker(linter))
|
1139
|
+
linter.register_checker(DocStringChecker(linter))
|
1140
|
+
linter.register_checker(PassChecker(linter))
|
1141
|
+
linter.register_checker(LambdaForComprehensionChecker(linter))
|