bee_python 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +202 -0
- data/build/README +23 -0
- data/egg/egg/build.yml +70 -0
- data/egg/egg/ez_setup.py +280 -0
- data/egg/egg/script.py +12 -0
- data/egg/egg/setup.erb +11 -0
- data/egg/egg/suite.py +37 -0
- data/egg/egg/test.py +31 -0
- data/egg/egg.yml +69 -0
- data/egg/http/build.erb +53 -0
- data/egg/http/server.py +34 -0
- data/egg/http.yml +50 -0
- data/egg/mysql/mysql.py +43 -0
- data/egg/mysql.yml +44 -0
- data/egg/project/build.erb +77 -0
- data/egg/project/script.py +42 -0
- data/egg/project/test.py +31 -0
- data/egg/project.yml +59 -0
- data/egg/script/build.erb +35 -0
- data/egg/script/script.py +42 -0
- data/egg/script.yml +50 -0
- data/egg/soap/build.erb +52 -0
- data/egg/soap/client.py +18 -0
- data/egg/soap/server.py +30 -0
- data/egg/soap.yml +58 -0
- data/egg/source/source.py +42 -0
- data/egg/source.yml +47 -0
- data/egg/test/test.py +28 -0
- data/egg/test.yml +44 -0
- data/egg/xmlrpc/build.erb +52 -0
- data/egg/xmlrpc/client.py +22 -0
- data/egg/xmlrpc/server.py +24 -0
- data/egg/xmlrpc.yml +51 -0
- data/lib/bee_task_python.rb +390 -0
- data/test/build.yml +16 -0
- data/test/tc_bee_task_python.rb +27 -0
- data/test/test_build.rb +26 -0
- data/test/test_build_listener.rb +62 -0
- data/test/ts_bee_python.rb +26 -0
- data/tools/common/__init__.py +5 -0
- data/tools/common/common/__init__.py +140 -0
- data/tools/common/common/__pkginfo__.py +43 -0
- data/tools/common/common/adbh.py +35 -0
- data/tools/common/common/cache.py +114 -0
- data/tools/common/common/changelog.py +234 -0
- data/tools/common/common/clcommands.py +181 -0
- data/tools/common/common/cli.py +212 -0
- data/tools/common/common/compat.py +328 -0
- data/tools/common/common/configuration.py +1087 -0
- data/tools/common/common/contexts.py +58 -0
- data/tools/common/common/corbautils.py +117 -0
- data/tools/common/common/daemon.py +171 -0
- data/tools/common/common/date.py +279 -0
- data/tools/common/common/db.py +49 -0
- data/tools/common/common/dbf.py +229 -0
- data/tools/common/common/debugger.py +208 -0
- data/tools/common/common/decorators.py +190 -0
- data/tools/common/common/deprecation.py +118 -0
- data/tools/common/common/fileutils.py +409 -0
- data/tools/common/common/graph.py +259 -0
- data/tools/common/common/html.py +142 -0
- data/tools/common/common/interface.py +76 -0
- data/tools/common/common/logging_ext.py +166 -0
- data/tools/common/common/modutils.py +670 -0
- data/tools/common/common/optik_ext.py +383 -0
- data/tools/common/common/optparser.py +92 -0
- data/tools/common/common/pdf_ext.py +111 -0
- data/tools/common/common/proc.py +276 -0
- data/tools/common/common/pyro_ext.py +146 -0
- data/tools/common/common/pytest.py +754 -0
- data/tools/common/common/shellutils.py +383 -0
- data/tools/common/common/sphinx_ext.py +87 -0
- data/tools/common/common/sphinxutils.py +122 -0
- data/tools/common/common/sqlgen.py +31 -0
- data/tools/common/common/table.py +930 -0
- data/tools/common/common/tasksqueue.py +97 -0
- data/tools/common/common/test/__init__.py +1 -0
- data/tools/common/common/test/data/ChangeLog +184 -0
- data/tools/common/common/test/data/MyPyPa-0.1.0-py2.5.egg +0 -0
- data/tools/common/common/test/data/__init__.py +1 -0
- data/tools/common/common/test/data/content_differ_dir/NOTHING +0 -0
- data/tools/common/common/test/data/content_differ_dir/README +1 -0
- data/tools/common/common/test/data/content_differ_dir/subdir/coin +1 -0
- data/tools/common/common/test/data/content_differ_dir/subdir/toto.txt +53 -0
- data/tools/common/common/test/data/file_differ_dir/NOTHING +0 -0
- data/tools/common/common/test/data/file_differ_dir/README +1 -0
- data/tools/common/common/test/data/file_differ_dir/subdir/toto.txt +53 -0
- data/tools/common/common/test/data/file_differ_dir/subdirtwo/Hello +0 -0
- data/tools/common/common/test/data/find_test/__init__.py +0 -0
- data/tools/common/common/test/data/find_test/foo.txt +0 -0
- data/tools/common/common/test/data/find_test/module.py +0 -0
- data/tools/common/common/test/data/find_test/module2.py +0 -0
- data/tools/common/common/test/data/find_test/newlines.txt +0 -0
- data/tools/common/common/test/data/find_test/noendingnewline.py +0 -0
- data/tools/common/common/test/data/find_test/nonregr.py +0 -0
- data/tools/common/common/test/data/find_test/normal_file.txt +0 -0
- data/tools/common/common/test/data/find_test/spam.txt +0 -0
- data/tools/common/common/test/data/find_test/sub/doc.txt +0 -0
- data/tools/common/common/test/data/find_test/sub/momo.py +0 -0
- data/tools/common/common/test/data/find_test/test.ini +0 -0
- data/tools/common/common/test/data/find_test/test1.msg +0 -0
- data/tools/common/common/test/data/find_test/test2.msg +0 -0
- data/tools/common/common/test/data/find_test/write_protected_file.txt +0 -0
- data/tools/common/common/test/data/foo.txt +9 -0
- data/tools/common/common/test/data/module.py +88 -0
- data/tools/common/common/test/data/module2.py +77 -0
- data/tools/common/common/test/data/newlines.txt +3 -0
- data/tools/common/common/test/data/noendingnewline.py +36 -0
- data/tools/common/common/test/data/nonregr.py +14 -0
- data/tools/common/common/test/data/normal_file.txt +0 -0
- data/tools/common/common/test/data/reference_dir/NOTHING +0 -0
- data/tools/common/common/test/data/reference_dir/README +1 -0
- data/tools/common/common/test/data/reference_dir/subdir/coin +1 -0
- data/tools/common/common/test/data/reference_dir/subdir/toto.txt +53 -0
- data/tools/common/common/test/data/same_dir/NOTHING +0 -0
- data/tools/common/common/test/data/same_dir/README +1 -0
- data/tools/common/common/test/data/same_dir/subdir/coin +1 -0
- data/tools/common/common/test/data/same_dir/subdir/toto.txt +53 -0
- data/tools/common/common/test/data/spam.txt +9 -0
- data/tools/common/common/test/data/sub/doc.txt +1 -0
- data/tools/common/common/test/data/sub/momo.py +1 -0
- data/tools/common/common/test/data/subdir_differ_dir/NOTHING +0 -0
- data/tools/common/common/test/data/subdir_differ_dir/README +1 -0
- data/tools/common/common/test/data/subdir_differ_dir/subdir/coin +1 -0
- data/tools/common/common/test/data/subdir_differ_dir/subdir/toto.txt +53 -0
- data/tools/common/common/test/data/test.ini +20 -0
- data/tools/common/common/test/data/test1.msg +30 -0
- data/tools/common/common/test/data/test2.msg +42 -0
- data/tools/common/common/test/data/write_protected_file.txt +0 -0
- data/tools/common/common/test/foomod.py +17 -0
- data/tools/common/common/test/unittest_cache.py +129 -0
- data/tools/common/common/test/unittest_changelog.py +37 -0
- data/tools/common/common/test/unittest_compat.py +239 -0
- data/tools/common/common/test/unittest_configuration.py +348 -0
- data/tools/common/common/test/unittest_date.py +154 -0
- data/tools/common/common/test/unittest_decorators.py +62 -0
- data/tools/common/common/test/unittest_deprecation.py +76 -0
- data/tools/common/common/test/unittest_fileutils.py +133 -0
- data/tools/common/common/test/unittest_graph.py +50 -0
- data/tools/common/common/test/unittest_html.py +76 -0
- data/tools/common/common/test/unittest_interface.py +87 -0
- data/tools/common/common/test/unittest_modutils.py +244 -0
- data/tools/common/common/test/unittest_pytest.py +50 -0
- data/tools/common/common/test/unittest_shellutils.py +248 -0
- data/tools/common/common/test/unittest_table.py +448 -0
- data/tools/common/common/test/unittest_taskqueue.py +71 -0
- data/tools/common/common/test/unittest_testlib.py +956 -0
- data/tools/common/common/test/unittest_textutils.py +247 -0
- data/tools/common/common/test/unittest_tree.py +248 -0
- data/tools/common/common/test/unittest_umessage.py +55 -0
- data/tools/common/common/test/unittest_ureports_html.py +64 -0
- data/tools/common/common/test/unittest_ureports_text.py +105 -0
- data/tools/common/common/test/unittest_xmlutils.py +75 -0
- data/tools/common/common/test/utils.py +87 -0
- data/tools/common/common/testlib.py +1927 -0
- data/tools/common/common/textutils.py +476 -0
- data/tools/common/common/tree.py +372 -0
- data/tools/common/common/umessage.py +161 -0
- data/tools/common/common/ureports/__init__.py +174 -0
- data/tools/common/common/ureports/docbook_writer.py +139 -0
- data/tools/common/common/ureports/html_writer.py +131 -0
- data/tools/common/common/ureports/nodes.py +201 -0
- data/tools/common/common/ureports/text_writer.py +140 -0
- data/tools/common/common/vcgutils.py +216 -0
- data/tools/common/common/visitor.py +107 -0
- data/tools/common/common/xmlrpcutils.py +136 -0
- data/tools/common/common/xmlutils.py +61 -0
- data/tools/compile/compile.py +16 -0
- data/tools/coverage/coverage.py +602 -0
- data/tools/epydoc/__init__.py +227 -0
- data/tools/epydoc/__init__.pyc +0 -0
- data/tools/epydoc/apidoc.py +2203 -0
- data/tools/epydoc/apidoc.pyc +0 -0
- data/tools/epydoc/checker.py +349 -0
- data/tools/epydoc/checker.pyc +0 -0
- data/tools/epydoc/cli.py +1470 -0
- data/tools/epydoc/cli.pyc +0 -0
- data/tools/epydoc/compat.py +250 -0
- data/tools/epydoc/compat.pyc +0 -0
- data/tools/epydoc/docbuilder.py +1358 -0
- data/tools/epydoc/docbuilder.pyc +0 -0
- data/tools/epydoc/docintrospecter.py +1056 -0
- data/tools/epydoc/docintrospecter.pyc +0 -0
- data/tools/epydoc/docparser.py +2113 -0
- data/tools/epydoc/docparser.pyc +0 -0
- data/tools/epydoc/docstringparser.py +1111 -0
- data/tools/epydoc/docstringparser.pyc +0 -0
- data/tools/epydoc/docwriter/__init__.py +12 -0
- data/tools/epydoc/docwriter/__init__.pyc +0 -0
- data/tools/epydoc/docwriter/dotgraph.py +1351 -0
- data/tools/epydoc/docwriter/dotgraph.pyc +0 -0
- data/tools/epydoc/docwriter/html.py +3491 -0
- data/tools/epydoc/docwriter/html.pyc +0 -0
- data/tools/epydoc/docwriter/html_colorize.py +909 -0
- data/tools/epydoc/docwriter/html_colorize.pyc +0 -0
- data/tools/epydoc/docwriter/html_css.py +550 -0
- data/tools/epydoc/docwriter/html_css.pyc +0 -0
- data/tools/epydoc/docwriter/html_help.py +190 -0
- data/tools/epydoc/docwriter/html_help.pyc +0 -0
- data/tools/epydoc/docwriter/latex.py +1187 -0
- data/tools/epydoc/docwriter/latex.pyc +0 -0
- data/tools/epydoc/docwriter/plaintext.py +276 -0
- data/tools/epydoc/docwriter/plaintext.pyc +0 -0
- data/tools/epydoc/docwriter/xlink.py +505 -0
- data/tools/epydoc/docwriter/xlink.pyc +0 -0
- data/tools/epydoc/gui.py +1148 -0
- data/tools/epydoc/gui.pyc +0 -0
- data/tools/epydoc/log.py +204 -0
- data/tools/epydoc/log.pyc +0 -0
- data/tools/epydoc/markup/__init__.py +623 -0
- data/tools/epydoc/markup/__init__.pyc +0 -0
- data/tools/epydoc/markup/doctest.py +311 -0
- data/tools/epydoc/markup/doctest.pyc +0 -0
- data/tools/epydoc/markup/epytext.py +2116 -0
- data/tools/epydoc/markup/epytext.pyc +0 -0
- data/tools/epydoc/markup/javadoc.py +250 -0
- data/tools/epydoc/markup/javadoc.pyc +0 -0
- data/tools/epydoc/markup/plaintext.py +78 -0
- data/tools/epydoc/markup/plaintext.pyc +0 -0
- data/tools/epydoc/markup/pyval_repr.py +532 -0
- data/tools/epydoc/markup/pyval_repr.pyc +0 -0
- data/tools/epydoc/markup/restructuredtext.py +906 -0
- data/tools/epydoc/markup/restructuredtext.pyc +0 -0
- data/tools/epydoc/test/__init__.py +97 -0
- data/tools/epydoc/test/__init__.pyc +0 -0
- data/tools/epydoc/test/util.py +226 -0
- data/tools/epydoc/test/util.pyc +0 -0
- data/tools/epydoc/util.py +289 -0
- data/tools/epydoc/util.pyc +0 -0
- data/tools/logilab/logilab/__init__.py +5 -0
- data/tools/logilab/logilab/astng/__init__.py +82 -0
- data/tools/logilab/logilab/astng/__pkginfo__.py +76 -0
- data/tools/logilab/logilab/astng/_exceptions.py +64 -0
- data/tools/logilab/logilab/astng/_nodes_ast.py +667 -0
- data/tools/logilab/logilab/astng/_nodes_compiler.py +758 -0
- data/tools/logilab/logilab/astng/bases.py +608 -0
- data/tools/logilab/logilab/astng/builder.py +239 -0
- data/tools/logilab/logilab/astng/inference.py +426 -0
- data/tools/logilab/logilab/astng/inspector.py +289 -0
- data/tools/logilab/logilab/astng/manager.py +421 -0
- data/tools/logilab/logilab/astng/mixins.py +165 -0
- data/tools/logilab/logilab/astng/node_classes.py +848 -0
- data/tools/logilab/logilab/astng/nodes.py +85 -0
- data/tools/logilab/logilab/astng/nodes_as_string.py +389 -0
- data/tools/logilab/logilab/astng/patchcomptransformer.py +159 -0
- data/tools/logilab/logilab/astng/protocols.py +333 -0
- data/tools/logilab/logilab/astng/raw_building.py +212 -0
- data/tools/logilab/logilab/astng/rebuilder.py +307 -0
- data/tools/logilab/logilab/astng/scoped_nodes.py +951 -0
- data/tools/logilab/logilab/astng/test/__init__.py +19 -0
- data/tools/logilab/logilab/astng/test/data/MyPyPa-0.1.0-py2.5.egg +0 -0
- data/tools/logilab/logilab/astng/test/data/MyPyPa-0.1.0-py2.5.zip +0 -0
- data/tools/logilab/logilab/astng/test/data/SSL1/Connection1.py +33 -0
- data/tools/logilab/logilab/astng/test/data/SSL1/__init__.py +20 -0
- data/tools/logilab/logilab/astng/test/data/__init__.py +20 -0
- data/tools/logilab/logilab/astng/test/data/all.py +29 -0
- data/tools/logilab/logilab/astng/test/data/appl/__init__.py +23 -0
- data/tools/logilab/logilab/astng/test/data/appl/myConnection.py +30 -0
- data/tools/logilab/logilab/astng/test/data/format.py +34 -0
- data/tools/logilab/logilab/astng/test/data/module.py +90 -0
- data/tools/logilab/logilab/astng/test/data/module2.py +112 -0
- data/tools/logilab/logilab/astng/test/data/noendingnewline.py +57 -0
- data/tools/logilab/logilab/astng/test/data/nonregr.py +76 -0
- data/tools/logilab/logilab/astng/test/data/notall.py +28 -0
- data/tools/logilab/logilab/astng/test/data2/__init__.py +20 -0
- data/tools/logilab/logilab/astng/test/data2/clientmodule_test.py +51 -0
- data/tools/logilab/logilab/astng/test/data2/suppliermodule_test.py +32 -0
- data/tools/logilab/logilab/astng/test/regrtest.py +135 -0
- data/tools/logilab/logilab/astng/test/regrtest_data/absimport.py +22 -0
- data/tools/logilab/logilab/astng/test/regrtest_data/descriptor_crash.py +31 -0
- data/tools/logilab/logilab/astng/test/regrtest_data/import_package_subpackage_module.py +68 -0
- data/tools/logilab/logilab/astng/test/regrtest_data/package/__init__.py +24 -0
- data/tools/logilab/logilab/astng/test/regrtest_data/package/subpackage/__init__.py +20 -0
- data/tools/logilab/logilab/astng/test/regrtest_data/package/subpackage/module.py +20 -0
- data/tools/logilab/logilab/astng/test/unittest_builder.py +684 -0
- data/tools/logilab/logilab/astng/test/unittest_inference.py +1112 -0
- data/tools/logilab/logilab/astng/test/unittest_inspector.py +105 -0
- data/tools/logilab/logilab/astng/test/unittest_lookup.py +302 -0
- data/tools/logilab/logilab/astng/test/unittest_manager.py +98 -0
- data/tools/logilab/logilab/astng/test/unittest_nodes.py +302 -0
- data/tools/logilab/logilab/astng/test/unittest_scoped_nodes.py +501 -0
- data/tools/logilab/logilab/astng/test/unittest_utils.py +104 -0
- data/tools/logilab/logilab/astng/utils.py +342 -0
- data/tools/logilab/logilab/common/__init__.py +140 -0
- data/tools/logilab/logilab/common/__pkginfo__.py +43 -0
- data/tools/logilab/logilab/common/adbh.py +35 -0
- data/tools/logilab/logilab/common/cache.py +114 -0
- data/tools/logilab/logilab/common/changelog.py +234 -0
- data/tools/logilab/logilab/common/clcommands.py +181 -0
- data/tools/logilab/logilab/common/cli.py +212 -0
- data/tools/logilab/logilab/common/compat.py +328 -0
- data/tools/logilab/logilab/common/configuration.py +1087 -0
- data/tools/logilab/logilab/common/contexts.py +58 -0
- data/tools/logilab/logilab/common/corbautils.py +117 -0
- data/tools/logilab/logilab/common/daemon.py +171 -0
- data/tools/logilab/logilab/common/date.py +279 -0
- data/tools/logilab/logilab/common/db.py +49 -0
- data/tools/logilab/logilab/common/dbf.py +229 -0
- data/tools/logilab/logilab/common/debugger.py +208 -0
- data/tools/logilab/logilab/common/decorators.py +190 -0
- data/tools/logilab/logilab/common/deprecation.py +118 -0
- data/tools/logilab/logilab/common/fileutils.py +409 -0
- data/tools/logilab/logilab/common/graph.py +259 -0
- data/tools/logilab/logilab/common/html.py +142 -0
- data/tools/logilab/logilab/common/interface.py +76 -0
- data/tools/logilab/logilab/common/logging_ext.py +166 -0
- data/tools/logilab/logilab/common/modutils.py +670 -0
- data/tools/logilab/logilab/common/optik_ext.py +383 -0
- data/tools/logilab/logilab/common/optparser.py +92 -0
- data/tools/logilab/logilab/common/pdf_ext.py +111 -0
- data/tools/logilab/logilab/common/proc.py +276 -0
- data/tools/logilab/logilab/common/pyro_ext.py +146 -0
- data/tools/logilab/logilab/common/pytest.py +754 -0
- data/tools/logilab/logilab/common/shellutils.py +383 -0
- data/tools/logilab/logilab/common/sphinx_ext.py +87 -0
- data/tools/logilab/logilab/common/sphinxutils.py +122 -0
- data/tools/logilab/logilab/common/sqlgen.py +31 -0
- data/tools/logilab/logilab/common/table.py +930 -0
- data/tools/logilab/logilab/common/tasksqueue.py +97 -0
- data/tools/logilab/logilab/common/test/__init__.py +1 -0
- data/tools/logilab/logilab/common/test/data/ChangeLog +184 -0
- data/tools/logilab/logilab/common/test/data/MyPyPa-0.1.0-py2.5.egg +0 -0
- data/tools/logilab/logilab/common/test/data/__init__.py +1 -0
- data/tools/logilab/logilab/common/test/data/content_differ_dir/NOTHING +0 -0
- data/tools/logilab/logilab/common/test/data/content_differ_dir/README +1 -0
- data/tools/logilab/logilab/common/test/data/content_differ_dir/subdir/coin +1 -0
- data/tools/logilab/logilab/common/test/data/content_differ_dir/subdir/toto.txt +53 -0
- data/tools/logilab/logilab/common/test/data/file_differ_dir/NOTHING +0 -0
- data/tools/logilab/logilab/common/test/data/file_differ_dir/README +1 -0
- data/tools/logilab/logilab/common/test/data/file_differ_dir/subdir/toto.txt +53 -0
- data/tools/logilab/logilab/common/test/data/file_differ_dir/subdirtwo/Hello +0 -0
- data/tools/logilab/logilab/common/test/data/find_test/__init__.py +0 -0
- data/tools/logilab/logilab/common/test/data/find_test/foo.txt +0 -0
- data/tools/logilab/logilab/common/test/data/find_test/module.py +0 -0
- data/tools/logilab/logilab/common/test/data/find_test/module2.py +0 -0
- data/tools/logilab/logilab/common/test/data/find_test/newlines.txt +0 -0
- data/tools/logilab/logilab/common/test/data/find_test/noendingnewline.py +0 -0
- data/tools/logilab/logilab/common/test/data/find_test/nonregr.py +0 -0
- data/tools/logilab/logilab/common/test/data/find_test/normal_file.txt +0 -0
- data/tools/logilab/logilab/common/test/data/find_test/spam.txt +0 -0
- data/tools/logilab/logilab/common/test/data/find_test/sub/doc.txt +0 -0
- data/tools/logilab/logilab/common/test/data/find_test/sub/momo.py +0 -0
- data/tools/logilab/logilab/common/test/data/find_test/test.ini +0 -0
- data/tools/logilab/logilab/common/test/data/find_test/test1.msg +0 -0
- data/tools/logilab/logilab/common/test/data/find_test/test2.msg +0 -0
- data/tools/logilab/logilab/common/test/data/find_test/write_protected_file.txt +0 -0
- data/tools/logilab/logilab/common/test/data/foo.txt +9 -0
- data/tools/logilab/logilab/common/test/data/module.py +88 -0
- data/tools/logilab/logilab/common/test/data/module2.py +77 -0
- data/tools/logilab/logilab/common/test/data/newlines.txt +3 -0
- data/tools/logilab/logilab/common/test/data/noendingnewline.py +36 -0
- data/tools/logilab/logilab/common/test/data/nonregr.py +14 -0
- data/tools/logilab/logilab/common/test/data/normal_file.txt +0 -0
- data/tools/logilab/logilab/common/test/data/reference_dir/NOTHING +0 -0
- data/tools/logilab/logilab/common/test/data/reference_dir/README +1 -0
- data/tools/logilab/logilab/common/test/data/reference_dir/subdir/coin +1 -0
- data/tools/logilab/logilab/common/test/data/reference_dir/subdir/toto.txt +53 -0
- data/tools/logilab/logilab/common/test/data/same_dir/NOTHING +0 -0
- data/tools/logilab/logilab/common/test/data/same_dir/README +1 -0
- data/tools/logilab/logilab/common/test/data/same_dir/subdir/coin +1 -0
- data/tools/logilab/logilab/common/test/data/same_dir/subdir/toto.txt +53 -0
- data/tools/logilab/logilab/common/test/data/spam.txt +9 -0
- data/tools/logilab/logilab/common/test/data/sub/doc.txt +1 -0
- data/tools/logilab/logilab/common/test/data/sub/momo.py +1 -0
- data/tools/logilab/logilab/common/test/data/subdir_differ_dir/NOTHING +0 -0
- data/tools/logilab/logilab/common/test/data/subdir_differ_dir/README +1 -0
- data/tools/logilab/logilab/common/test/data/subdir_differ_dir/subdir/coin +1 -0
- data/tools/logilab/logilab/common/test/data/subdir_differ_dir/subdir/toto.txt +53 -0
- data/tools/logilab/logilab/common/test/data/test.ini +20 -0
- data/tools/logilab/logilab/common/test/data/test1.msg +30 -0
- data/tools/logilab/logilab/common/test/data/test2.msg +42 -0
- data/tools/logilab/logilab/common/test/data/write_protected_file.txt +0 -0
- data/tools/logilab/logilab/common/test/foomod.py +17 -0
- data/tools/logilab/logilab/common/test/unittest_cache.py +129 -0
- data/tools/logilab/logilab/common/test/unittest_changelog.py +37 -0
- data/tools/logilab/logilab/common/test/unittest_compat.py +239 -0
- data/tools/logilab/logilab/common/test/unittest_configuration.py +348 -0
- data/tools/logilab/logilab/common/test/unittest_date.py +154 -0
- data/tools/logilab/logilab/common/test/unittest_decorators.py +62 -0
- data/tools/logilab/logilab/common/test/unittest_deprecation.py +76 -0
- data/tools/logilab/logilab/common/test/unittest_fileutils.py +133 -0
- data/tools/logilab/logilab/common/test/unittest_graph.py +50 -0
- data/tools/logilab/logilab/common/test/unittest_html.py +76 -0
- data/tools/logilab/logilab/common/test/unittest_interface.py +87 -0
- data/tools/logilab/logilab/common/test/unittest_modutils.py +244 -0
- data/tools/logilab/logilab/common/test/unittest_pytest.py +50 -0
- data/tools/logilab/logilab/common/test/unittest_shellutils.py +248 -0
- data/tools/logilab/logilab/common/test/unittest_table.py +448 -0
- data/tools/logilab/logilab/common/test/unittest_taskqueue.py +71 -0
- data/tools/logilab/logilab/common/test/unittest_testlib.py +956 -0
- data/tools/logilab/logilab/common/test/unittest_textutils.py +247 -0
- data/tools/logilab/logilab/common/test/unittest_tree.py +248 -0
- data/tools/logilab/logilab/common/test/unittest_umessage.py +55 -0
- data/tools/logilab/logilab/common/test/unittest_ureports_html.py +64 -0
- data/tools/logilab/logilab/common/test/unittest_ureports_text.py +105 -0
- data/tools/logilab/logilab/common/test/unittest_xmlutils.py +75 -0
- data/tools/logilab/logilab/common/test/utils.py +87 -0
- data/tools/logilab/logilab/common/testlib.py +1927 -0
- data/tools/logilab/logilab/common/textutils.py +476 -0
- data/tools/logilab/logilab/common/tree.py +372 -0
- data/tools/logilab/logilab/common/umessage.py +161 -0
- data/tools/logilab/logilab/common/ureports/__init__.py +174 -0
- data/tools/logilab/logilab/common/ureports/docbook_writer.py +139 -0
- data/tools/logilab/logilab/common/ureports/html_writer.py +131 -0
- data/tools/logilab/logilab/common/ureports/nodes.py +201 -0
- data/tools/logilab/logilab/common/ureports/text_writer.py +140 -0
- data/tools/logilab/logilab/common/vcgutils.py +216 -0
- data/tools/logilab/logilab/common/visitor.py +107 -0
- data/tools/logilab/logilab/common/xmlrpcutils.py +136 -0
- data/tools/logilab/logilab/common/xmlutils.py +61 -0
- data/tools/pychecker/COPYRIGHT +31 -0
- data/tools/pychecker/ChangeLog +349 -0
- data/tools/pychecker/CodeChecks.py +1969 -0
- data/tools/pychecker/CodeChecks.pyc +0 -0
- data/tools/pychecker/CodeChecks.pyo +0 -0
- data/tools/pychecker/Config.py +475 -0
- data/tools/pychecker/Config.pyc +0 -0
- data/tools/pychecker/Config.pyo +0 -0
- data/tools/pychecker/KNOWN_BUGS +100 -0
- data/tools/pychecker/MAINTAINERS +81 -0
- data/tools/pychecker/NEWS +406 -0
- data/tools/pychecker/OP.py +131 -0
- data/tools/pychecker/OP.pyc +0 -0
- data/tools/pychecker/OP.pyo +0 -0
- data/tools/pychecker/OptionTypes.py +117 -0
- data/tools/pychecker/OptionTypes.pyc +0 -0
- data/tools/pychecker/OptionTypes.pyo +0 -0
- data/tools/pychecker/README +152 -0
- data/tools/pychecker/Stack.py +115 -0
- data/tools/pychecker/Stack.pyc +0 -0
- data/tools/pychecker/Stack.pyo +0 -0
- data/tools/pychecker/TODO +101 -0
- data/tools/pychecker/VERSION +1 -0
- data/tools/pychecker/Warning.py +50 -0
- data/tools/pychecker/Warning.pyc +0 -0
- data/tools/pychecker/Warning.pyo +0 -0
- data/tools/pychecker/__init__.py +17 -0
- data/tools/pychecker/__init__.pyc +0 -0
- data/tools/pychecker/__init__.pyo +0 -0
- data/tools/pychecker/checker.py +961 -0
- data/tools/pychecker/checker.pyc +0 -0
- data/tools/pychecker/checker.pyo +0 -0
- data/tools/pychecker/function.py +159 -0
- data/tools/pychecker/function.pyc +0 -0
- data/tools/pychecker/function.pyo +0 -0
- data/tools/pychecker/msgs.py +175 -0
- data/tools/pychecker/msgs.pyc +0 -0
- data/tools/pychecker/msgs.pyo +0 -0
- data/tools/pychecker/options.py +275 -0
- data/tools/pychecker/options.pyc +0 -0
- data/tools/pychecker/options.pyo +0 -0
- data/tools/pychecker/pcmodules.py +19 -0
- data/tools/pychecker/pcmodules.pyc +0 -0
- data/tools/pychecker/pcmodules.pyo +0 -0
- data/tools/pychecker/printer.py +47 -0
- data/tools/pychecker/printer.pyc +0 -0
- data/tools/pychecker/printer.pyo +0 -0
- data/tools/pychecker/python.py +427 -0
- data/tools/pychecker/python.pyc +0 -0
- data/tools/pychecker/python.pyo +0 -0
- data/tools/pychecker/utils.py +102 -0
- data/tools/pychecker/utils.pyc +0 -0
- data/tools/pychecker/utils.pyo +0 -0
- data/tools/pychecker/warn.py +778 -0
- data/tools/pychecker/warn.pyc +0 -0
- data/tools/pychecker/warn.pyo +0 -0
- data/tools/pylint2/pylint/__init__.py +16 -0
- data/tools/pylint2/pylint/__pkginfo__.py +67 -0
- data/tools/pylint2/pylint/checkers/__init__.py +155 -0
- data/tools/pylint2/pylint/checkers/base.py +749 -0
- data/tools/pylint2/pylint/checkers/classes.py +527 -0
- data/tools/pylint2/pylint/checkers/design_analysis.py +344 -0
- data/tools/pylint2/pylint/checkers/exceptions.py +183 -0
- data/tools/pylint2/pylint/checkers/format.py +367 -0
- data/tools/pylint2/pylint/checkers/imports.py +379 -0
- data/tools/pylint2/pylint/checkers/logging.py +98 -0
- data/tools/pylint2/pylint/checkers/misc.py +128 -0
- data/tools/pylint2/pylint/checkers/newstyle.py +107 -0
- data/tools/pylint2/pylint/checkers/raw_metrics.py +125 -0
- data/tools/pylint2/pylint/checkers/similar.py +333 -0
- data/tools/pylint2/pylint/checkers/string_format.py +239 -0
- data/tools/pylint2/pylint/checkers/typecheck.py +364 -0
- data/tools/pylint2/pylint/checkers/utils.py +208 -0
- data/tools/pylint2/pylint/checkers/variables.py +498 -0
- data/tools/pylint2/pylint/config.py +149 -0
- data/tools/pylint2/pylint/epylint.py +149 -0
- data/tools/pylint2/pylint/gui.py +433 -0
- data/tools/pylint2/pylint/interfaces.py +98 -0
- data/tools/pylint2/pylint/lint.py +914 -0
- data/tools/pylint2/pylint/pyreverse/__init__.py +5 -0
- data/tools/pylint2/pylint/pyreverse/diadefslib.py +229 -0
- data/tools/pylint2/pylint/pyreverse/diagrams.py +247 -0
- data/tools/pylint2/pylint/pyreverse/main.py +123 -0
- data/tools/pylint2/pylint/pyreverse/utils.py +131 -0
- data/tools/pylint2/pylint/pyreverse/writer.py +196 -0
- data/tools/pylint2/pylint/reporters/__init__.py +67 -0
- data/tools/pylint2/pylint/reporters/guireporter.py +36 -0
- data/tools/pylint2/pylint/reporters/html.py +69 -0
- data/tools/pylint2/pylint/reporters/text.py +156 -0
- data/tools/pylint2/pylint/utils.py +518 -0
- data/tools/pylint2/pylint.py +16 -0
- data/tools/test/suite.py +35 -0
- metadata +566 -0
@@ -0,0 +1,107 @@
|
|
1
|
+
# Copyright (c) 2005-2006 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
|
+
# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
16
|
+
"""check for new / old style related problems
|
17
|
+
"""
|
18
|
+
|
19
|
+
from logilab import astng
|
20
|
+
|
21
|
+
from pylint.interfaces import IASTNGChecker
|
22
|
+
from pylint.checkers import BaseChecker
|
23
|
+
|
24
|
+
MSGS = {
|
25
|
+
'E1001': ('Use __slots__ on an old style class',
|
26
|
+
'Used when an old style class use the __slots__ attribute.'),
|
27
|
+
'E1002': ('Use super on an old style class',
|
28
|
+
'Used when an old style class use the super builtin.'),
|
29
|
+
'E1003': ('Bad first argument %r given to super class',
|
30
|
+
'Used when another argument than the current class is given as \
|
31
|
+
first argument of the super builtin.'),
|
32
|
+
'W1001': ('Use of "property" on an old style class',
|
33
|
+
'Used when PyLint detect the use of the builtin "property" \
|
34
|
+
on an old style class while this is relying on new style \
|
35
|
+
classes features'),
|
36
|
+
}
|
37
|
+
|
38
|
+
|
39
|
+
class NewStyleConflictChecker(BaseChecker):
|
40
|
+
"""checks for usage of new style capabilities on old style classes and
|
41
|
+
other new/old styles conflicts problems
|
42
|
+
* use of property, __slots__, super
|
43
|
+
* "super" usage
|
44
|
+
"""
|
45
|
+
|
46
|
+
__implements__ = (IASTNGChecker,)
|
47
|
+
|
48
|
+
# configuration section name
|
49
|
+
name = 'newstyle'
|
50
|
+
# messages
|
51
|
+
msgs = MSGS
|
52
|
+
priority = -2
|
53
|
+
# configuration options
|
54
|
+
options = ()
|
55
|
+
|
56
|
+
# def __init__(self, linter=None):
|
57
|
+
# BaseChecker.__init__(self, linter)
|
58
|
+
|
59
|
+
def visit_class(self, node):
|
60
|
+
"""check __slots__ usage
|
61
|
+
"""
|
62
|
+
if '__slots__' in node and not node.newstyle:
|
63
|
+
self.add_message('E1001', node=node)
|
64
|
+
|
65
|
+
def visit_callfunc(self, node):
|
66
|
+
"""check property usage"""
|
67
|
+
parent = node.parent.frame()
|
68
|
+
if (isinstance(parent, astng.Class) and
|
69
|
+
not parent.newstyle and
|
70
|
+
isinstance(node.func, astng.Name)):
|
71
|
+
name = node.func.name
|
72
|
+
if name == 'property':
|
73
|
+
self.add_message('W1001', node=node)
|
74
|
+
|
75
|
+
def visit_function(self, node):
|
76
|
+
"""check use of super"""
|
77
|
+
# ignore actual functions or method within a new style class
|
78
|
+
if not node.is_method():
|
79
|
+
return
|
80
|
+
klass = node.parent.frame()
|
81
|
+
for stmt in node.nodes_of_class(astng.CallFunc):
|
82
|
+
expr = stmt.func
|
83
|
+
if not isinstance(expr, astng.Getattr):
|
84
|
+
continue
|
85
|
+
call = expr.expr
|
86
|
+
# skip the test if using super
|
87
|
+
if isinstance(call, astng.CallFunc) and \
|
88
|
+
isinstance(call.func, astng.Name) and \
|
89
|
+
call.func.name == 'super':
|
90
|
+
if not klass.newstyle:
|
91
|
+
# super should not be used on an old style class
|
92
|
+
self.add_message('E1002', node=node)
|
93
|
+
else:
|
94
|
+
# super first arg should be the class
|
95
|
+
try:
|
96
|
+
supcls = (call.args and call.args[0].infer().next()
|
97
|
+
or None)
|
98
|
+
except astng.InferenceError:
|
99
|
+
continue
|
100
|
+
if klass is not supcls:
|
101
|
+
supcls = getattr(supcls, 'name', supcls)
|
102
|
+
self.add_message('E1003', node=node, args=supcls)
|
103
|
+
|
104
|
+
|
105
|
+
def register(linter):
|
106
|
+
"""required method to auto register this checker """
|
107
|
+
linter.register_checker(NewStyleConflictChecker(linter))
|
@@ -0,0 +1,125 @@
|
|
1
|
+
# This program is free software; you can redistribute it and/or modify it under
|
2
|
+
# the terms of the GNU General Public License as published by the Free Software
|
3
|
+
# Foundation; either version 2 of the License, or (at your option) any later
|
4
|
+
# version.
|
5
|
+
#
|
6
|
+
# This program is distributed in the hope that it will be useful, but WITHOUT
|
7
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
8
|
+
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
9
|
+
#
|
10
|
+
# You should have received a copy of the GNU General Public License along with
|
11
|
+
# this program; if not, write to the Free Software Foundation, Inc.,
|
12
|
+
# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
13
|
+
""" Copyright (c) 2003-2010 LOGILAB S.A. (Paris, FRANCE).
|
14
|
+
http://www.logilab.fr/ -- mailto:contact@logilab.fr
|
15
|
+
|
16
|
+
Raw metrics checker
|
17
|
+
"""
|
18
|
+
|
19
|
+
import tokenize
|
20
|
+
|
21
|
+
# pylint now requires pylint >= 2.2, so this is no longer necessary
|
22
|
+
#if not hasattr(tokenize, 'NL'):
|
23
|
+
# raise ValueError("tokenize.NL doesn't exist -- tokenize module too old")
|
24
|
+
|
25
|
+
from logilab.common.ureports import Table
|
26
|
+
|
27
|
+
from pylint.interfaces import IRawChecker
|
28
|
+
from pylint.checkers import BaseRawChecker, EmptyReport
|
29
|
+
from pylint.reporters import diff_string
|
30
|
+
|
31
|
+
def report_raw_stats(sect, stats, old_stats):
|
32
|
+
"""calculate percentage of code / doc / comment / empty
|
33
|
+
"""
|
34
|
+
total_lines = stats['total_lines']
|
35
|
+
if not total_lines:
|
36
|
+
raise EmptyReport()
|
37
|
+
sect.description = '%s lines have been analyzed' % total_lines
|
38
|
+
lines = ('type', 'number', '%', 'previous', 'difference')
|
39
|
+
for node_type in ('code', 'docstring', 'comment', 'empty'):
|
40
|
+
key = node_type + '_lines'
|
41
|
+
total = stats[key]
|
42
|
+
percent = float(total * 100) / total_lines
|
43
|
+
old = old_stats.get(key, None)
|
44
|
+
if old is not None:
|
45
|
+
diff_str = diff_string(old, total)
|
46
|
+
else:
|
47
|
+
old, diff_str = 'NC', 'NC'
|
48
|
+
lines += (node_type, str(total), '%.2f' % percent,
|
49
|
+
str(old), diff_str)
|
50
|
+
sect.append(Table(children=lines, cols=5, rheaders=1))
|
51
|
+
|
52
|
+
|
53
|
+
class RawMetricsChecker(BaseRawChecker):
|
54
|
+
"""does not check anything but gives some raw metrics :
|
55
|
+
* total number of lines
|
56
|
+
* total number of code lines
|
57
|
+
* total number of docstring lines
|
58
|
+
* total number of comments lines
|
59
|
+
* total number of empty lines
|
60
|
+
"""
|
61
|
+
|
62
|
+
__implements__ = (IRawChecker,)
|
63
|
+
|
64
|
+
# configuration section name
|
65
|
+
name = 'metrics'
|
66
|
+
# configuration options
|
67
|
+
options = ( )
|
68
|
+
# messages
|
69
|
+
msgs = {}
|
70
|
+
# reports
|
71
|
+
reports = ( ('RP0701', 'Raw metrics', report_raw_stats), )
|
72
|
+
|
73
|
+
def __init__(self, linter):
|
74
|
+
BaseRawChecker.__init__(self, linter)
|
75
|
+
self.stats = None
|
76
|
+
|
77
|
+
def open(self):
|
78
|
+
"""init statistics"""
|
79
|
+
self.stats = self.linter.add_stats(total_lines=0, code_lines=0,
|
80
|
+
empty_lines=0, docstring_lines=0,
|
81
|
+
comment_lines=0)
|
82
|
+
|
83
|
+
def process_tokens(self, tokens):
|
84
|
+
"""update stats"""
|
85
|
+
i = 0
|
86
|
+
tokens = list(tokens)
|
87
|
+
while i < len(tokens):
|
88
|
+
i, lines_number, line_type = get_type(tokens, i)
|
89
|
+
self.stats['total_lines'] += lines_number
|
90
|
+
self.stats[line_type] += lines_number
|
91
|
+
|
92
|
+
|
93
|
+
JUNK = (tokenize.NL, tokenize.INDENT, tokenize.NEWLINE, tokenize.ENDMARKER)
|
94
|
+
|
95
|
+
def get_type(tokens, start_index):
|
96
|
+
"""return the line type : docstring, comment, code, empty"""
|
97
|
+
i = start_index
|
98
|
+
tok_type = tokens[i][0]
|
99
|
+
start = tokens[i][2]
|
100
|
+
pos = start
|
101
|
+
line_type = None
|
102
|
+
while i < len(tokens) and tokens[i][2][0] == start[0]:
|
103
|
+
tok_type = tokens[i][0]
|
104
|
+
pos = tokens[i][3]
|
105
|
+
if line_type is None:
|
106
|
+
if tok_type == tokenize.STRING:
|
107
|
+
line_type = 'docstring_lines'
|
108
|
+
elif tok_type == tokenize.COMMENT:
|
109
|
+
line_type = 'comment_lines'
|
110
|
+
elif tok_type in JUNK:
|
111
|
+
pass
|
112
|
+
else:
|
113
|
+
line_type = 'code_lines'
|
114
|
+
i += 1
|
115
|
+
if line_type is None:
|
116
|
+
line_type = 'empty_lines'
|
117
|
+
elif i < len(tokens) and tok_type == tokenize.NEWLINE:
|
118
|
+
i += 1
|
119
|
+
return i, pos[0] - start[0] + 1, line_type
|
120
|
+
|
121
|
+
|
122
|
+
def register(linter):
|
123
|
+
""" required method to auto register this checker """
|
124
|
+
linter.register_checker(RawMetricsChecker(linter))
|
125
|
+
|
@@ -0,0 +1,333 @@
|
|
1
|
+
# pylint: disable=W0622
|
2
|
+
# Copyright (c) 2004-2006 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
|
+
# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
17
|
+
"""a similarities / code duplication command line tool and pylint checker
|
18
|
+
"""
|
19
|
+
from __future__ import generators
|
20
|
+
|
21
|
+
import sys
|
22
|
+
|
23
|
+
from logilab.common.compat import set, izip, sum, enumerate
|
24
|
+
from logilab.common.ureports import Table
|
25
|
+
|
26
|
+
from pylint.interfaces import IRawChecker
|
27
|
+
from pylint.checkers import BaseChecker, table_lines_from_stats
|
28
|
+
|
29
|
+
|
30
|
+
class Similar:
|
31
|
+
"""finds copy-pasted lines of code in a project"""
|
32
|
+
|
33
|
+
def __init__(self, min_lines=4, ignore_comments=False,
|
34
|
+
ignore_docstrings=False):
|
35
|
+
self.min_lines = min_lines
|
36
|
+
self.ignore_comments = ignore_comments
|
37
|
+
self.ignore_docstrings = ignore_docstrings
|
38
|
+
self.linesets = []
|
39
|
+
|
40
|
+
def append_stream(self, streamid, stream):
|
41
|
+
"""append a file to search for similarities"""
|
42
|
+
self.linesets.append(LineSet(streamid,
|
43
|
+
stream.readlines(),
|
44
|
+
self.ignore_comments,
|
45
|
+
self.ignore_docstrings))
|
46
|
+
|
47
|
+
def run(self):
|
48
|
+
"""start looking for similarities and display results on stdout"""
|
49
|
+
self._display_sims(self._compute_sims())
|
50
|
+
|
51
|
+
def _compute_sims(self):
|
52
|
+
"""compute similarities in appended files"""
|
53
|
+
no_duplicates = {}
|
54
|
+
for num, lineset1, idx1, lineset2, idx2 in self._iter_sims():
|
55
|
+
duplicate = no_duplicates.setdefault(num, [])
|
56
|
+
for couples in duplicate:
|
57
|
+
if (lineset1, idx1) in couples or (lineset2, idx2) in couples:
|
58
|
+
couples.add( (lineset1, idx1) )
|
59
|
+
couples.add( (lineset2, idx2) )
|
60
|
+
break
|
61
|
+
else:
|
62
|
+
duplicate.append( set([(lineset1, idx1), (lineset2, idx2)]) )
|
63
|
+
sims = []
|
64
|
+
for num, ensembles in no_duplicates.iteritems():
|
65
|
+
for couples in ensembles:
|
66
|
+
sims.append( (num, couples) )
|
67
|
+
sims.sort()
|
68
|
+
sims.reverse()
|
69
|
+
return sims
|
70
|
+
|
71
|
+
def _display_sims(self, sims):
|
72
|
+
"""display computed similarities on stdout"""
|
73
|
+
nb_lignes_dupliquees = 0
|
74
|
+
for num, couples in sims:
|
75
|
+
print
|
76
|
+
print num, "similar lines in", len(couples), "files"
|
77
|
+
couples = list(couples)
|
78
|
+
couples.sort()
|
79
|
+
for lineset, idx in couples:
|
80
|
+
print "==%s:%s" % (lineset.name, idx)
|
81
|
+
# pylint: disable=W0631
|
82
|
+
for line in lineset._real_lines[idx:idx+num]:
|
83
|
+
print " ", line,
|
84
|
+
nb_lignes_dupliquees += num * (len(couples)-1)
|
85
|
+
nb_total_lignes = sum([len(lineset) for lineset in self.linesets])
|
86
|
+
print "TOTAL lines=%s duplicates=%s percent=%s" \
|
87
|
+
% (nb_total_lignes, nb_lignes_dupliquees,
|
88
|
+
nb_lignes_dupliquees*1. / nb_total_lignes)
|
89
|
+
|
90
|
+
def _find_common(self, lineset1, lineset2):
|
91
|
+
"""find similarities in the two given linesets"""
|
92
|
+
lines1 = lineset1.enumerate_stripped
|
93
|
+
lines2 = lineset2.enumerate_stripped
|
94
|
+
find = lineset2.find
|
95
|
+
index1 = 0
|
96
|
+
min_lines = self.min_lines
|
97
|
+
while index1 < len(lineset1):
|
98
|
+
skip = 1
|
99
|
+
num = 0
|
100
|
+
for index2 in find( lineset1[index1] ):
|
101
|
+
non_blank = 0
|
102
|
+
for num, ((_, line1), (_, line2)) in enumerate(
|
103
|
+
izip(lines1(index1), lines2(index2))):
|
104
|
+
if line1 != line2:
|
105
|
+
if non_blank > min_lines:
|
106
|
+
yield num, lineset1, index1, lineset2, index2
|
107
|
+
skip = max(skip, num)
|
108
|
+
break
|
109
|
+
if line1:
|
110
|
+
non_blank += 1
|
111
|
+
else:
|
112
|
+
# we may have reach the end
|
113
|
+
num += 1
|
114
|
+
if non_blank > min_lines:
|
115
|
+
yield num, lineset1, index1, lineset2, index2
|
116
|
+
skip = max(skip, num)
|
117
|
+
index1 += skip
|
118
|
+
|
119
|
+
def _iter_sims(self):
|
120
|
+
"""iterate on similarities among all files, by making a cartesian
|
121
|
+
product
|
122
|
+
"""
|
123
|
+
for idx, lineset in enumerate(self.linesets[:-1]):
|
124
|
+
for lineset2 in self.linesets[idx+1:]:
|
125
|
+
for sim in self._find_common(lineset, lineset2):
|
126
|
+
yield sim
|
127
|
+
|
128
|
+
def stripped_lines(lines, ignore_comments, ignore_docstrings):
|
129
|
+
strippedlines = []
|
130
|
+
docstring = None
|
131
|
+
for line in lines:
|
132
|
+
line = line.strip()
|
133
|
+
if ignore_docstrings:
|
134
|
+
if not docstring and \
|
135
|
+
(line.startswith('"""') or line.startswith("'''")):
|
136
|
+
docstring = line[:3]
|
137
|
+
line = line[3:]
|
138
|
+
if docstring:
|
139
|
+
if line.endswith(docstring):
|
140
|
+
docstring = None
|
141
|
+
line = ''
|
142
|
+
# XXX cut when a line begins with code but end with a comment
|
143
|
+
if ignore_comments and line.startswith('#'):
|
144
|
+
line = ''
|
145
|
+
strippedlines.append(line)
|
146
|
+
return strippedlines
|
147
|
+
|
148
|
+
class LineSet:
|
149
|
+
"""Holds and indexes all the lines of a single source file"""
|
150
|
+
def __init__(self, name, lines, ignore_comments=False,
|
151
|
+
ignore_docstrings=False):
|
152
|
+
self.name = name
|
153
|
+
self._real_lines = lines
|
154
|
+
self._stripped_lines = stripped_lines(lines, ignore_comments,
|
155
|
+
ignore_docstrings)
|
156
|
+
self._index = self._mk_index()
|
157
|
+
|
158
|
+
def __str__(self):
|
159
|
+
return '<Lineset for %s>' % self.name
|
160
|
+
|
161
|
+
def __len__(self):
|
162
|
+
return len(self._real_lines)
|
163
|
+
|
164
|
+
def __getitem__(self, index):
|
165
|
+
return self._stripped_lines[index]
|
166
|
+
|
167
|
+
def __cmp__(self, other):
|
168
|
+
return cmp(self.name, other.name)
|
169
|
+
|
170
|
+
def __hash__(self):
|
171
|
+
return id(self)
|
172
|
+
|
173
|
+
def enumerate_stripped(self, start_at=0):
|
174
|
+
"""return an iterator on stripped lines, starting from a given index
|
175
|
+
if specified, else 0
|
176
|
+
"""
|
177
|
+
idx = start_at
|
178
|
+
if start_at:
|
179
|
+
lines = self._stripped_lines[start_at:]
|
180
|
+
else:
|
181
|
+
lines = self._stripped_lines
|
182
|
+
for line in lines:
|
183
|
+
#if line:
|
184
|
+
yield idx, line
|
185
|
+
idx += 1
|
186
|
+
|
187
|
+
def find(self, stripped_line):
|
188
|
+
"""return positions of the given stripped line in this set"""
|
189
|
+
return self._index.get(stripped_line, ())
|
190
|
+
|
191
|
+
def _mk_index(self):
|
192
|
+
"""create the index for this set"""
|
193
|
+
index = {}
|
194
|
+
for line_no, line in enumerate(self._stripped_lines):
|
195
|
+
if line:
|
196
|
+
index.setdefault(line, []).append( line_no )
|
197
|
+
return index
|
198
|
+
|
199
|
+
|
200
|
+
MSGS = {'R0801': ('Similar lines in %s files\n%s',
|
201
|
+
'Indicates that a set of similar lines has been detected \
|
202
|
+
among multiple file. This usually means that the code should \
|
203
|
+
be refactored to avoid this duplication.')}
|
204
|
+
|
205
|
+
def report_similarities(sect, stats, old_stats):
|
206
|
+
"""make a layout with some stats about duplication"""
|
207
|
+
lines = ['', 'now', 'previous', 'difference']
|
208
|
+
lines += table_lines_from_stats(stats, old_stats,
|
209
|
+
('nb_duplicated_lines',
|
210
|
+
'percent_duplicated_lines'))
|
211
|
+
sect.append(Table(children=lines, cols=4, rheaders=1, cheaders=1))
|
212
|
+
|
213
|
+
|
214
|
+
# wrapper to get a pylint checker from the similar class
|
215
|
+
class SimilarChecker(BaseChecker, Similar):
|
216
|
+
"""checks for similarities and duplicated code. This computation may be
|
217
|
+
memory / CPU intensive, so you should disable it if you experiments some
|
218
|
+
problems.
|
219
|
+
"""
|
220
|
+
|
221
|
+
__implements__ = (IRawChecker,)
|
222
|
+
# configuration section name
|
223
|
+
name = 'similarities'
|
224
|
+
# messages
|
225
|
+
msgs = MSGS
|
226
|
+
# configuration options
|
227
|
+
# for available dict keys/values see the optik parser 'add_option' method
|
228
|
+
options = (('min-similarity-lines',
|
229
|
+
{'default' : 4, 'type' : "int", 'metavar' : '<int>',
|
230
|
+
'help' : 'Minimum lines number of a similarity.'}),
|
231
|
+
('ignore-comments',
|
232
|
+
{'default' : True, 'type' : 'yn', 'metavar' : '<y or n>',
|
233
|
+
'help': 'Ignore comments when computing similarities.'}
|
234
|
+
),
|
235
|
+
('ignore-docstrings',
|
236
|
+
{'default' : True, 'type' : 'yn', 'metavar' : '<y or n>',
|
237
|
+
'help': 'Ignore docstrings when computing similarities.'}
|
238
|
+
),
|
239
|
+
)
|
240
|
+
# reports
|
241
|
+
reports = ( ('R0801', 'Duplication', report_similarities), ) # XXX actually a Refactoring message
|
242
|
+
|
243
|
+
def __init__(self, linter=None):
|
244
|
+
BaseChecker.__init__(self, linter)
|
245
|
+
Similar.__init__(self, min_lines=4,
|
246
|
+
ignore_comments=True, ignore_docstrings=True)
|
247
|
+
self.stats = None
|
248
|
+
|
249
|
+
def set_option(self, optname, value, action=None, optdict=None):
|
250
|
+
"""method called to set an option (registered in the options list)
|
251
|
+
|
252
|
+
overridden to report options setting to Similar
|
253
|
+
"""
|
254
|
+
BaseChecker.set_option(self, optname, value, action, optdict)
|
255
|
+
if optname == 'min-similarity-lines':
|
256
|
+
self.min_lines = self.config.min_similarity_lines
|
257
|
+
elif optname == 'ignore-comments':
|
258
|
+
self.ignore_comments = self.config.ignore_comments
|
259
|
+
elif optname == 'ignore-docstrings':
|
260
|
+
self.ignore_docstrings = self.config.ignore_docstrings
|
261
|
+
|
262
|
+
def open(self):
|
263
|
+
"""init the checkers: reset linesets and statistics information"""
|
264
|
+
self.linesets = []
|
265
|
+
self.stats = self.linter.add_stats(nb_duplicated_lines=0,
|
266
|
+
percent_duplicated_lines=0)
|
267
|
+
|
268
|
+
def process_module(self, stream):
|
269
|
+
"""process a module
|
270
|
+
|
271
|
+
the module's content is accessible via the stream object
|
272
|
+
|
273
|
+
stream must implements the readlines method
|
274
|
+
"""
|
275
|
+
self.append_stream(self.linter.current_name, stream)
|
276
|
+
|
277
|
+
def close(self):
|
278
|
+
"""compute and display similarities on closing (i.e. end of parsing)"""
|
279
|
+
total = sum([len(lineset) for lineset in self.linesets])
|
280
|
+
duplicated = 0
|
281
|
+
stats = self.stats
|
282
|
+
for num, couples in self._compute_sims():
|
283
|
+
msg = []
|
284
|
+
for lineset, idx in couples:
|
285
|
+
msg.append("==%s:%s" % (lineset.name, idx))
|
286
|
+
msg.sort()
|
287
|
+
# pylint: disable=W0631
|
288
|
+
for line in lineset._real_lines[idx:idx+num]:
|
289
|
+
msg.append(line.rstrip())
|
290
|
+
self.add_message('R0801', args=(len(couples), '\n'.join(msg)))
|
291
|
+
duplicated += num * (len(couples) - 1)
|
292
|
+
stats['nb_duplicated_lines'] = duplicated
|
293
|
+
stats['percent_duplicated_lines'] = total and duplicated * 100. / total
|
294
|
+
|
295
|
+
|
296
|
+
def register(linter):
|
297
|
+
"""required method to auto register this checker """
|
298
|
+
linter.register_checker(SimilarChecker(linter))
|
299
|
+
|
300
|
+
def usage(status=0):
|
301
|
+
"""display command line usage information"""
|
302
|
+
print "finds copy pasted blocks in a set of files"
|
303
|
+
print
|
304
|
+
print 'Usage: similar [-d|--duplicates min_duplicated_lines] \
|
305
|
+
[--ignore-comments] file1...'
|
306
|
+
sys.exit(status)
|
307
|
+
|
308
|
+
def run(argv=None):
|
309
|
+
"""standalone command line access point"""
|
310
|
+
if argv is None:
|
311
|
+
argv = sys.argv[1:]
|
312
|
+
from getopt import getopt
|
313
|
+
s_opts = 'hd:'
|
314
|
+
l_opts = ('help', 'duplicates=', 'ignore-comments')
|
315
|
+
min_lines = 4
|
316
|
+
ignore_comments = False
|
317
|
+
opts, args = getopt(argv, s_opts, l_opts)
|
318
|
+
for opt, val in opts:
|
319
|
+
if opt in ('-d', '--duplicates'):
|
320
|
+
min_lines = int(val)
|
321
|
+
elif opt in ('-h', '--help'):
|
322
|
+
usage()
|
323
|
+
elif opt == '--ignore-comments':
|
324
|
+
ignore_comments = True
|
325
|
+
if not args:
|
326
|
+
usage(1)
|
327
|
+
sim = Similar(min_lines, ignore_comments)
|
328
|
+
for filename in args:
|
329
|
+
sim.append_stream(filename, open(filename))
|
330
|
+
sim.run()
|
331
|
+
|
332
|
+
if __name__ == '__main__':
|
333
|
+
run()
|