bee_python 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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,1969 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
|
3
|
+
# Copyright (c) 2001-2006, MetaSlash Inc. All rights reserved.
|
4
|
+
# Portions Copyright (c) 2005, Google, Inc. All rights reserved.
|
5
|
+
|
6
|
+
"""
|
7
|
+
Find warnings in byte code from Python source files.
|
8
|
+
"""
|
9
|
+
|
10
|
+
import string
|
11
|
+
import types
|
12
|
+
|
13
|
+
from pychecker import msgs
|
14
|
+
from pychecker import utils
|
15
|
+
from pychecker import Warning
|
16
|
+
from pychecker import OP
|
17
|
+
from pychecker import Stack
|
18
|
+
from pychecker import python
|
19
|
+
|
20
|
+
__pychecker__ = 'no-argsused'
|
21
|
+
|
22
|
+
|
23
|
+
def cfg() :
|
24
|
+
return utils.cfg()
|
25
|
+
|
26
|
+
def getFunctionArgErr(func_name, argCount, minArgs, maxArgs):
|
27
|
+
err = None
|
28
|
+
if maxArgs == None:
|
29
|
+
if argCount < minArgs :
|
30
|
+
err = msgs.INVALID_ARG_COUNT2 % (func_name, argCount, minArgs)
|
31
|
+
elif argCount < minArgs or argCount > maxArgs:
|
32
|
+
if minArgs == maxArgs:
|
33
|
+
err = msgs.INVALID_ARG_COUNT1 % (func_name, argCount, minArgs)
|
34
|
+
else:
|
35
|
+
err = msgs.INVALID_ARG_COUNT3 % (func_name, argCount, minArgs, maxArgs)
|
36
|
+
return err
|
37
|
+
|
38
|
+
def _checkFunctionArgCount(code, func_name, argCount, minArgs, maxArgs,
|
39
|
+
objectReference = 0) :
|
40
|
+
# there is an implied argument for object creation and self.xxx()
|
41
|
+
if objectReference :
|
42
|
+
minArgs = minArgs - 1
|
43
|
+
if maxArgs is not None :
|
44
|
+
maxArgs = maxArgs - 1
|
45
|
+
|
46
|
+
err = getFunctionArgErr(func_name, argCount, minArgs, maxArgs)
|
47
|
+
if err :
|
48
|
+
code.addWarning(err)
|
49
|
+
|
50
|
+
def _checkFunctionArgs(code, func, objectReference, argCount, kwArgs,
|
51
|
+
check_arg_count = 1) :
|
52
|
+
func_name = func.function.func_code.co_name
|
53
|
+
if kwArgs :
|
54
|
+
args_len = func.function.func_code.co_argcount
|
55
|
+
arg_names = func.function.func_code.co_varnames[argCount:args_len]
|
56
|
+
if argCount < args_len and kwArgs[0] in arg_names:
|
57
|
+
if cfg().namedArgs :
|
58
|
+
code.addWarning(msgs.FUNC_USES_NAMED_ARGS % func_name)
|
59
|
+
|
60
|
+
# convert the named args into regular params, and really check
|
61
|
+
while argCount < args_len and kwArgs and kwArgs[0] in arg_names:
|
62
|
+
argCount = argCount + 1
|
63
|
+
kwArgs = kwArgs[1:]
|
64
|
+
_checkFunctionArgs(code, func, objectReference, argCount, kwArgs,
|
65
|
+
check_arg_count)
|
66
|
+
return
|
67
|
+
|
68
|
+
if not func.supportsKW :
|
69
|
+
code.addWarning(msgs.FUNC_DOESNT_SUPPORT_KW % func_name)
|
70
|
+
|
71
|
+
if check_arg_count :
|
72
|
+
_checkFunctionArgCount(code, func_name, argCount,
|
73
|
+
func.minArgs, func.maxArgs, objectReference)
|
74
|
+
|
75
|
+
def _getReferenceFromModule(module, identifier) :
|
76
|
+
func = module.functions.get(identifier, None)
|
77
|
+
if func is not None :
|
78
|
+
return func, None, 0
|
79
|
+
|
80
|
+
create = 0
|
81
|
+
c = module.classes.get(identifier, None)
|
82
|
+
if c is not None :
|
83
|
+
func = c.methods.get(utils.INIT, None)
|
84
|
+
create = 1
|
85
|
+
return func, c, create
|
86
|
+
|
87
|
+
def _getFunction(module, stackValue) :
|
88
|
+
'Return (function, class) from the stack value'
|
89
|
+
|
90
|
+
identifier = stackValue.data
|
91
|
+
if type(identifier) == types.StringType :
|
92
|
+
return _getReferenceFromModule(module, identifier)
|
93
|
+
|
94
|
+
# find the module this references
|
95
|
+
i, maxLen = 0, len(identifier)
|
96
|
+
while i < maxLen :
|
97
|
+
id = utils.safestr(identifier[i])
|
98
|
+
if module.classes.has_key(id) or module.functions.has_key(id) :
|
99
|
+
break
|
100
|
+
refModule = module.modules.get(id, None)
|
101
|
+
if refModule is not None :
|
102
|
+
module = refModule
|
103
|
+
else :
|
104
|
+
return None, None, 0
|
105
|
+
i = i + 1
|
106
|
+
|
107
|
+
# if we got to the end, there is only modules, nothing we can do
|
108
|
+
# we also can't handle if there is more than 2 items left
|
109
|
+
if i >= maxLen or (i+2) < maxLen :
|
110
|
+
return None, None, 0
|
111
|
+
|
112
|
+
if (i+1) == maxLen :
|
113
|
+
return _getReferenceFromModule(module, identifier[-1])
|
114
|
+
|
115
|
+
# we can't handle self.x.y
|
116
|
+
if (i+2) == maxLen and identifier[0] == cfg().methodArgName:
|
117
|
+
return None, None, 0
|
118
|
+
|
119
|
+
c = module.classes.get(identifier[-2], None)
|
120
|
+
if c is None :
|
121
|
+
return None, None, 0
|
122
|
+
return c.methods.get(identifier[-1], None), c, 0
|
123
|
+
|
124
|
+
def _validateKwArgs(code, info, func_name, kwArgs):
|
125
|
+
if len(info) < 4:
|
126
|
+
code.addWarning(msgs.FUNC_DOESNT_SUPPORT_KW % func_name)
|
127
|
+
elif not info[3]:
|
128
|
+
return
|
129
|
+
|
130
|
+
try:
|
131
|
+
# info could be from a builtin method which means that
|
132
|
+
# info[3] is not a list.
|
133
|
+
dummy = info[3][0]
|
134
|
+
except IndexError:
|
135
|
+
return
|
136
|
+
|
137
|
+
for arg in kwArgs:
|
138
|
+
if arg not in info[3]:
|
139
|
+
code.addWarning(msgs.FUNC_DOESNT_SUPPORT_KW_ARG % (func_name, arg))
|
140
|
+
|
141
|
+
def _checkBuiltin(code, loadValue, argCount, kwArgs, check_arg_count = 1) :
|
142
|
+
returnValue = Stack.makeFuncReturnValue(loadValue, argCount)
|
143
|
+
func_name = loadValue.data
|
144
|
+
if loadValue.type == Stack.TYPE_GLOBAL :
|
145
|
+
info = python.GLOBAL_FUNC_INFO.get(func_name, None)
|
146
|
+
if info is not None :
|
147
|
+
if func_name == 'input' and cfg().usesInput:
|
148
|
+
code.addWarning(msgs.USES_INPUT)
|
149
|
+
if cfg().constAttr and \
|
150
|
+
((func_name == 'setattr' and argCount >= 2) or
|
151
|
+
(func_name == 'getattr' and argCount == 2)):
|
152
|
+
arg2 = code.stack[-argCount + 1]
|
153
|
+
if arg2.const:
|
154
|
+
# lambda with setattr and const is a common way of setting
|
155
|
+
# attributes, so allow it
|
156
|
+
if code.func.function.func_name != '<lambda>':
|
157
|
+
code.addWarning(msgs.USES_CONST_ATTR % func_name)
|
158
|
+
|
159
|
+
if kwArgs:
|
160
|
+
_validateKwArgs(code, info, func_name, kwArgs)
|
161
|
+
elif check_arg_count :
|
162
|
+
_checkFunctionArgCount(code, func_name, argCount,
|
163
|
+
info[1], info[2])
|
164
|
+
returnValue = Stack.Item(returnValue.data, info[0])
|
165
|
+
returnValue.setStringType(info[0])
|
166
|
+
elif type(func_name) == types.TupleType and len(func_name) <= 2 :
|
167
|
+
objType = code.typeMap.get(utils.safestr(func_name[0]), [])
|
168
|
+
if types.ListType in objType :
|
169
|
+
try :
|
170
|
+
if func_name[1] == 'append' and argCount > 1 :
|
171
|
+
code.addWarning(msgs.LIST_APPEND_ARGS % func_name[0])
|
172
|
+
check_arg_count = 0
|
173
|
+
except AttributeError :
|
174
|
+
# FIXME: why do we need to catch AttributeError???
|
175
|
+
pass
|
176
|
+
if len(objType) == 1 :
|
177
|
+
# if it's a builtin, check method
|
178
|
+
builtinType = python.BUILTIN_METHODS.get(objType[0])
|
179
|
+
if builtinType is not None :
|
180
|
+
methodInfo = builtinType.get(func_name[1])
|
181
|
+
# set func properly
|
182
|
+
if kwArgs :
|
183
|
+
_validateKwArgs(code, methodInfo, func_name[1], kwArgs)
|
184
|
+
elif methodInfo :
|
185
|
+
returnValue = Stack.Item(func_name[1], methodInfo[0])
|
186
|
+
returnValue.setStringType(methodInfo[0])
|
187
|
+
if check_arg_count and methodInfo is not None :
|
188
|
+
_checkFunctionArgCount(code, func_name[1], argCount,
|
189
|
+
methodInfo[1], methodInfo[2])
|
190
|
+
|
191
|
+
return returnValue
|
192
|
+
|
193
|
+
_IMMUTABLE_LIST_METHODS = ('count', 'index',)
|
194
|
+
_IMMUTABLE_DICT_METHODS = ('copy', 'get', 'has_key',
|
195
|
+
'items', 'keys', 'values',
|
196
|
+
'iteritems', 'iterkeys', 'itervalues')
|
197
|
+
|
198
|
+
def _checkModifyDefaultArg(code, objectName, methodName=None) :
|
199
|
+
try :
|
200
|
+
value = code.func.defaultValue(objectName)
|
201
|
+
objectType = type(value)
|
202
|
+
if objectType in python.MUTABLE_TYPES :
|
203
|
+
if objectType == types.DictType and \
|
204
|
+
methodName in _IMMUTABLE_DICT_METHODS :
|
205
|
+
return
|
206
|
+
if objectType == types.ListType and \
|
207
|
+
methodName in _IMMUTABLE_LIST_METHODS :
|
208
|
+
return
|
209
|
+
code.addWarning(msgs.MODIFYING_DEFAULT_ARG % objectName)
|
210
|
+
except ValueError :
|
211
|
+
pass
|
212
|
+
|
213
|
+
def _isexception(object) :
|
214
|
+
# FIXME: i have no idea why this function is necessary
|
215
|
+
# it seems that the issubclass() should work, but it doesn't always
|
216
|
+
|
217
|
+
if hasattr(object, 'type'):
|
218
|
+
if object.type == types.TupleType:
|
219
|
+
# if we have a tuple, we can't check the contents (not enough info)
|
220
|
+
## for item in object.value:
|
221
|
+
## if not _isexception(item):
|
222
|
+
## return 0
|
223
|
+
return 1
|
224
|
+
|
225
|
+
try:
|
226
|
+
# try/except is necessary for globals like NotImplemented
|
227
|
+
if issubclass(object, Exception) :
|
228
|
+
return 1
|
229
|
+
# Python 2.5 added a BaseException to the hierarchy. That's
|
230
|
+
# really what we need to check if it exists.
|
231
|
+
if utils.pythonVersion() >= utils.PYTHON_2_5:
|
232
|
+
if issubclass(object, BaseException):
|
233
|
+
return 1
|
234
|
+
except TypeError:
|
235
|
+
return 0
|
236
|
+
|
237
|
+
for c in object.__bases__ :
|
238
|
+
if utils.startswith(utils.safestr(c), 'exceptions.') :
|
239
|
+
return 1
|
240
|
+
if len(c.__bases__) > 0 and _isexception(c) :
|
241
|
+
return 1
|
242
|
+
return 0
|
243
|
+
|
244
|
+
def _checkStringFind(code, loadValue):
|
245
|
+
if len(loadValue.data) == 2 and loadValue.data[1] == 'find':
|
246
|
+
try:
|
247
|
+
if types.StringType in code.typeMap.get(loadValue.data[0], []):
|
248
|
+
op = code.nextOpInfo()[0]
|
249
|
+
if OP.IS_CONDITIONAL_JUMP(op) or OP.IS_NOT(op):
|
250
|
+
code.addWarning(msgs.BAD_STRING_FIND)
|
251
|
+
except TypeError:
|
252
|
+
# we don't care if loadValue.data[0] is not hashable
|
253
|
+
pass
|
254
|
+
|
255
|
+
def _checkAbstract(refClass, code, name):
|
256
|
+
name_list = refClass.isAbstract()
|
257
|
+
if name_list:
|
258
|
+
name_list.sort()
|
259
|
+
names = string.join(name_list, ", ")
|
260
|
+
code.addWarning(msgs.METHODS_NEED_OVERRIDE % (names, name))
|
261
|
+
|
262
|
+
_SEQUENCE_TYPES = (types.TupleType, types.ListType, types.StringType)
|
263
|
+
try: _SEQUENCE_TYPES = _SEQUENCE_TYPES + (types.UnicodeType,)
|
264
|
+
except AttributeError: pass
|
265
|
+
|
266
|
+
# FIXME: this is not complete. errors will be caught only sometimes,
|
267
|
+
# depending on the order the functions/methods are processed
|
268
|
+
# in the dict. Need to be able to run through all functions
|
269
|
+
# twice, but because the code sucks, this is not possible.
|
270
|
+
def _checkReturnValueUse(code, func):
|
271
|
+
if func.returnValues is None:
|
272
|
+
return
|
273
|
+
|
274
|
+
err = None
|
275
|
+
opInfo = code.nextOpInfo()
|
276
|
+
if func.returnsNoValue():
|
277
|
+
# make sure we really know how to check for all the return types
|
278
|
+
for rv in func.returnValues:
|
279
|
+
if rv[1].type in _UNCHECKABLE_STACK_TYPES:
|
280
|
+
return
|
281
|
+
|
282
|
+
if not OP.POP_TOP(opInfo[0]):
|
283
|
+
err = msgs.USING_NONE_RETURN_VALUE % utils.safestr(func)
|
284
|
+
elif OP.UNPACK_SEQUENCE(opInfo[0]):
|
285
|
+
# verify unpacking into proper # of vars
|
286
|
+
varCount = opInfo[1]
|
287
|
+
stackRV = func.returnValues[0][1]
|
288
|
+
returnType = stackRV.getType({})
|
289
|
+
funcCount = stackRV.length
|
290
|
+
if returnType in _SEQUENCE_TYPES:
|
291
|
+
if varCount != funcCount and funcCount > 0:
|
292
|
+
err = msgs.WRONG_UNPACK_FUNCTION % (utils.safestr(func), funcCount, varCount)
|
293
|
+
elif returnType not in _UNCHECKABLE_STACK_TYPES:
|
294
|
+
err = msgs.UNPACK_NON_SEQUENCE % (utils.safestr(func), _getTypeStr(returnType))
|
295
|
+
if err:
|
296
|
+
code.addWarning(err)
|
297
|
+
|
298
|
+
def _handleFunctionCall(codeSource, code, argCount, indexOffset = 0,
|
299
|
+
check_arg_count = 1) :
|
300
|
+
'Checks for warnings, returns function called (may be None)'
|
301
|
+
|
302
|
+
if not code.stack :
|
303
|
+
return
|
304
|
+
|
305
|
+
kwArgCount = argCount >> utils.VAR_ARGS_BITS
|
306
|
+
argCount = argCount & utils.MAX_ARGS_MASK
|
307
|
+
|
308
|
+
# function call on stack is before the args, and keyword args
|
309
|
+
funcIndex = argCount + 2 * kwArgCount + 1 + indexOffset
|
310
|
+
if funcIndex > len(code.stack) :
|
311
|
+
funcIndex = 0
|
312
|
+
# to find on stack, we have to look backwards from top of stack (end)
|
313
|
+
funcIndex = -funcIndex
|
314
|
+
|
315
|
+
# store the keyword names/keys to check if using named arguments
|
316
|
+
kwArgs = []
|
317
|
+
if kwArgCount > 0 :
|
318
|
+
# loop backwards by 2 (keyword, value) in stack to find keyword args
|
319
|
+
for i in range(-2 - indexOffset, (-2 * kwArgCount - 1), -2) :
|
320
|
+
kwArgs.append(code.stack[i].data)
|
321
|
+
kwArgs.reverse()
|
322
|
+
|
323
|
+
loadValue = code.stack[funcIndex]
|
324
|
+
funcName = loadValue.getName()
|
325
|
+
returnValue = Stack.makeFuncReturnValue(loadValue, argCount)
|
326
|
+
|
327
|
+
if loadValue.isMethodCall(codeSource.classObject, cfg().methodArgName):
|
328
|
+
methodName = loadValue.data[1]
|
329
|
+
try :
|
330
|
+
m = codeSource.classObject.methods[methodName]
|
331
|
+
if m != None :
|
332
|
+
objRef = not m.isStaticMethod()
|
333
|
+
_checkFunctionArgs(code, m, objRef, argCount, kwArgs,
|
334
|
+
check_arg_count)
|
335
|
+
except KeyError :
|
336
|
+
sattr = codeSource.classObject.statics.get(methodName)
|
337
|
+
if sattr is not None :
|
338
|
+
funcName = sattr.getName()
|
339
|
+
|
340
|
+
if sattr is None and cfg().callingAttribute :
|
341
|
+
code.addWarning(msgs.INVALID_METHOD % methodName)
|
342
|
+
|
343
|
+
elif loadValue.type in (Stack.TYPE_ATTRIBUTE, Stack.TYPE_GLOBAL) and \
|
344
|
+
type(loadValue.data) in (types.StringType, types.TupleType) :
|
345
|
+
# apply(func, (args)), can't check # of args, so just return func
|
346
|
+
if loadValue.data == 'apply' :
|
347
|
+
loadValue = code.stack[funcIndex+1]
|
348
|
+
funcName = loadValue.getName()
|
349
|
+
else :
|
350
|
+
if cfg().modifyDefaultValue and \
|
351
|
+
type(loadValue.data) == types.TupleType :
|
352
|
+
_checkModifyDefaultArg(code, loadValue.data[0],
|
353
|
+
loadValue.data[1])
|
354
|
+
|
355
|
+
func, refClass, method = _getFunction(codeSource.module, loadValue)
|
356
|
+
if func == None and type(loadValue.data) == types.TupleType and \
|
357
|
+
len(loadValue.data) == 2 :
|
358
|
+
# looks like we are making a method call
|
359
|
+
data = loadValue.data
|
360
|
+
if type(data[0]) == types.StringType :
|
361
|
+
# do we know the type of the local variable?
|
362
|
+
varType = code.typeMap.get(data[0])
|
363
|
+
if varType is not None and len(varType) == 1 :
|
364
|
+
if hasattr(varType[0], 'methods') :
|
365
|
+
# it's a class & we know the type, get the method
|
366
|
+
func = varType[0].methods.get(data[1])
|
367
|
+
if func is not None :
|
368
|
+
method = 1
|
369
|
+
|
370
|
+
if cfg().abstractClasses and refClass and method:
|
371
|
+
_checkAbstract(refClass, code, funcName)
|
372
|
+
|
373
|
+
if cfg().stringFind:
|
374
|
+
_checkStringFind(code, loadValue)
|
375
|
+
|
376
|
+
if func != None :
|
377
|
+
if refClass and func.isClassMethod():
|
378
|
+
argCount = argCount + 1
|
379
|
+
_checkFunctionArgs(code, func, method, argCount, kwArgs,
|
380
|
+
check_arg_count)
|
381
|
+
# if this isn't a c'tor, we should check
|
382
|
+
if not (refClass and method) and cfg().checkReturnValues:
|
383
|
+
_checkReturnValueUse(code, func)
|
384
|
+
|
385
|
+
if refClass :
|
386
|
+
if method :
|
387
|
+
# c'tor, return the class as the type
|
388
|
+
returnValue = Stack.Item(loadValue, refClass)
|
389
|
+
elif func.isClassMethod():
|
390
|
+
# FIXME: do anything here?
|
391
|
+
pass
|
392
|
+
elif argCount > 0 and cfg().methodArgName and \
|
393
|
+
not func.isStaticMethod() and \
|
394
|
+
code.stack[funcIndex].type == Stack.TYPE_ATTRIBUTE and \
|
395
|
+
code.stack[funcIndex+1].data != cfg().methodArgName:
|
396
|
+
e = msgs.SELF_NOT_FIRST_ARG % (cfg().methodArgName, '')
|
397
|
+
code.addWarning(e)
|
398
|
+
elif refClass and method :
|
399
|
+
returnValue = Stack.Item(loadValue, refClass)
|
400
|
+
if (argCount > 0 or len(kwArgs) > 0) and \
|
401
|
+
not refClass.ignoreAttrs and \
|
402
|
+
not refClass.methods.has_key(utils.INIT) and \
|
403
|
+
not _isexception(refClass.classObject) :
|
404
|
+
code.addWarning(msgs.NO_CTOR_ARGS)
|
405
|
+
else :
|
406
|
+
returnValue = _checkBuiltin(code, loadValue, argCount, kwArgs,
|
407
|
+
check_arg_count)
|
408
|
+
if returnValue.type is types.NoneType and \
|
409
|
+
not OP.POP_TOP(code.nextOpInfo()[0]) :
|
410
|
+
name = utils.safestr(loadValue.data)
|
411
|
+
if type(loadValue.data) == types.TupleType :
|
412
|
+
name = string.join(loadValue.data, '.')
|
413
|
+
# lambda with setattr is a common way of setting
|
414
|
+
# attributes, so allow it
|
415
|
+
if name != 'setattr' \
|
416
|
+
or code.func.function.func_name != '<lambda>':
|
417
|
+
code.addWarning(msgs.USING_NONE_RETURN_VALUE % name)
|
418
|
+
|
419
|
+
code.stack = code.stack[:funcIndex] + [ returnValue ]
|
420
|
+
code.functionsCalled[funcName] = loadValue
|
421
|
+
|
422
|
+
|
423
|
+
def _classHasAttribute(c, attr) :
|
424
|
+
return (c.methods.has_key(attr) or c.members.has_key(attr) or
|
425
|
+
hasattr(c.classObject, attr))
|
426
|
+
|
427
|
+
def _checkClassAttribute(attr, c, code) :
|
428
|
+
if _classHasAttribute(c, attr) :
|
429
|
+
try :
|
430
|
+
del c.memberRefs[attr]
|
431
|
+
except KeyError :
|
432
|
+
pass
|
433
|
+
elif cfg().classAttrExists :
|
434
|
+
if attr not in cfg().missingAttrs:
|
435
|
+
code.addWarning(msgs.INVALID_CLASS_ATTR % attr)
|
436
|
+
|
437
|
+
def _checkModuleAttribute(attr, module, code, ref) :
|
438
|
+
try:
|
439
|
+
if attr not in module.modules[ref].attributes and \
|
440
|
+
not utils.endswith(ref, '.' + attr) :
|
441
|
+
code.addWarning(msgs.INVALID_MODULE_ATTR % attr)
|
442
|
+
except (KeyError, TypeError):
|
443
|
+
# if ref isn't found, or ref isn't even hashable, we don't care
|
444
|
+
# we may not know, or ref could be something funky [e for e].method()
|
445
|
+
pass
|
446
|
+
|
447
|
+
try:
|
448
|
+
_checkClassAttribute(attr, module.classes[ref], code)
|
449
|
+
except (KeyError, TypeError):
|
450
|
+
# if ref isn't found, or ref isn't even hashable, we don't care
|
451
|
+
# we may not know, or ref could be something funky [e for e].method()
|
452
|
+
pass
|
453
|
+
|
454
|
+
|
455
|
+
def _getGlobalName(name, func) :
|
456
|
+
# get the right name of global refs (for from XXX import YYY)
|
457
|
+
opModule = func.function.func_globals.get(name)
|
458
|
+
try :
|
459
|
+
if opModule and isinstance(opModule, types.ModuleType) :
|
460
|
+
name = opModule.__name__
|
461
|
+
except :
|
462
|
+
# we have to do this in case the class raises an access exception
|
463
|
+
# due to overriding __special__() methods
|
464
|
+
pass
|
465
|
+
|
466
|
+
return name
|
467
|
+
|
468
|
+
|
469
|
+
def _checkNoEffect(code, ignoreStmtWithNoEffect=0):
|
470
|
+
if (not ignoreStmtWithNoEffect and
|
471
|
+
OP.POP_TOP(code.nextOpInfo()[0]) and cfg().noEffect):
|
472
|
+
code.addWarning(msgs.POSSIBLE_STMT_WITH_NO_EFFECT)
|
473
|
+
|
474
|
+
def _makeConstant(code, index, factoryFunction) :
|
475
|
+
"Build a constant on the stack ((), [], or {})"
|
476
|
+
if index > 0 :
|
477
|
+
code.stack[-index:] = [ factoryFunction(code.stack[-index:]) ]
|
478
|
+
_checkNoEffect(code)
|
479
|
+
else :
|
480
|
+
code.pushStack(factoryFunction())
|
481
|
+
|
482
|
+
|
483
|
+
def _hasGlobal(operand, module, func, main) :
|
484
|
+
return (func.function.func_globals.has_key(operand) or
|
485
|
+
main or module.moduleLineNums.has_key(operand) or
|
486
|
+
__builtins__.has_key(operand))
|
487
|
+
|
488
|
+
def _checkGlobal(operand, module, func, code, err, main = 0) :
|
489
|
+
if not _hasGlobal(operand, module, func, main) :
|
490
|
+
code.addWarning(err % operand)
|
491
|
+
if not cfg().reportAllGlobals :
|
492
|
+
func.function.func_globals[operand] = operand
|
493
|
+
|
494
|
+
|
495
|
+
def _handleComparison(stack, operand) :
|
496
|
+
num_ops = 2
|
497
|
+
if operand == 'exception match':
|
498
|
+
num_ops = 1
|
499
|
+
|
500
|
+
si = min(len(stack), num_ops)
|
501
|
+
compareValues = stack[-si:]
|
502
|
+
for _ in range(si, 2) :
|
503
|
+
compareValues.append(Stack.Item(None, None))
|
504
|
+
stack[-si:] = [ Stack.makeComparison(compareValues, operand) ]
|
505
|
+
return compareValues
|
506
|
+
|
507
|
+
def _handleImport(code, operand, module, main, fromName) :
|
508
|
+
# FIXME: this function should be refactored/cleaned up
|
509
|
+
key = operand
|
510
|
+
tmpOperand = tmpFromName = operand
|
511
|
+
if fromName is not None :
|
512
|
+
tmpOperand = tmpFromName = fromName
|
513
|
+
key = (fromName, operand)
|
514
|
+
|
515
|
+
if cfg().deprecated:
|
516
|
+
try:
|
517
|
+
undeprecated = python.DEPRECATED_MODULES[tmpFromName]
|
518
|
+
except KeyError:
|
519
|
+
pass
|
520
|
+
else:
|
521
|
+
msg = msgs.USING_DEPRECATED_MODULE % tmpFromName
|
522
|
+
if undeprecated:
|
523
|
+
msg.data = msg.data + msgs.USE_INSTEAD % undeprecated
|
524
|
+
code.addWarning(msg)
|
525
|
+
|
526
|
+
if cfg().reimportSelf and tmpOperand == module.module.__name__ :
|
527
|
+
code.addWarning(msgs.IMPORT_SELF % tmpOperand)
|
528
|
+
|
529
|
+
modline1 = module.moduleLineNums.get(tmpOperand, None)
|
530
|
+
modline2 = module.moduleLineNums.get((tmpFromName, '*'), None)
|
531
|
+
key2 = (tmpFromName,)
|
532
|
+
if fromName is not None and operand != '*' :
|
533
|
+
key2 = (tmpFromName, operand)
|
534
|
+
modline3 = module.moduleLineNums.get(key2, None)
|
535
|
+
|
536
|
+
if modline1 is not None or modline2 is not None or modline3 is not None :
|
537
|
+
err = None
|
538
|
+
|
539
|
+
if fromName is None :
|
540
|
+
if modline1 is not None :
|
541
|
+
err = msgs.MODULE_IMPORTED_AGAIN % operand
|
542
|
+
elif cfg().mixImport :
|
543
|
+
err = msgs.MIX_IMPORT_AND_FROM_IMPORT % tmpFromName
|
544
|
+
else :
|
545
|
+
if modline3 is not None and operand != '*' :
|
546
|
+
err = 'from %s import %s' % (tmpFromName, operand)
|
547
|
+
err = msgs.MODULE_MEMBER_IMPORTED_AGAIN % err
|
548
|
+
elif modline1 is not None :
|
549
|
+
if cfg().mixImport and code.getLineNum() != modline1[1] :
|
550
|
+
err = msgs.MIX_IMPORT_AND_FROM_IMPORT % tmpFromName
|
551
|
+
else :
|
552
|
+
err = msgs.MODULE_MEMBER_ALSO_STAR_IMPORTED % fromName
|
553
|
+
|
554
|
+
# filter out warnings when files are different (ie, from X import ...)
|
555
|
+
if err is not None and cfg().moduleImportErrors :
|
556
|
+
bytes = module.main_code
|
557
|
+
if bytes is None or \
|
558
|
+
bytes.function.func_code.co_filename == code.func_code.co_filename :
|
559
|
+
code.addWarning(err)
|
560
|
+
|
561
|
+
if main :
|
562
|
+
fileline = (code.func_code.co_filename, code.getLineNum())
|
563
|
+
module.moduleLineNums[key] = fileline
|
564
|
+
if fromName is not None :
|
565
|
+
module.moduleLineNums[(fromName,)] = fileline
|
566
|
+
|
567
|
+
|
568
|
+
def _handleImportFrom(code, operand, module, main) :
|
569
|
+
fromName = code.stack[-1].data
|
570
|
+
if utils.pythonVersion() < utils.PYTHON_2_0 and \
|
571
|
+
OP.POP_TOP(code.nextOpInfo()[0]):
|
572
|
+
code.popNextOp()
|
573
|
+
code.pushStack(Stack.Item(operand, types.ModuleType))
|
574
|
+
_handleImport(code, operand, module, main, fromName)
|
575
|
+
|
576
|
+
|
577
|
+
# http://www.python.org/doc/current/lib/typesseq-strings.html
|
578
|
+
_FORMAT_CONVERTERS = 'diouxXeEfFgGcrs'
|
579
|
+
# NOTE: lLh are legal in the flags, but are ignored by python, we warn
|
580
|
+
_FORMAT_FLAGS = '*#- +.' + string.digits
|
581
|
+
|
582
|
+
def _getFormatInfo(format, code) :
|
583
|
+
vars = []
|
584
|
+
|
585
|
+
# first get rid of all the instances of %% in the string, they don't count
|
586
|
+
format = string.replace(format, "%%", "")
|
587
|
+
sections = string.split(format, '%')
|
588
|
+
percentFormatCount = formatCount = string.count(format, '%')
|
589
|
+
mappingFormatCount = 0
|
590
|
+
|
591
|
+
# skip the first item in the list, it's always empty
|
592
|
+
for section in sections[1:] :
|
593
|
+
orig_section = section
|
594
|
+
if not section:
|
595
|
+
w = msgs.INVALID_FORMAT % orig_section
|
596
|
+
w.data = w.data + ' (end of format string)'
|
597
|
+
code.addWarning(w)
|
598
|
+
continue
|
599
|
+
|
600
|
+
# handle dictionary formats
|
601
|
+
if section[0] == '(' :
|
602
|
+
mappingFormatCount = mappingFormatCount + 1
|
603
|
+
varname = string.split(section, ')')
|
604
|
+
if varname[1] == '' :
|
605
|
+
code.addWarning(msgs.INVALID_FORMAT % section)
|
606
|
+
vars.append(varname[0][1:])
|
607
|
+
section = varname[1]
|
608
|
+
|
609
|
+
if not section :
|
610
|
+
# no format data to check
|
611
|
+
continue
|
612
|
+
|
613
|
+
# FIXME: we ought to just define a regular expression to check
|
614
|
+
# formatRE = '[ #+-]*([0-9]*|*)(|.(|*|[0-9]*)[diouxXeEfFgGcrs].*'
|
615
|
+
stars = 0
|
616
|
+
for i in range(0, len(section)) :
|
617
|
+
if section[i] in _FORMAT_CONVERTERS :
|
618
|
+
break
|
619
|
+
if section[i] in _FORMAT_FLAGS :
|
620
|
+
if section[i] == '*' :
|
621
|
+
stars = stars + 1
|
622
|
+
if mappingFormatCount > 0 :
|
623
|
+
code.addWarning(msgs.USING_STAR_IN_FORMAT_MAPPING % section)
|
624
|
+
|
625
|
+
if stars > 2 :
|
626
|
+
code.addWarning(msgs.TOO_MANY_STARS_IN_FORMAT)
|
627
|
+
|
628
|
+
formatCount = formatCount + stars
|
629
|
+
if section[i] not in _FORMAT_CONVERTERS :
|
630
|
+
code.addWarning(msgs.INVALID_FORMAT % orig_section)
|
631
|
+
|
632
|
+
if mappingFormatCount > 0 and mappingFormatCount != percentFormatCount :
|
633
|
+
code.addWarning(msgs.CANT_MIX_MAPPING_IN_FORMATS)
|
634
|
+
|
635
|
+
return formatCount, vars
|
636
|
+
|
637
|
+
def _getConstant(code, module, data) :
|
638
|
+
data = utils.safestr(data.data)
|
639
|
+
format = code.constants.get(data)
|
640
|
+
if format is not None :
|
641
|
+
return format
|
642
|
+
|
643
|
+
format = module.variables.get(data)
|
644
|
+
if format is not None and format.value is not None :
|
645
|
+
return format.value
|
646
|
+
return None
|
647
|
+
|
648
|
+
_UNCHECKABLE_FORMAT_STACK_TYPES = \
|
649
|
+
(Stack.TYPE_UNKNOWN, Stack.TYPE_FUNC_RETURN, Stack.TYPE_ATTRIBUTE,
|
650
|
+
Stack.TYPE_GLOBAL, Stack.TYPE_EXCEPT)
|
651
|
+
_UNCHECKABLE_STACK_TYPES = _UNCHECKABLE_FORMAT_STACK_TYPES + (types.NoneType,)
|
652
|
+
|
653
|
+
def _getFormatString(code, codeSource) :
|
654
|
+
if len(code.stack) <= 1 :
|
655
|
+
return ''
|
656
|
+
|
657
|
+
format = code.stack[-2]
|
658
|
+
if format.type != types.StringType or not format.const :
|
659
|
+
format = _getConstant(code, codeSource.module, format)
|
660
|
+
if format is None or type(format) != types.StringType :
|
661
|
+
return ''
|
662
|
+
return format
|
663
|
+
return format.data
|
664
|
+
|
665
|
+
|
666
|
+
def _getFormatWarnings(code, codeSource) :
|
667
|
+
format = _getFormatString(code, codeSource)
|
668
|
+
if not format :
|
669
|
+
return
|
670
|
+
|
671
|
+
args = 0
|
672
|
+
count, vars = _getFormatInfo(format, code)
|
673
|
+
topOfStack = code.stack[-1]
|
674
|
+
if topOfStack.isLocals() :
|
675
|
+
for varname in vars :
|
676
|
+
if not code.unusedLocals.has_key(varname) :
|
677
|
+
code.addWarning(msgs.NO_LOCAL_VAR % varname)
|
678
|
+
else :
|
679
|
+
code.unusedLocals[varname] = None
|
680
|
+
else :
|
681
|
+
stackItemType = topOfStack.getType(code.typeMap)
|
682
|
+
if ((stackItemType == types.DictType and len(vars) > 0) or
|
683
|
+
codeSource.func.isParam(topOfStack.data) or
|
684
|
+
stackItemType in _UNCHECKABLE_FORMAT_STACK_TYPES) :
|
685
|
+
return
|
686
|
+
|
687
|
+
if topOfStack.type == types.TupleType :
|
688
|
+
args = topOfStack.length
|
689
|
+
elif stackItemType == types.TupleType :
|
690
|
+
args = len(code.constants.get(topOfStack.data, (0,)))
|
691
|
+
else :
|
692
|
+
args = 1
|
693
|
+
|
694
|
+
if args and count != args :
|
695
|
+
code.addWarning(msgs.INVALID_FORMAT_COUNT % (count, args))
|
696
|
+
|
697
|
+
def _checkAttributeType(code, stackValue, attr) :
|
698
|
+
if not cfg().checkObjectAttrs :
|
699
|
+
return
|
700
|
+
|
701
|
+
varTypes = code.typeMap.get(utils.safestr(stackValue.data), None)
|
702
|
+
if not varTypes :
|
703
|
+
return
|
704
|
+
|
705
|
+
# the value may have been converted on stack (`v`)
|
706
|
+
other_types = []
|
707
|
+
if stackValue.type not in varTypes :
|
708
|
+
other_types = [stackValue.type]
|
709
|
+
|
710
|
+
for varType in varTypes + other_types :
|
711
|
+
# ignore built-in types that have no attributes
|
712
|
+
if python.METHODLESS_OBJECTS.has_key(varType) :
|
713
|
+
continue
|
714
|
+
|
715
|
+
attrs = python.BUILTIN_ATTRS.get(varType, None)
|
716
|
+
if attrs is not None :
|
717
|
+
if attr in attrs :
|
718
|
+
return
|
719
|
+
continue
|
720
|
+
|
721
|
+
if hasattr(varType, 'ignoreAttrs') :
|
722
|
+
if varType.ignoreAttrs or _classHasAttribute(varType, attr) :
|
723
|
+
return
|
724
|
+
elif not hasattr(varType, 'attributes') or attr in varType.attributes :
|
725
|
+
return
|
726
|
+
|
727
|
+
code.addWarning(msgs.OBJECT_HAS_NO_ATTR % (stackValue.data, attr))
|
728
|
+
|
729
|
+
|
730
|
+
def _getTypeStr(t):
|
731
|
+
returnStr = utils.safestr(t)
|
732
|
+
strs = string.split(returnStr, "'")
|
733
|
+
try:
|
734
|
+
if len(strs) == 3:
|
735
|
+
returnStr = strs[-2]
|
736
|
+
except IndexError:
|
737
|
+
pass
|
738
|
+
return returnStr
|
739
|
+
|
740
|
+
|
741
|
+
def _getLineNum(co, instr_index):
|
742
|
+
co_lnotab = co.co_lnotab
|
743
|
+
lineno = co.co_firstlineno
|
744
|
+
addr = 0
|
745
|
+
for lnotab_index in range(0, len(co_lnotab), 2):
|
746
|
+
addr = addr + ord(co_lnotab[lnotab_index])
|
747
|
+
if addr > instr_index:
|
748
|
+
return lineno
|
749
|
+
lineno = lineno + ord(co_lnotab[lnotab_index+1])
|
750
|
+
return lineno
|
751
|
+
|
752
|
+
|
753
|
+
class Code :
|
754
|
+
'Hold all the code state information necessary to find warnings'
|
755
|
+
|
756
|
+
def __init__(self) :
|
757
|
+
self.bytes = None
|
758
|
+
self.func = None
|
759
|
+
self.func_code = None
|
760
|
+
self.index = 0
|
761
|
+
self.indexList = []
|
762
|
+
self.extended_arg = 0
|
763
|
+
self.lastLineNum = 0
|
764
|
+
self.maxCode = 0
|
765
|
+
self.has_except = 0
|
766
|
+
self.try_finally_first = 0
|
767
|
+
self.starts_and_ends_with_finally = 0
|
768
|
+
|
769
|
+
self.returnValues = []
|
770
|
+
self.raiseValues = []
|
771
|
+
self.stack = []
|
772
|
+
|
773
|
+
self.unpackCount = 0
|
774
|
+
self.loops = 0
|
775
|
+
self.branches = {}
|
776
|
+
|
777
|
+
self.warnings = []
|
778
|
+
|
779
|
+
self.globalRefs = {}
|
780
|
+
self.unusedLocals = {}
|
781
|
+
self.deletedLocals = {}
|
782
|
+
self.functionsCalled = {}
|
783
|
+
self.typeMap = {}
|
784
|
+
self.constants = {}
|
785
|
+
self.codeObjects = {}
|
786
|
+
|
787
|
+
def init(self, func) :
|
788
|
+
self.func = func
|
789
|
+
self.func_code, self.bytes, self.index, self.maxCode, self.extended_arg = \
|
790
|
+
OP.initFuncCode(func.function)
|
791
|
+
self.lastLineNum = self.func_code.co_firstlineno
|
792
|
+
self.returnValues = []
|
793
|
+
|
794
|
+
# initialize the arguments to unused
|
795
|
+
for arg in func.arguments() :
|
796
|
+
self.unusedLocals[arg] = 0
|
797
|
+
self.typeMap[arg] = [ Stack.TYPE_UNKNOWN ]
|
798
|
+
|
799
|
+
def getLineNum(self):
|
800
|
+
line = self.lastLineNum
|
801
|
+
# if we don't have linenum info, calc it from co_lntab & index
|
802
|
+
if line == self.func_code.co_firstlineno:
|
803
|
+
# FIXME: this could be optimized, if we kept last line info
|
804
|
+
line = _getLineNum(self.func_code, self.index - 1)
|
805
|
+
return line
|
806
|
+
|
807
|
+
def getWarning(self, err, line = None) :
|
808
|
+
if line is None :
|
809
|
+
line = self.getLineNum()
|
810
|
+
return Warning.Warning(self.func_code, line, err)
|
811
|
+
|
812
|
+
def addWarning(self, err, line = None) :
|
813
|
+
w = err
|
814
|
+
if not isinstance(w, Warning.Warning):
|
815
|
+
w = self.getWarning(err, line)
|
816
|
+
self.warnings.append(w)
|
817
|
+
|
818
|
+
def popNextOp(self) :
|
819
|
+
self.indexList.append(self.index)
|
820
|
+
info = OP.getInfo(self.bytes, self.index, self.extended_arg)
|
821
|
+
op, oparg, self.index, self.extended_arg = info
|
822
|
+
if op < OP.HAVE_ARGUMENT :
|
823
|
+
utils.debug(" %d %s" % (self.indexList[-1], OP.name[op]))
|
824
|
+
operand = None
|
825
|
+
else :
|
826
|
+
operand = OP.getOperand(op, self.func_code, oparg)
|
827
|
+
self.label = label = OP.getLabel(op, oparg, self.index)
|
828
|
+
utils.debug(" %d %s" % (self.indexList[-1], OP.name[op]), oparg, operand)
|
829
|
+
if label != None :
|
830
|
+
self.addBranch(label)
|
831
|
+
|
832
|
+
return op, oparg, operand
|
833
|
+
|
834
|
+
def nextOpInfo(self, offset = 0) :
|
835
|
+
try :
|
836
|
+
return OP.getInfo(self.bytes, self.index + offset, 0)[0:3]
|
837
|
+
except IndexError :
|
838
|
+
return -1, 0, -1
|
839
|
+
|
840
|
+
def getFirstOp(self) :
|
841
|
+
# find the first real op, maybe we should not check if params are used
|
842
|
+
i = extended_arg = 0
|
843
|
+
while i < self.maxCode :
|
844
|
+
op, oparg, i, extended_arg = OP.getInfo(self.bytes, i, extended_arg)
|
845
|
+
if not OP.LINE_NUM(op) :
|
846
|
+
if not (OP.LOAD_CONST(op) or OP.LOAD_GLOBAL(op)) :
|
847
|
+
return op
|
848
|
+
raise RuntimeError('Could not find first opcode in function')
|
849
|
+
|
850
|
+
def pushStack(self, item, ignoreStmtWithNoEffect=0):
|
851
|
+
self.stack.append(item)
|
852
|
+
_checkNoEffect(self, ignoreStmtWithNoEffect)
|
853
|
+
|
854
|
+
def popStack(self) :
|
855
|
+
if self.stack :
|
856
|
+
del self.stack[-1]
|
857
|
+
|
858
|
+
def popStackItems(self, count) :
|
859
|
+
stackLen = len(self.stack)
|
860
|
+
if stackLen > 0 :
|
861
|
+
count = min(count, stackLen)
|
862
|
+
del self.stack[-count:]
|
863
|
+
|
864
|
+
def unpack(self) :
|
865
|
+
if self.unpackCount :
|
866
|
+
self.unpackCount = self.unpackCount - 1
|
867
|
+
else :
|
868
|
+
self.popStack()
|
869
|
+
|
870
|
+
def __getStringStackType(self, data) :
|
871
|
+
try :
|
872
|
+
return data.getType({})
|
873
|
+
except AttributeError :
|
874
|
+
return Stack.TYPE_UNKNOWN
|
875
|
+
|
876
|
+
def __getStackType(self) :
|
877
|
+
if not self.stack :
|
878
|
+
return Stack.TYPE_UNKNOWN
|
879
|
+
|
880
|
+
if not self.unpackCount :
|
881
|
+
return self.__getStringStackType(self.stack[-1])
|
882
|
+
|
883
|
+
data = self.stack[-1].data
|
884
|
+
if type(data) == types.TupleType :
|
885
|
+
try :
|
886
|
+
return self.__getStringStackType(data[len(data)-self.unpackCount])
|
887
|
+
except IndexError :
|
888
|
+
# happens when unpacking a var for which we don't know the size
|
889
|
+
pass
|
890
|
+
|
891
|
+
return Stack.TYPE_UNKNOWN
|
892
|
+
|
893
|
+
def setType(self, name) :
|
894
|
+
valueList = self.typeMap.get(name, [])
|
895
|
+
newType = self.__getStackType()
|
896
|
+
# longs are being merged with ints, assume they are the same
|
897
|
+
# comparisons are really ints anyways
|
898
|
+
if newType in (types.LongType, Stack.TYPE_COMPARISON):
|
899
|
+
newType = types.IntType
|
900
|
+
if newType not in valueList :
|
901
|
+
valueList.append(newType)
|
902
|
+
|
903
|
+
# need to ignore various types (Unknown, Func return values, etc)
|
904
|
+
# also ignore None, don't care if they use it and a real type
|
905
|
+
if valueList and newType not in _UNCHECKABLE_STACK_TYPES and \
|
906
|
+
cfg().inconsistentTypes:
|
907
|
+
oldTypes = []
|
908
|
+
# only add types to the value list that are "interesting"
|
909
|
+
for typeToAdd in valueList:
|
910
|
+
if typeToAdd not in _UNCHECKABLE_STACK_TYPES and \
|
911
|
+
typeToAdd != newType:
|
912
|
+
oldTypes.append(_getTypeStr(typeToAdd))
|
913
|
+
# do we have any "interesting" old types? if so, warn
|
914
|
+
if oldTypes:
|
915
|
+
self.addWarning(msgs.INCONSISTENT_TYPE % \
|
916
|
+
(name, oldTypes, _getTypeStr(newType)))
|
917
|
+
self.typeMap[name] = valueList
|
918
|
+
|
919
|
+
def addReturn(self) :
|
920
|
+
if len(self.stack) > 0 :
|
921
|
+
value = (self.getLineNum(), self.stack[-1], self.nextOpInfo()[2])
|
922
|
+
self.returnValues.append(value)
|
923
|
+
self.popStack()
|
924
|
+
|
925
|
+
def addRaise(self) :
|
926
|
+
self.raiseValues.append((self.getLineNum(), None, self.nextOpInfo()[2]))
|
927
|
+
|
928
|
+
def addBranch(self, label) :
|
929
|
+
if label is not None :
|
930
|
+
self.branches[label] = self.branches.get(label, 0) + 1
|
931
|
+
|
932
|
+
def removeBranch(self, label) :
|
933
|
+
branch = self.branches.get(label, None)
|
934
|
+
if branch is not None :
|
935
|
+
if branch == 1 :
|
936
|
+
del self.branches[label]
|
937
|
+
else :
|
938
|
+
self.branches[label] = branch - 1
|
939
|
+
|
940
|
+
def remove_unreachable_code(self, label) :
|
941
|
+
if len(self.indexList) >= 2 :
|
942
|
+
index = self.indexList[-2]
|
943
|
+
if index >= 0 and OP.POP_BLOCK(ord(self.bytes[index])) :
|
944
|
+
index = self.indexList[-3]
|
945
|
+
if index >= 0 :
|
946
|
+
op = ord(self.bytes[index])
|
947
|
+
if OP.RETURN_VALUE(op) or OP.RAISE_VARARGS(op) or \
|
948
|
+
OP.END_FINALLY(ord(self.bytes[label-1])) :
|
949
|
+
self.removeBranch(label)
|
950
|
+
|
951
|
+
def updateCheckerArgs(self, operand) :
|
952
|
+
rc = utils.shouldUpdateArgs(operand)
|
953
|
+
if rc :
|
954
|
+
utils.updateCheckerArgs(self.stack[-1].data, self.func_code,
|
955
|
+
self.getLineNum(), self.warnings)
|
956
|
+
return rc
|
957
|
+
|
958
|
+
def updateModuleLineNums(self, module, operand) :
|
959
|
+
filelist = (self.func_code.co_filename, self.getLineNum())
|
960
|
+
module.moduleLineNums[operand] = filelist
|
961
|
+
|
962
|
+
|
963
|
+
class CodeSource :
|
964
|
+
'Holds source information about a code block (module, class, func, etc)'
|
965
|
+
def __init__(self, module, func, c, main, in_class, code) :
|
966
|
+
self.module = module
|
967
|
+
self.func = func
|
968
|
+
self.classObject = c
|
969
|
+
self.main = main
|
970
|
+
self.in_class = in_class
|
971
|
+
self.code = code
|
972
|
+
self.calling_code = []
|
973
|
+
|
974
|
+
def _checkException(code, name) :
|
975
|
+
if code.stack and code.stack[-1].type == Stack.TYPE_EXCEPT :
|
976
|
+
if __builtins__.has_key(name) :
|
977
|
+
code.addWarning(msgs.SET_EXCEPT_TO_BUILTIN % name)
|
978
|
+
|
979
|
+
def _checkAssign(code, name):
|
980
|
+
if name in _BAD_ASSIGN_NAMES:
|
981
|
+
code.addWarning(msgs.SHOULDNT_ASSIGN_BUILTIN % name)
|
982
|
+
else:
|
983
|
+
cap = string.capitalize(name)
|
984
|
+
if cap in _BAD_ASSIGN_NAMES:
|
985
|
+
code.addWarning(msgs.SHOULDNT_ASSIGN_NAME % (name, cap))
|
986
|
+
|
987
|
+
def _checkVariableOperationOnItself(code, lname, msg):
|
988
|
+
if code.stack and code.stack[-1].getName() == lname:
|
989
|
+
code.addWarning(msg % lname)
|
990
|
+
|
991
|
+
def _checkFutureKeywords(code, varname) :
|
992
|
+
kw = python.FUTURE_KEYWORDS.get(varname)
|
993
|
+
if kw is not None :
|
994
|
+
code.addWarning(msgs.USING_KEYWORD % (varname, kw))
|
995
|
+
|
996
|
+
def _STORE_NAME(oparg, operand, codeSource, code) :
|
997
|
+
if not code.updateCheckerArgs(operand) :
|
998
|
+
_checkFutureKeywords(code, operand)
|
999
|
+
module = codeSource.module
|
1000
|
+
if not codeSource.in_class :
|
1001
|
+
_checkShadowBuiltin(code, operand)
|
1002
|
+
if not codeSource.calling_code :
|
1003
|
+
_checkGlobal(operand, module, codeSource.func, code,
|
1004
|
+
msgs.GLOBAL_DEFINED_NOT_DECLARED, codeSource.main)
|
1005
|
+
else :
|
1006
|
+
if code.stack :
|
1007
|
+
codeSource.classObject.statics[operand] = code.stack[-1]
|
1008
|
+
codeSource.classObject.lineNums[operand] = code.getLineNum()
|
1009
|
+
|
1010
|
+
var = module.variables.get(operand)
|
1011
|
+
if var is not None and code.stack and code.stack[-1].const :
|
1012
|
+
var.value = code.stack[-1].data
|
1013
|
+
|
1014
|
+
if code.unpackCount :
|
1015
|
+
code.unpackCount = code.unpackCount - 1
|
1016
|
+
else:
|
1017
|
+
_checkAssign(code, operand)
|
1018
|
+
_checkException(code, operand)
|
1019
|
+
code.popStack()
|
1020
|
+
if not module.moduleLineNums.has_key(operand) and codeSource.main :
|
1021
|
+
code.updateModuleLineNums(module, operand)
|
1022
|
+
|
1023
|
+
_STORE_GLOBAL = _STORE_NAME
|
1024
|
+
|
1025
|
+
def _checkLoadGlobal(codeSource, code, varname) :
|
1026
|
+
_checkFutureKeywords(code, varname)
|
1027
|
+
should_check = 1
|
1028
|
+
if code.func_code.co_name == utils.LAMBDA :
|
1029
|
+
# this could really be a local reference, check first
|
1030
|
+
if not codeSource.main and codeSource.calling_code:
|
1031
|
+
func = getattr(codeSource.calling_code[-1], 'function', None)
|
1032
|
+
if func is not None and varname in func.func_code.co_varnames :
|
1033
|
+
_handleLoadLocal(code, codeSource, varname)
|
1034
|
+
should_check = 0
|
1035
|
+
|
1036
|
+
if should_check :
|
1037
|
+
# if a global var starts w/__ and the global is referenced in a class
|
1038
|
+
# we have to strip off the _class-name, to get the original name
|
1039
|
+
if codeSource.classObject and \
|
1040
|
+
utils.startswith(varname, '_' + codeSource.classObject.name + '__'):
|
1041
|
+
varname = varname[len(codeSource.classObject.name)+1:]
|
1042
|
+
|
1043
|
+
# make sure we remember each global ref to check for unused
|
1044
|
+
code.globalRefs[_getGlobalName(varname, codeSource.func)] = varname
|
1045
|
+
if not codeSource.in_class :
|
1046
|
+
_checkGlobal(varname, codeSource.module, codeSource.func,
|
1047
|
+
code, msgs.INVALID_GLOBAL)
|
1048
|
+
|
1049
|
+
def _LOAD_NAME(oparg, operand, codeSource, code) :
|
1050
|
+
_checkLoadGlobal(codeSource, code, operand)
|
1051
|
+
|
1052
|
+
# if there was from XXX import *, _* names aren't imported
|
1053
|
+
if codeSource.module.modules.has_key(operand) and \
|
1054
|
+
hasattr(codeSource.module.module, operand) :
|
1055
|
+
operand = getattr(codeSource.module.module, operand).__name__
|
1056
|
+
|
1057
|
+
opType, const = Stack.TYPE_GLOBAL, 0
|
1058
|
+
if operand == 'None' :
|
1059
|
+
opType, const = types.NoneType, 0
|
1060
|
+
elif operand == 'Ellipsis' :
|
1061
|
+
opType, const = types.EllipsisType, 1
|
1062
|
+
code.pushStack(Stack.Item(operand, opType, const))
|
1063
|
+
|
1064
|
+
_LOAD_GLOBAL = _LOAD_NAME
|
1065
|
+
|
1066
|
+
def _LOAD_DEREF(oparg, operand, codeSource, code) :
|
1067
|
+
if type(oparg) == types.IntType :
|
1068
|
+
func_code = code.func_code
|
1069
|
+
try:
|
1070
|
+
argname = func_code.co_cellvars[oparg]
|
1071
|
+
except IndexError:
|
1072
|
+
argname = func_code.co_freevars[oparg - len(func_code.co_cellvars)]
|
1073
|
+
code.pushStack(Stack.Item(argname, types.StringType))
|
1074
|
+
if code.func_code.co_name != utils.LAMBDA :
|
1075
|
+
code.unusedLocals[argname] = None
|
1076
|
+
else :
|
1077
|
+
_LOAD_GLOBAL(oparg, operand, codeSource, code)
|
1078
|
+
|
1079
|
+
_LOAD_CLOSURE = _LOAD_DEREF
|
1080
|
+
|
1081
|
+
def _DELETE_NAME(oparg, operand, codeSource, code) :
|
1082
|
+
_checkLoadGlobal(codeSource, code, operand)
|
1083
|
+
# FIXME: handle deleting global multiple times
|
1084
|
+
_DELETE_GLOBAL = _DELETE_NAME
|
1085
|
+
|
1086
|
+
def _make_const(value):
|
1087
|
+
if type(value) == types.TupleType:
|
1088
|
+
return Stack.makeTuple(map(_make_const, value))
|
1089
|
+
return Stack.Item(value, type(value), 1)
|
1090
|
+
|
1091
|
+
def _LOAD_CONST(oparg, operand, codeSource, code) :
|
1092
|
+
code.pushStack(_make_const(operand))
|
1093
|
+
if type(operand) == types.CodeType :
|
1094
|
+
name = operand.co_name
|
1095
|
+
obj = code.codeObjects.get(name, None)
|
1096
|
+
if name == utils.LAMBDA :
|
1097
|
+
# use a unique key, so we can have multiple lambdas
|
1098
|
+
code.codeObjects[code.index] = operand
|
1099
|
+
elif obj is None :
|
1100
|
+
code.codeObjects[name] = operand
|
1101
|
+
elif cfg().redefiningFunction :
|
1102
|
+
code.addWarning(msgs.REDEFINING_ATTR % (name, obj.co_firstlineno))
|
1103
|
+
|
1104
|
+
|
1105
|
+
def _checkLocalShadow(code, module, varname) :
|
1106
|
+
if module.variables.has_key(varname) and cfg().shadows :
|
1107
|
+
line = module.moduleLineNums.get(varname, ('<unknown>', 0))
|
1108
|
+
w = code.getWarning(msgs.LOCAL_SHADOWS_GLOBAL % (varname, line[1]))
|
1109
|
+
if line[0] != w.file:
|
1110
|
+
w.err = '%s in file %s' % (w.err, line[0])
|
1111
|
+
code.addWarning(w)
|
1112
|
+
|
1113
|
+
def _checkShadowBuiltin(code, varname) :
|
1114
|
+
if __builtins__.has_key(varname) and varname[0] != '_' and \
|
1115
|
+
cfg().shadowBuiltins:
|
1116
|
+
code.addWarning(msgs.VARIABLE_SHADOWS_BUILTIN % varname)
|
1117
|
+
|
1118
|
+
def _checkLoadLocal(code, codeSource, varname, deletedWarn, usedBeforeSetWarn) :
|
1119
|
+
_checkFutureKeywords(code, varname)
|
1120
|
+
deletedLine = code.deletedLocals.get(varname)
|
1121
|
+
if deletedLine :
|
1122
|
+
code.addWarning(deletedWarn % (varname, deletedLine))
|
1123
|
+
elif not code.unusedLocals.has_key(varname) and \
|
1124
|
+
not codeSource.func.isParam(varname) :
|
1125
|
+
code.addWarning(usedBeforeSetWarn % varname)
|
1126
|
+
code.unusedLocals[varname] = None
|
1127
|
+
_checkLocalShadow(code, codeSource.module, varname)
|
1128
|
+
|
1129
|
+
def _handleLoadLocal(code, codeSource, varname) :
|
1130
|
+
_checkLoadLocal(code, codeSource, varname,
|
1131
|
+
msgs.LOCAL_DELETED, msgs.VAR_USED_BEFORE_SET)
|
1132
|
+
|
1133
|
+
def _LOAD_FAST(oparg, operand, codeSource, code) :
|
1134
|
+
code.pushStack(Stack.Item(operand, type(operand)))
|
1135
|
+
_handleLoadLocal(code, codeSource, operand)
|
1136
|
+
|
1137
|
+
def _STORE_FAST(oparg, operand, codeSource, code) :
|
1138
|
+
if not code.updateCheckerArgs(operand) :
|
1139
|
+
_checkFutureKeywords(code, operand)
|
1140
|
+
if code.stack and code.stack[-1].type == types.StringType and \
|
1141
|
+
not code.stack[-1].const:
|
1142
|
+
_checkVariableOperationOnItself(code, operand,
|
1143
|
+
msgs.SET_VAR_TO_ITSELF)
|
1144
|
+
code.setType(operand)
|
1145
|
+
if not code.unpackCount and code.stack and \
|
1146
|
+
(code.stack[-1].const or code.stack[-1].type == types.TupleType) :
|
1147
|
+
if code.constants.has_key(operand) :
|
1148
|
+
del code.constants[operand]
|
1149
|
+
else :
|
1150
|
+
code.constants[operand] = code.stack[-1].data
|
1151
|
+
|
1152
|
+
_checkLocalShadow(code, codeSource.module, operand)
|
1153
|
+
_checkShadowBuiltin(code, operand)
|
1154
|
+
_checkAssign(code, operand)
|
1155
|
+
_checkException(code, operand)
|
1156
|
+
if code.deletedLocals.has_key(operand) :
|
1157
|
+
del code.deletedLocals[operand]
|
1158
|
+
if not code.unusedLocals.has_key(operand) :
|
1159
|
+
errLine = code.getLineNum()
|
1160
|
+
if code.unpackCount and not cfg().unusedLocalTuple :
|
1161
|
+
errLine = -errLine
|
1162
|
+
code.unusedLocals[operand] = errLine
|
1163
|
+
code.unpack()
|
1164
|
+
|
1165
|
+
def _DELETE_FAST(oparg, operand, codeSource, code) :
|
1166
|
+
_checkLoadLocal(code, codeSource, operand,
|
1167
|
+
msgs.LOCAL_ALREADY_DELETED, msgs.VAR_DELETED_BEFORE_SET)
|
1168
|
+
code.deletedLocals[operand] = code.getLineNum()
|
1169
|
+
|
1170
|
+
def _checkAttribute(top, operand, codeSource, code) :
|
1171
|
+
if top.data == cfg().methodArgName and codeSource.classObject != None :
|
1172
|
+
_checkClassAttribute(operand, codeSource.classObject, code)
|
1173
|
+
elif type(top.type) == types.StringType or top.type == types.ModuleType :
|
1174
|
+
_checkModuleAttribute(operand, codeSource.module, code, top.data)
|
1175
|
+
else :
|
1176
|
+
_checkAttributeType(code, top, operand)
|
1177
|
+
|
1178
|
+
def _checkExcessiveReferences(code, top, extraAttr = None) :
|
1179
|
+
if cfg().maxReferences <= 0 :
|
1180
|
+
return
|
1181
|
+
|
1182
|
+
try :
|
1183
|
+
data = top.data
|
1184
|
+
if extraAttr is not None :
|
1185
|
+
data = data + (extraAttr,)
|
1186
|
+
|
1187
|
+
maxReferences = cfg().maxReferences
|
1188
|
+
if data[0] == cfg().methodArgName:
|
1189
|
+
maxReferences = maxReferences + 1
|
1190
|
+
if len(data) > maxReferences :
|
1191
|
+
name = string.join(top.data, '.')
|
1192
|
+
code.addWarning(msgs.TOO_MANY_REFERENCES % (maxReferences, name))
|
1193
|
+
except TypeError :
|
1194
|
+
pass
|
1195
|
+
|
1196
|
+
def _checkDeprecated(code, identifierTuple):
|
1197
|
+
# check deprecated module.function
|
1198
|
+
try:
|
1199
|
+
name = string.join(identifierTuple, '.')
|
1200
|
+
undeprecated = python.DEPRECATED_ATTRS[name]
|
1201
|
+
except (KeyError, TypeError):
|
1202
|
+
pass
|
1203
|
+
else:
|
1204
|
+
msg = msgs.USING_DEPRECATED_ATTR % name
|
1205
|
+
if undeprecated:
|
1206
|
+
msg.data = msg.data + msgs.USE_INSTEAD % undeprecated
|
1207
|
+
code.addWarning(msg)
|
1208
|
+
|
1209
|
+
def _LOAD_ATTR(oparg, operand, codeSource, code) :
|
1210
|
+
if len(code.stack) > 0 :
|
1211
|
+
top = code.stack[-1]
|
1212
|
+
_checkAttribute(top, operand, codeSource, code)
|
1213
|
+
top.addAttribute(operand)
|
1214
|
+
|
1215
|
+
if len(top.data) == 2:
|
1216
|
+
if cfg().deprecated:
|
1217
|
+
_checkDeprecated(code, top.data)
|
1218
|
+
|
1219
|
+
try:
|
1220
|
+
insecure = python.SECURITY_FUNCS.get(top.data[0])
|
1221
|
+
except TypeError:
|
1222
|
+
pass
|
1223
|
+
else:
|
1224
|
+
if insecure and insecure.has_key(operand):
|
1225
|
+
func = string.join(top.data, '.')
|
1226
|
+
code.addWarning(msgs.USING_INSECURE_FUNC % func)
|
1227
|
+
|
1228
|
+
nextOp = code.nextOpInfo()[0]
|
1229
|
+
if not OP.LOAD_ATTR(nextOp) :
|
1230
|
+
if OP.POP_TOP(nextOp) and cfg().noEffect:
|
1231
|
+
code.addWarning(msgs.POSSIBLE_STMT_WITH_NO_EFFECT)
|
1232
|
+
else :
|
1233
|
+
_checkExcessiveReferences(code, top)
|
1234
|
+
|
1235
|
+
def _ok_to_set_attr(classObject, basename, attr) :
|
1236
|
+
return (cfg().onlyCheckInitForMembers and classObject != None and
|
1237
|
+
basename == cfg().methodArgName and
|
1238
|
+
not _classHasAttribute(classObject, attr))
|
1239
|
+
|
1240
|
+
def _STORE_ATTR(oparg, operand, codeSource, code) :
|
1241
|
+
if code.stack :
|
1242
|
+
top = code.stack.pop()
|
1243
|
+
top_name = '%s.%s' % (top.getName(), operand)
|
1244
|
+
try:
|
1245
|
+
# FIXME: this is a hack to handle code like:
|
1246
|
+
# a.a = [x for x in range(2) if x > 1]
|
1247
|
+
previous = code.stack[-1]
|
1248
|
+
except IndexError:
|
1249
|
+
previous = None
|
1250
|
+
if top.type in (types.StringType, Stack.TYPE_ATTRIBUTE) and \
|
1251
|
+
previous and previous.type == Stack.TYPE_ATTRIBUTE:
|
1252
|
+
_checkVariableOperationOnItself(code, top_name,
|
1253
|
+
msgs.SET_VAR_TO_ITSELF)
|
1254
|
+
_checkExcessiveReferences(code, top, operand)
|
1255
|
+
if _ok_to_set_attr(codeSource.classObject, top.data, operand) :
|
1256
|
+
code.addWarning(msgs.INVALID_SET_CLASS_ATTR % operand)
|
1257
|
+
code.unpack()
|
1258
|
+
|
1259
|
+
def _DELETE_ATTR(oparg, operand, codeSource, code) :
|
1260
|
+
if len(code.stack) > 0 :
|
1261
|
+
_checkAttribute(code.stack[-1], operand, codeSource, code)
|
1262
|
+
|
1263
|
+
def _getExceptionInfo(codeSource, item):
|
1264
|
+
# FIXME: probably ought to try to handle raise module.Error
|
1265
|
+
if item.type is types.StringType and item.const == 1:
|
1266
|
+
return item.data, 1
|
1267
|
+
|
1268
|
+
e = None
|
1269
|
+
if item.type is Stack.TYPE_GLOBAL:
|
1270
|
+
try:
|
1271
|
+
e = eval(item.data)
|
1272
|
+
except NameError:
|
1273
|
+
pass
|
1274
|
+
|
1275
|
+
if not e:
|
1276
|
+
try:
|
1277
|
+
c = codeSource.module.classes.get(item.data)
|
1278
|
+
except TypeError: # item.data may not be hashable (e.g., list)
|
1279
|
+
return e, 0
|
1280
|
+
|
1281
|
+
if c is not None:
|
1282
|
+
e = c.classObject
|
1283
|
+
else:
|
1284
|
+
v = codeSource.module.variables.get(item.data)
|
1285
|
+
if v is not None:
|
1286
|
+
return v, (v.type == types.StringType)
|
1287
|
+
return e, 0
|
1288
|
+
|
1289
|
+
_UNCHECKABLE_CATCH_TYPES = (Stack.TYPE_UNKNOWN, Stack.TYPE_ATTRIBUTE)
|
1290
|
+
def _checkCatchException(codeSource, code, item):
|
1291
|
+
if not cfg().badExceptions:
|
1292
|
+
return
|
1293
|
+
|
1294
|
+
if item.data is None or item.type in _UNCHECKABLE_CATCH_TYPES:
|
1295
|
+
return
|
1296
|
+
|
1297
|
+
e, is_str = _getExceptionInfo(codeSource, item)
|
1298
|
+
if is_str:
|
1299
|
+
code.addWarning(msgs.CATCH_STR_EXCEPTION % item.data)
|
1300
|
+
elif e is not None and not _isexception(e):
|
1301
|
+
code.addWarning(msgs.CATCH_BAD_EXCEPTION % item.data)
|
1302
|
+
|
1303
|
+
def _handleExceptionChecks(codeSource, code, checks):
|
1304
|
+
for item in checks:
|
1305
|
+
if item is not None:
|
1306
|
+
if item.type is not types.TupleType:
|
1307
|
+
_checkCatchException(codeSource, code, item)
|
1308
|
+
else:
|
1309
|
+
for ti in item.data:
|
1310
|
+
if isinstance(ti, Stack.Item):
|
1311
|
+
_checkCatchException(codeSource, code, ti)
|
1312
|
+
|
1313
|
+
_BOOL_NAMES = ('True', 'False')
|
1314
|
+
_BAD_ASSIGN_NAMES = _BOOL_NAMES + ('None',)
|
1315
|
+
|
1316
|
+
def _checkBoolean(code, checks):
|
1317
|
+
for item in checks:
|
1318
|
+
try:
|
1319
|
+
data = string.capitalize(item.data)
|
1320
|
+
if item.type is Stack.TYPE_GLOBAL and data in _BOOL_NAMES:
|
1321
|
+
code.addWarning(msgs.BOOL_COMPARE % item.data)
|
1322
|
+
except (AttributeError, TypeError):
|
1323
|
+
# TypeError is necessary for Python 1.5.2
|
1324
|
+
pass # ignore items that are not a StackItem or a string
|
1325
|
+
|
1326
|
+
def _COMPARE_OP(oparg, operand, codeSource, code) :
|
1327
|
+
compareValues = _handleComparison(code.stack, operand)
|
1328
|
+
if oparg == OP.EXCEPT_COMPARISON:
|
1329
|
+
_handleExceptionChecks(codeSource, code, compareValues)
|
1330
|
+
elif oparg < OP.IN_COMPARISON: # '<', '<=', '==', '!=', '>', '>='
|
1331
|
+
_checkBoolean(code, compareValues)
|
1332
|
+
elif oparg < OP.IS_COMPARISON: # 'in', 'not in'
|
1333
|
+
# TODO: any checks that should be done here?
|
1334
|
+
pass
|
1335
|
+
elif cfg().isLiteral:
|
1336
|
+
# X is Y or X is not Y comparison
|
1337
|
+
second_arg = code.stack[-1].data[2]
|
1338
|
+
# FIXME: how should booleans be handled, need to think about it
|
1339
|
+
## if second_arg.const or (second_arg.type == Stack.TYPE_GLOBAL and
|
1340
|
+
## second_arg.data in ['True', 'False']):
|
1341
|
+
if second_arg.const and second_arg.data is not None:
|
1342
|
+
data = second_arg.data
|
1343
|
+
if second_arg.type is types.DictType:
|
1344
|
+
data = {}
|
1345
|
+
not_str = ''
|
1346
|
+
if oparg != OP.IS_COMPARISON:
|
1347
|
+
not_str = ' not'
|
1348
|
+
code.addWarning(msgs.IS_LITERAL % (not_str, data))
|
1349
|
+
|
1350
|
+
_checkNoEffect(code)
|
1351
|
+
|
1352
|
+
def _IMPORT_NAME(oparg, operand, codeSource, code) :
|
1353
|
+
code.pushStack(Stack.Item(operand, types.ModuleType))
|
1354
|
+
nextOp = code.nextOpInfo()[0]
|
1355
|
+
if not OP.IMPORT_FROM(nextOp) and not OP.IMPORT_STAR(nextOp) :
|
1356
|
+
_handleImport(code, operand, codeSource.module, codeSource.main, None)
|
1357
|
+
|
1358
|
+
def _IMPORT_FROM(oparg, operand, codeSource, code) :
|
1359
|
+
_handleImportFrom(code, operand, codeSource.module, codeSource.main)
|
1360
|
+
# this is necessary for python 1.5 (see STORE_GLOBAL/NAME)
|
1361
|
+
if utils.pythonVersion() < utils.PYTHON_2_0 :
|
1362
|
+
code.popStack()
|
1363
|
+
if not codeSource.main :
|
1364
|
+
code.unusedLocals[operand] = None
|
1365
|
+
elif not codeSource.module.moduleLineNums.has_key(operand) :
|
1366
|
+
code.updateModuleLineNums(codeSource.module, operand)
|
1367
|
+
|
1368
|
+
def _IMPORT_STAR(oparg, operand, codeSource, code) :
|
1369
|
+
_handleImportFrom(code, '*', codeSource.module, codeSource.main)
|
1370
|
+
|
1371
|
+
# Python 2.3 introduced some optimizations that create problems
|
1372
|
+
# this is a utility for ignoring these cases
|
1373
|
+
def _shouldIgnoreCodeOptimizations(code, bytecodes, offset, length=None):
|
1374
|
+
if utils.pythonVersion() < utils.PYTHON_2_3:
|
1375
|
+
return 0
|
1376
|
+
|
1377
|
+
if length is None:
|
1378
|
+
length = offset - 1
|
1379
|
+
try:
|
1380
|
+
start = code.index - offset
|
1381
|
+
return bytecodes == code.bytes[start:start+length]
|
1382
|
+
except IndexError:
|
1383
|
+
return 0
|
1384
|
+
|
1385
|
+
# In Python 2.3, a, b = 1,2 generates this code:
|
1386
|
+
# ...
|
1387
|
+
# ROT_TWO
|
1388
|
+
# JUMP_FORWARD 2
|
1389
|
+
# DUP_TOP
|
1390
|
+
# POP_TOP
|
1391
|
+
#
|
1392
|
+
# which generates a Possible stmt w/no effect
|
1393
|
+
|
1394
|
+
# ROT_TWO = 2; JUMP_FORWARD = 110; 2, 0 is the offset (2)
|
1395
|
+
_IGNORE_SEQ = '%c%c%c%c' % (2, 110, 2, 0)
|
1396
|
+
def _shouldIgnoreNoEffectWarning(code):
|
1397
|
+
return _shouldIgnoreCodeOptimizations(code, _IGNORE_SEQ, 5)
|
1398
|
+
|
1399
|
+
def _DUP_TOP(oparg, operand, codeSource, code) :
|
1400
|
+
if len(code.stack) > 0 :
|
1401
|
+
code.pushStack(code.stack[-1], _shouldIgnoreNoEffectWarning(code))
|
1402
|
+
|
1403
|
+
def _popn(code, n) :
|
1404
|
+
if len(code.stack) >= 2 :
|
1405
|
+
loadValue = code.stack[-2]
|
1406
|
+
if cfg().modifyDefaultValue and loadValue.type == types.StringType :
|
1407
|
+
_checkModifyDefaultArg(code, loadValue.data)
|
1408
|
+
|
1409
|
+
code.popStackItems(n)
|
1410
|
+
|
1411
|
+
def _DELETE_SUBSCR(oparg, operand, codeSource, code) :
|
1412
|
+
_popn(code, 2)
|
1413
|
+
|
1414
|
+
def _STORE_SUBSCR(oparg, operand, codeSource, code) :
|
1415
|
+
_popn(code, 3)
|
1416
|
+
|
1417
|
+
def _CALL_FUNCTION(oparg, operand, codeSource, code) :
|
1418
|
+
_handleFunctionCall(codeSource, code, oparg)
|
1419
|
+
|
1420
|
+
def _CALL_FUNCTION_VAR(oparg, operand, codeSource, code) :
|
1421
|
+
_handleFunctionCall(codeSource, code, oparg, 1, 0)
|
1422
|
+
|
1423
|
+
def _CALL_FUNCTION_KW(oparg, operand, codeSource, code) :
|
1424
|
+
_handleFunctionCall(codeSource, code, oparg, 1)
|
1425
|
+
|
1426
|
+
def _CALL_FUNCTION_VAR_KW(oparg, operand, codeSource, code) :
|
1427
|
+
_handleFunctionCall(codeSource, code, oparg, 2, 0)
|
1428
|
+
|
1429
|
+
def _MAKE_FUNCTION(oparg, operand, codeSource, code) :
|
1430
|
+
newValue = Stack.makeFuncReturnValue(code.stack[-1], oparg)
|
1431
|
+
code.popStackItems(oparg+1)
|
1432
|
+
code.pushStack(newValue)
|
1433
|
+
|
1434
|
+
def _MAKE_CLOSURE(oparg, operand, codeSource, code) :
|
1435
|
+
_MAKE_FUNCTION(max(0, oparg - 1), operand, codeSource, code)
|
1436
|
+
|
1437
|
+
def _BUILD_MAP(oparg, operand, codeSource, code) :
|
1438
|
+
_makeConstant(code, oparg, Stack.makeDict)
|
1439
|
+
def _BUILD_TUPLE(oparg, operand, codeSource, code) :
|
1440
|
+
_makeConstant(code, oparg, Stack.makeTuple)
|
1441
|
+
def _BUILD_LIST(oparg, operand, codeSource, code) :
|
1442
|
+
_makeConstant(code, oparg, Stack.makeList)
|
1443
|
+
|
1444
|
+
def _BUILD_CLASS(oparg, operand, codeSource, code) :
|
1445
|
+
newValue = Stack.makeFuncReturnValue(code.stack[-1], types.ClassType)
|
1446
|
+
code.popStackItems(3)
|
1447
|
+
code.pushStack(newValue)
|
1448
|
+
|
1449
|
+
def _LIST_APPEND(oparg, operand, codeSource, code):
|
1450
|
+
code.popStackItems(2)
|
1451
|
+
|
1452
|
+
def _modifyStackName(code, suffix):
|
1453
|
+
if code.stack:
|
1454
|
+
tos = code.stack[-1]
|
1455
|
+
tos_type = type(tos.data)
|
1456
|
+
if tos_type == types.StringType:
|
1457
|
+
tos.data = tos.data + suffix
|
1458
|
+
elif tos_type == types.TupleType and \
|
1459
|
+
type(tos.data[-1]) == types.StringType:
|
1460
|
+
tos.data = tos.data[:-1] + (tos.data[-1] + suffix,)
|
1461
|
+
|
1462
|
+
def _UNARY_CONVERT(oparg, operand, codeSource, code) :
|
1463
|
+
if code.stack:
|
1464
|
+
stackValue = code.stack[-1]
|
1465
|
+
if stackValue.data == cfg().methodArgName and \
|
1466
|
+
stackValue.const == 0 and codeSource.classObject is not None and \
|
1467
|
+
codeSource.func.function.func_name == '__repr__' :
|
1468
|
+
code.addWarning(msgs.USING_SELF_IN_REPR)
|
1469
|
+
stackValue.data = utils.safestr(stackValue.data)
|
1470
|
+
stackValue.type = types.StringType
|
1471
|
+
_modifyStackName(code, '-repr')
|
1472
|
+
|
1473
|
+
def _UNARY_POSITIVE(oparg, operand, codeSource, code) :
|
1474
|
+
if OP.UNARY_POSITIVE(code.nextOpInfo()[0]) :
|
1475
|
+
code.addWarning(msgs.STMT_WITH_NO_EFFECT % '++')
|
1476
|
+
code.popNextOp()
|
1477
|
+
elif cfg().unaryPositive and code.stack and not code.stack[-1].const :
|
1478
|
+
code.addWarning(msgs.UNARY_POSITIVE_HAS_NO_EFFECT)
|
1479
|
+
_modifyStackName(code, '-pos')
|
1480
|
+
|
1481
|
+
def _UNARY_NEGATIVE(oparg, operand, codeSource, code) :
|
1482
|
+
if OP.UNARY_NEGATIVE(code.nextOpInfo()[0]) :
|
1483
|
+
code.addWarning(msgs.STMT_WITH_NO_EFFECT % '--')
|
1484
|
+
_modifyStackName(code, '-neg')
|
1485
|
+
|
1486
|
+
def _UNARY_NOT(oparg, operand, codeSource, code) :
|
1487
|
+
_modifyStackName(code, '-not')
|
1488
|
+
|
1489
|
+
def _UNARY_INVERT(oparg, operand, codeSource, code) :
|
1490
|
+
if OP.UNARY_INVERT(code.nextOpInfo()[0]) :
|
1491
|
+
code.addWarning(msgs.STMT_WITH_NO_EFFECT % '~~')
|
1492
|
+
_modifyStackName(code, '-invert')
|
1493
|
+
|
1494
|
+
|
1495
|
+
def _popStackRef(code, operand, count = 2) :
|
1496
|
+
code.popStackItems(count)
|
1497
|
+
code.pushStack(Stack.Item(operand, Stack.TYPE_UNKNOWN))
|
1498
|
+
|
1499
|
+
def _popModifiedStack(code, suffix=' '):
|
1500
|
+
code.popStack()
|
1501
|
+
_modifyStackName(code, suffix)
|
1502
|
+
|
1503
|
+
def _pop(oparg, operand, codeSource, code) :
|
1504
|
+
code.popStack()
|
1505
|
+
_POP_TOP = _PRINT_ITEM = _pop
|
1506
|
+
|
1507
|
+
def _popModified(oparg, operand, codeSource, code):
|
1508
|
+
_popModifiedStack(code)
|
1509
|
+
|
1510
|
+
def _BINARY_RSHIFT(oparg, operand, codeSource, code):
|
1511
|
+
_coerce_type(code)
|
1512
|
+
_popModified(oparg, operand, codeSource, code)
|
1513
|
+
_BINARY_LSHIFT = _BINARY_RSHIFT
|
1514
|
+
|
1515
|
+
def _checkModifyNoOp(code, op, msg=msgs.MODIFY_VAR_NOOP, modifyStack=1):
|
1516
|
+
stack = code.stack
|
1517
|
+
if len(stack) >= 2:
|
1518
|
+
if (stack[-1].type != Stack.TYPE_UNKNOWN and
|
1519
|
+
stack[-2].type != Stack.TYPE_UNKNOWN):
|
1520
|
+
name = stack[-1].getName()
|
1521
|
+
if name != Stack.TYPE_UNKNOWN and name == stack[-2].getName():
|
1522
|
+
code.addWarning(msg % (name, op, name))
|
1523
|
+
|
1524
|
+
if modifyStack:
|
1525
|
+
code.popStack()
|
1526
|
+
stack[-1].const = 0
|
1527
|
+
_modifyStackName(code, op)
|
1528
|
+
|
1529
|
+
def _BINARY_AND(oparg, operand, codeSource, code):
|
1530
|
+
# Don't modify the stack, since _coerce_type() will do it.
|
1531
|
+
_checkModifyNoOp(code, '&', modifyStack=0)
|
1532
|
+
_coerce_type(code)
|
1533
|
+
|
1534
|
+
def _BINARY_OR(oparg, operand, codeSource, code):
|
1535
|
+
# Don't modify the stack, since _coerce_type() will do it.
|
1536
|
+
_checkModifyNoOp(code, '|', modifyStack=0)
|
1537
|
+
_coerce_type(code)
|
1538
|
+
|
1539
|
+
def _BINARY_XOR(oparg, operand, codeSource, code):
|
1540
|
+
# Don't modify the stack, since _coerce_type() will do it.
|
1541
|
+
_checkModifyNoOp(code, '^', msgs.XOR_VAR_WITH_ITSELF, modifyStack=0)
|
1542
|
+
_coerce_type(code)
|
1543
|
+
|
1544
|
+
def _PRINT_ITEM_TO(oparg, operand, codeSource, code) :
|
1545
|
+
code.popStackItems(2)
|
1546
|
+
|
1547
|
+
try:
|
1548
|
+
ComplexType = types.ComplexType
|
1549
|
+
except NameError:
|
1550
|
+
ComplexType = types.FloatType # need some numeric type here
|
1551
|
+
|
1552
|
+
_NUMERIC_TYPES = (types.IntType, types.FloatType, ComplexType)
|
1553
|
+
|
1554
|
+
# FIXME: This is pathetically weak, need to handle more types
|
1555
|
+
def _coerce_type(code) :
|
1556
|
+
_checkNoEffect(code)
|
1557
|
+
newItem = Stack.Item('<stack>', Stack.TYPE_UNKNOWN)
|
1558
|
+
if len(code.stack) >= 2 :
|
1559
|
+
s1, s2 = code.stack[-2:]
|
1560
|
+
s1type = s1.getType(code.typeMap)
|
1561
|
+
s2type = s2.getType(code.typeMap)
|
1562
|
+
if s1type != s2type :
|
1563
|
+
if s1type in _NUMERIC_TYPES and s2type in _NUMERIC_TYPES :
|
1564
|
+
newType = types.FloatType
|
1565
|
+
if s1type == ComplexType or s2type == ComplexType:
|
1566
|
+
newType = ComplexType
|
1567
|
+
newItem.type = newType
|
1568
|
+
|
1569
|
+
code.popStackItems(2)
|
1570
|
+
code.pushStack(newItem)
|
1571
|
+
|
1572
|
+
def _BINARY_ADD(oparg, operand, codeSource, code) :
|
1573
|
+
stack = code.stack
|
1574
|
+
if len(stack) >= 2 and (stack[-1].const and stack[-2].const and
|
1575
|
+
stack[-1].type == stack[-2].type) :
|
1576
|
+
value = stack[-2].data + stack[-1].data
|
1577
|
+
code.popStackItems(2)
|
1578
|
+
code.pushStack(Stack.Item(value, type(value), 1))
|
1579
|
+
else :
|
1580
|
+
_coerce_type(code)
|
1581
|
+
|
1582
|
+
def _BINARY_SUBTRACT(oparg, operand, codeSource, code) :
|
1583
|
+
_coerce_type(code)
|
1584
|
+
_BINARY_POWER = _BINARY_SUBTRACT
|
1585
|
+
|
1586
|
+
def _BINARY_SUBSCR(oparg, operand, codeSource, code) :
|
1587
|
+
_checkNoEffect(code)
|
1588
|
+
if len(code.stack) >= 2 :
|
1589
|
+
stack = code.stack
|
1590
|
+
varType = code.typeMap.get(utils.safestr(stack[-2].data), [])
|
1591
|
+
if types.ListType in varType and stack[-1].type == types.TupleType :
|
1592
|
+
code.addWarning(msgs.USING_TUPLE_ACCESS_TO_LIST % stack[-2].data)
|
1593
|
+
_popStackRef(code, operand)
|
1594
|
+
|
1595
|
+
def _isint(stackItem, code) :
|
1596
|
+
if type(stackItem.data) == types.IntType :
|
1597
|
+
return 1
|
1598
|
+
stackTypes = code.typeMap.get(stackItem.data, [])
|
1599
|
+
if len(stackTypes) != 1 :
|
1600
|
+
return 0
|
1601
|
+
return types.IntType in stackTypes
|
1602
|
+
|
1603
|
+
def _BINARY_DIVIDE(oparg, operand, codeSource, code) :
|
1604
|
+
_checkNoEffect(code)
|
1605
|
+
_checkModifyNoOp(code, '/', msgs.DIVIDE_VAR_BY_ITSELF, 0)
|
1606
|
+
if cfg().intDivide and len(code.stack) >= 2 :
|
1607
|
+
if _isint(code.stack[-1], code) and _isint(code.stack[-2], code) :
|
1608
|
+
# don't warn if we are going to convert the result to an int
|
1609
|
+
if not (len(code.stack) >= 3 and
|
1610
|
+
code.stack[-3].data == 'int' and
|
1611
|
+
OP.CALL_FUNCTION(code.nextOpInfo()[0])):
|
1612
|
+
code.addWarning(msgs.INTEGER_DIVISION % tuple(code.stack[-2:]))
|
1613
|
+
|
1614
|
+
_popModifiedStack(code, '/')
|
1615
|
+
|
1616
|
+
def _BINARY_TRUE_DIVIDE(oparg, operand, codeSource, code) :
|
1617
|
+
_checkNoEffect(code)
|
1618
|
+
_checkVariableOperationOnItself(code, operand, msgs.DIVIDE_VAR_BY_ITSELF)
|
1619
|
+
_popModifiedStack(code, '/')
|
1620
|
+
_BINARY_FLOOR_DIVIDE = _BINARY_TRUE_DIVIDE
|
1621
|
+
|
1622
|
+
def _BINARY_MULTIPLY(oparg, operand, codeSource, code) :
|
1623
|
+
if len(code.stack) >= 2 :
|
1624
|
+
format = _getFormatString(code, codeSource)
|
1625
|
+
if format and type(code.stack[-1].data) == types.IntType :
|
1626
|
+
code.stack[-2].data = format * code.stack[-1].data
|
1627
|
+
code.popStack()
|
1628
|
+
else:
|
1629
|
+
_coerce_type(code)
|
1630
|
+
else:
|
1631
|
+
_popModifiedStack(code, '*')
|
1632
|
+
|
1633
|
+
def _BINARY_MODULO(oparg, operand, codeSource, code) :
|
1634
|
+
_checkNoEffect(code)
|
1635
|
+
if cfg().modulo1 and code.stack and code.stack[-1].data == 1:
|
1636
|
+
if len(code.stack) < 2 or \
|
1637
|
+
code.stack[-2].getType(code.typeMap) != types.FloatType:
|
1638
|
+
code.addWarning(msgs.MODULO_1)
|
1639
|
+
_getFormatWarnings(code, codeSource)
|
1640
|
+
_popModifiedStack(code, '%')
|
1641
|
+
if code.stack:
|
1642
|
+
code.stack[-1].const = 0
|
1643
|
+
|
1644
|
+
def _ROT_TWO(oparg, operand, codeSource, code) :
|
1645
|
+
if len(code.stack) >= 2 :
|
1646
|
+
tmp = code.stack[-2]
|
1647
|
+
code.stack[-2] = code.stack[-1]
|
1648
|
+
code.stack[-1] = tmp
|
1649
|
+
|
1650
|
+
def _ROT_THREE(oparg, operand, codeSource, code) :
|
1651
|
+
"""Lifts second and third stack item one position up,
|
1652
|
+
moves top down to position three."""
|
1653
|
+
if len(code.stack) >= 3 :
|
1654
|
+
second = code.stack[-2]
|
1655
|
+
third = code.stack[-3]
|
1656
|
+
code.stack[-3] = code.stack[-1]
|
1657
|
+
code.stack[-2] = third
|
1658
|
+
code.stack[-1] = second
|
1659
|
+
|
1660
|
+
def _ROT_FOUR(oparg, operand, codeSource, code) :
|
1661
|
+
"""Lifts second, third and forth stack item one position up,
|
1662
|
+
moves top down to position four."""
|
1663
|
+
if len(code.stack) >= 4 :
|
1664
|
+
second = code.stack[-2]
|
1665
|
+
third = code.stack[-3]
|
1666
|
+
fourth = code.stack[-4]
|
1667
|
+
code.stack[-4] = code.stack[-1]
|
1668
|
+
code.stack[-3] = fourth
|
1669
|
+
code.stack[-2] = third
|
1670
|
+
code.stack[-1] = second
|
1671
|
+
|
1672
|
+
def _SETUP_EXCEPT(oparg, operand, codeSource, code) :
|
1673
|
+
code.has_except = 1
|
1674
|
+
code.pushStack(Stack.Item(None, Stack.TYPE_EXCEPT))
|
1675
|
+
code.pushStack(Stack.Item(None, Stack.TYPE_EXCEPT))
|
1676
|
+
|
1677
|
+
def _SETUP_FINALLY(oparg, operand, codeSource, code) :
|
1678
|
+
if not code.has_except :
|
1679
|
+
code.try_finally_first = 1
|
1680
|
+
|
1681
|
+
def _END_FINALLY(oparg, operand, codeSource, code) :
|
1682
|
+
if code.try_finally_first and code.index == (len(code.bytes) - 4) :
|
1683
|
+
code.starts_and_ends_with_finally = 1
|
1684
|
+
|
1685
|
+
def _LINE_NUM(oparg, operand, codeSource, code) :
|
1686
|
+
code.lastLineNum = oparg
|
1687
|
+
|
1688
|
+
def _UNPACK_SEQUENCE(oparg, operand, codeSource, code) :
|
1689
|
+
code.unpackCount = oparg
|
1690
|
+
if code.stack:
|
1691
|
+
top = code.stack[-1]
|
1692
|
+
# if we know we have a tuple, make sure we unpack it into the
|
1693
|
+
# right # of variables
|
1694
|
+
topType = top.getType(code.typeMap)
|
1695
|
+
if topType in _SEQUENCE_TYPES:
|
1696
|
+
length = top.length
|
1697
|
+
# we don't know the length, maybe it's constant and we can find out
|
1698
|
+
if length == 0:
|
1699
|
+
value = code.constants.get(utils.safestr(top.data))
|
1700
|
+
if type(value) in _SEQUENCE_TYPES:
|
1701
|
+
length = len(value)
|
1702
|
+
if length > 0 and length != oparg:
|
1703
|
+
if cfg().unpackLength:
|
1704
|
+
code.addWarning(msgs.WRONG_UNPACK_SIZE % (length, oparg))
|
1705
|
+
elif topType not in _UNCHECKABLE_STACK_TYPES:
|
1706
|
+
if cfg().unpackNonSequence:
|
1707
|
+
code.addWarning(msgs.UNPACK_NON_SEQUENCE %
|
1708
|
+
(top.data, _getTypeStr(topType)))
|
1709
|
+
_modifyStackName(code, '-unpack')
|
1710
|
+
|
1711
|
+
def _SLICE_1_ARG(oparg, operand, codeSource, code) :
|
1712
|
+
_popStackRef(code, operand)
|
1713
|
+
|
1714
|
+
_SLICE1 = _SLICE2 = _SLICE_1_ARG
|
1715
|
+
|
1716
|
+
def _SLICE3(oparg, operand, codeSource, code) :
|
1717
|
+
_popStackRef(code, operand, 3)
|
1718
|
+
|
1719
|
+
def _check_string_iteration(code, index):
|
1720
|
+
try:
|
1721
|
+
item = code.stack[index]
|
1722
|
+
except IndexError:
|
1723
|
+
return
|
1724
|
+
if item.getType(code.typeMap) == types.StringType and \
|
1725
|
+
cfg().stringIteration:
|
1726
|
+
code.addWarning(msgs.STRING_ITERATION % item.data)
|
1727
|
+
|
1728
|
+
def _FOR_LOOP(oparg, operand, codeSource, code) :
|
1729
|
+
code.loops = code.loops + 1
|
1730
|
+
_check_string_iteration(code, -2)
|
1731
|
+
_popStackRef(code, '<for_loop>', 2)
|
1732
|
+
|
1733
|
+
def _GET_ITER(oparg, operand, codeSource, code) :
|
1734
|
+
_check_string_iteration(code, -1)
|
1735
|
+
|
1736
|
+
def _FOR_ITER(oparg, operand, codeSource, code) :
|
1737
|
+
code.loops = code.loops + 1
|
1738
|
+
_popStackRef(code, '<for_iter>', 1)
|
1739
|
+
|
1740
|
+
def _jump(oparg, operand, codeSource, code) :
|
1741
|
+
if len(code.stack) > 0 :
|
1742
|
+
topOfStack = code.stack[-1]
|
1743
|
+
if topOfStack.isMethodCall(codeSource.classObject, cfg().methodArgName):
|
1744
|
+
name = topOfStack.data[-1]
|
1745
|
+
if codeSource.classObject.methods.has_key(name) :
|
1746
|
+
code.addWarning(msgs.USING_METHOD_AS_ATTR % name)
|
1747
|
+
_JUMP_ABSOLUTE = _jump
|
1748
|
+
|
1749
|
+
def _skip_loops(bytes, i, lastLineNum, max) :
|
1750
|
+
extended_arg = 0
|
1751
|
+
blockCount = 1
|
1752
|
+
while i < max :
|
1753
|
+
op, oparg, i, extended_arg = OP.getInfo(bytes, i, extended_arg)
|
1754
|
+
if OP.LINE_NUM(op) :
|
1755
|
+
lastLineNum = oparg
|
1756
|
+
elif OP.FOR_LOOP(op) or OP.FOR_ITER(op) or OP.SETUP_LOOP(op) :
|
1757
|
+
blockCount = blockCount + 1
|
1758
|
+
elif OP.POP_BLOCK(op) :
|
1759
|
+
blockCount = blockCount - 1
|
1760
|
+
if blockCount <= 0 :
|
1761
|
+
break
|
1762
|
+
|
1763
|
+
return lastLineNum, i
|
1764
|
+
|
1765
|
+
def _is_unreachable(code, topOfStack, branch, if_false) :
|
1766
|
+
# Are we are checking exceptions, but we not catching all exceptions?
|
1767
|
+
if (topOfStack.type == Stack.TYPE_COMPARISON and
|
1768
|
+
topOfStack.data[1] == 'exception match' and
|
1769
|
+
topOfStack.data[2] is not Exception) :
|
1770
|
+
return 1
|
1771
|
+
|
1772
|
+
# do we possibly have while 1: ?
|
1773
|
+
if not (topOfStack.const and topOfStack.data == 1 and if_false) :
|
1774
|
+
return 0
|
1775
|
+
|
1776
|
+
# get the op just before the branch (ie, -3)
|
1777
|
+
op, oparg, i, extended_arg = OP.getInfo(code.bytes, branch - 3, 0)
|
1778
|
+
# are we are jumping to before the while 1: (LOAD_CONST, JUMP_IF_FALSE)
|
1779
|
+
if not (OP.JUMP_ABSOLUTE(op) and oparg == (code.index - 3*3)) :
|
1780
|
+
return 0
|
1781
|
+
|
1782
|
+
# check if we break out of the loop
|
1783
|
+
i = code.index
|
1784
|
+
lastLineNum = code.getLineNum()
|
1785
|
+
while i < branch :
|
1786
|
+
op, oparg, i, extended_arg = OP.getInfo(code.bytes, i, extended_arg)
|
1787
|
+
if OP.LINE_NUM(op) :
|
1788
|
+
lastLineNum = oparg
|
1789
|
+
elif OP.BREAK_LOOP(op) :
|
1790
|
+
return 0
|
1791
|
+
elif OP.FOR_LOOP(op) or OP.FOR_ITER(op) or OP.SETUP_LOOP(op) :
|
1792
|
+
lastLineNum, i = _skip_loops(code.bytes, i, lastLineNum, branch)
|
1793
|
+
|
1794
|
+
i = code.index - 3*4
|
1795
|
+
op, oparg, i, extended_arg = OP.getInfo(code.bytes, i, 0)
|
1796
|
+
if OP.SETUP_LOOP(op) :
|
1797
|
+
# a little lie to pretend we have a raise after a while 1:
|
1798
|
+
code.removeBranch(i + oparg)
|
1799
|
+
code.raiseValues.append((lastLineNum, None, i + oparg))
|
1800
|
+
return 1
|
1801
|
+
|
1802
|
+
# In Python 2.3, while/if 1: gets optimized to
|
1803
|
+
# ...
|
1804
|
+
# JUMP_FORWARD 4
|
1805
|
+
# JUMP_IF_FALSE ?
|
1806
|
+
# POP_TOP
|
1807
|
+
#
|
1808
|
+
# which generates a Using a conditional statement with a constant value
|
1809
|
+
|
1810
|
+
# JUMP_FORWARD = 110; 4, 0 is the offset (4)
|
1811
|
+
_IGNORE_BOGUS_JUMP = '%c%c%c' % (110, 4, 0)
|
1812
|
+
def _shouldIgnoreBogusJumps(code):
|
1813
|
+
return _shouldIgnoreCodeOptimizations(code, _IGNORE_BOGUS_JUMP, 6, 3)
|
1814
|
+
|
1815
|
+
def _checkConstantCondition(code, topOfStack, if_false):
|
1816
|
+
# don't warn when doing (test and 'true' or 'false')
|
1817
|
+
# still warn when doing (test and None or 'false')
|
1818
|
+
if if_false or not OP.LOAD_CONST(code.nextOpInfo(1)[0]) or \
|
1819
|
+
not topOfStack.data or topOfStack.type is types.NoneType:
|
1820
|
+
if not _shouldIgnoreBogusJumps(code):
|
1821
|
+
code.addWarning(msgs.CONSTANT_CONDITION % utils.safestr(topOfStack))
|
1822
|
+
|
1823
|
+
def _jump_conditional(oparg, operand, codeSource, code, if_false) :
|
1824
|
+
# FIXME: this doesn't work in 2.3+ since constant conditions
|
1825
|
+
# are optimized away by the compiler.
|
1826
|
+
if code.stack :
|
1827
|
+
topOfStack = code.stack[-1]
|
1828
|
+
if (topOfStack.const or topOfStack.type is types.NoneType) and \
|
1829
|
+
cfg().constantConditions and \
|
1830
|
+
(topOfStack.data != 1 or cfg().constant1):
|
1831
|
+
_checkConstantCondition(code, topOfStack, if_false)
|
1832
|
+
|
1833
|
+
if _is_unreachable(code, topOfStack, code.label, if_false) :
|
1834
|
+
code.removeBranch(code.label)
|
1835
|
+
|
1836
|
+
_jump(oparg, operand, codeSource, code)
|
1837
|
+
|
1838
|
+
def _JUMP_IF_FALSE(oparg, operand, codeSource, code) :
|
1839
|
+
_jump_conditional(oparg, operand, codeSource, code, 1)
|
1840
|
+
|
1841
|
+
def _JUMP_IF_TRUE(oparg, operand, codeSource, code) :
|
1842
|
+
_jump_conditional(oparg, operand, codeSource, code, 0)
|
1843
|
+
|
1844
|
+
def _JUMP_FORWARD(oparg, operand, codeSource, code) :
|
1845
|
+
_jump(oparg, operand, codeSource, code)
|
1846
|
+
code.remove_unreachable_code(code.label)
|
1847
|
+
|
1848
|
+
def _RETURN_VALUE(oparg, operand, codeSource, code) :
|
1849
|
+
if not codeSource.calling_code :
|
1850
|
+
code.addReturn()
|
1851
|
+
|
1852
|
+
def _EXEC_STMT(oparg, operand, codeSource, code) :
|
1853
|
+
if cfg().usesExec :
|
1854
|
+
if code.stack and code.stack[-1].isNone() :
|
1855
|
+
code.addWarning(msgs.USES_GLOBAL_EXEC)
|
1856
|
+
else :
|
1857
|
+
code.addWarning(msgs.USES_EXEC)
|
1858
|
+
|
1859
|
+
def _checkStrException(code, varType, item):
|
1860
|
+
if varType is types.StringType:
|
1861
|
+
code.addWarning(msgs.RAISE_STR_EXCEPTION % item.data)
|
1862
|
+
|
1863
|
+
def _RAISE_VARARGS(oparg, operand, codeSource, code) :
|
1864
|
+
code.addRaise()
|
1865
|
+
if not cfg().badExceptions:
|
1866
|
+
return
|
1867
|
+
|
1868
|
+
if oparg > 0 and len(code.stack) >= oparg:
|
1869
|
+
item = code.stack[-oparg]
|
1870
|
+
if item.type not in (Stack.TYPE_FUNC_RETURN, Stack.TYPE_UNKNOWN):
|
1871
|
+
if item.type is Stack.TYPE_GLOBAL:
|
1872
|
+
e, is_str = _getExceptionInfo(codeSource, item)
|
1873
|
+
if is_str:
|
1874
|
+
_checkStrException(code, e.type, item)
|
1875
|
+
elif e is not None and not _isexception(e):
|
1876
|
+
code.addWarning(msgs.RAISE_BAD_EXCEPTION % item.data)
|
1877
|
+
else:
|
1878
|
+
_checkStrException(code, item.getType(code.typeMap), item)
|
1879
|
+
|
1880
|
+
|
1881
|
+
DISPATCH = [ None ] * 256
|
1882
|
+
DISPATCH[ 1] = _POP_TOP
|
1883
|
+
DISPATCH[ 2] = _ROT_TWO
|
1884
|
+
DISPATCH[ 3] = _ROT_THREE
|
1885
|
+
DISPATCH[ 4] = _DUP_TOP
|
1886
|
+
DISPATCH[ 5] = _ROT_FOUR
|
1887
|
+
DISPATCH[ 10] = _UNARY_POSITIVE
|
1888
|
+
DISPATCH[ 11] = _UNARY_NEGATIVE
|
1889
|
+
DISPATCH[ 12] = _UNARY_NOT
|
1890
|
+
DISPATCH[ 13] = _UNARY_CONVERT
|
1891
|
+
DISPATCH[ 15] = _UNARY_INVERT
|
1892
|
+
DISPATCH[ 18] = _LIST_APPEND
|
1893
|
+
DISPATCH[ 19] = _BINARY_POWER
|
1894
|
+
DISPATCH[ 20] = _BINARY_MULTIPLY
|
1895
|
+
DISPATCH[ 21] = _BINARY_DIVIDE
|
1896
|
+
DISPATCH[ 22] = _BINARY_MODULO
|
1897
|
+
DISPATCH[ 23] = _BINARY_ADD
|
1898
|
+
DISPATCH[ 24] = _BINARY_SUBTRACT
|
1899
|
+
DISPATCH[ 25] = _BINARY_SUBSCR
|
1900
|
+
DISPATCH[ 26] = _BINARY_FLOOR_DIVIDE
|
1901
|
+
DISPATCH[ 27] = _BINARY_TRUE_DIVIDE
|
1902
|
+
# FIXME: add INPLACE FLOOR/TRUE DIVIDE: 28/29
|
1903
|
+
DISPATCH[ 31] = _SLICE1
|
1904
|
+
DISPATCH[ 32] = _SLICE2
|
1905
|
+
DISPATCH[ 33] = _SLICE3
|
1906
|
+
DISPATCH[ 55] = _BINARY_ADD # INPLACE
|
1907
|
+
DISPATCH[ 56] = _BINARY_SUBTRACT # INPLACE
|
1908
|
+
DISPATCH[ 57] = _BINARY_MULTIPLY # INPLACE
|
1909
|
+
DISPATCH[ 58] = _BINARY_DIVIDE # INPLACE
|
1910
|
+
DISPATCH[ 59] = _BINARY_MODULO # INPLACE
|
1911
|
+
DISPATCH[ 60] = _STORE_SUBSCR
|
1912
|
+
DISPATCH[ 61] = _DELETE_SUBSCR
|
1913
|
+
DISPATCH[ 62] = _BINARY_LSHIFT
|
1914
|
+
DISPATCH[ 63] = _BINARY_RSHIFT
|
1915
|
+
DISPATCH[ 64] = _BINARY_AND
|
1916
|
+
DISPATCH[ 65] = _BINARY_XOR
|
1917
|
+
DISPATCH[ 66] = _BINARY_OR
|
1918
|
+
DISPATCH[ 67] = _BINARY_POWER # INPLACE
|
1919
|
+
DISPATCH[ 68] = _GET_ITER
|
1920
|
+
DISPATCH[ 71] = _PRINT_ITEM
|
1921
|
+
DISPATCH[ 73] = _PRINT_ITEM_TO
|
1922
|
+
DISPATCH[ 75] = _BINARY_LSHIFT # INPLACE
|
1923
|
+
DISPATCH[ 76] = _BINARY_RSHIFT # INPLACE
|
1924
|
+
DISPATCH[ 77] = _BINARY_AND # INPLACE
|
1925
|
+
DISPATCH[ 78] = _BINARY_XOR # INPLACE
|
1926
|
+
DISPATCH[ 79] = _BINARY_OR # INPLACE
|
1927
|
+
DISPATCH[ 83] = _RETURN_VALUE
|
1928
|
+
DISPATCH[ 84] = _IMPORT_STAR
|
1929
|
+
DISPATCH[ 85] = _EXEC_STMT
|
1930
|
+
DISPATCH[ 88] = _END_FINALLY
|
1931
|
+
DISPATCH[ 89] = _BUILD_CLASS
|
1932
|
+
DISPATCH[ 90] = _STORE_NAME
|
1933
|
+
DISPATCH[ 91] = _DELETE_NAME
|
1934
|
+
DISPATCH[ 92] = _UNPACK_SEQUENCE
|
1935
|
+
DISPATCH[ 93] = _FOR_ITER
|
1936
|
+
DISPATCH[ 95] = _STORE_ATTR
|
1937
|
+
DISPATCH[ 96] = _DELETE_ATTR
|
1938
|
+
DISPATCH[ 97] = _STORE_GLOBAL
|
1939
|
+
DISPATCH[ 98] = _DELETE_GLOBAL
|
1940
|
+
DISPATCH[100] = _LOAD_CONST
|
1941
|
+
DISPATCH[101] = _LOAD_NAME
|
1942
|
+
DISPATCH[102] = _BUILD_TUPLE
|
1943
|
+
DISPATCH[103] = _BUILD_LIST
|
1944
|
+
DISPATCH[104] = _BUILD_MAP
|
1945
|
+
DISPATCH[105] = _LOAD_ATTR
|
1946
|
+
DISPATCH[106] = _COMPARE_OP
|
1947
|
+
DISPATCH[107] = _IMPORT_NAME
|
1948
|
+
DISPATCH[108] = _IMPORT_FROM
|
1949
|
+
DISPATCH[110] = _JUMP_FORWARD
|
1950
|
+
DISPATCH[111] = _JUMP_IF_FALSE
|
1951
|
+
DISPATCH[112] = _JUMP_IF_TRUE
|
1952
|
+
DISPATCH[113] = _JUMP_ABSOLUTE
|
1953
|
+
DISPATCH[114] = _FOR_LOOP
|
1954
|
+
DISPATCH[116] = _LOAD_GLOBAL
|
1955
|
+
DISPATCH[121] = _SETUP_EXCEPT
|
1956
|
+
DISPATCH[122] = _SETUP_FINALLY
|
1957
|
+
DISPATCH[124] = _LOAD_FAST
|
1958
|
+
DISPATCH[125] = _STORE_FAST
|
1959
|
+
DISPATCH[126] = _DELETE_FAST
|
1960
|
+
DISPATCH[127] = _LINE_NUM
|
1961
|
+
DISPATCH[130] = _RAISE_VARARGS
|
1962
|
+
DISPATCH[131] = _CALL_FUNCTION
|
1963
|
+
DISPATCH[132] = _MAKE_FUNCTION
|
1964
|
+
DISPATCH[134] = _MAKE_CLOSURE
|
1965
|
+
DISPATCH[135] = _LOAD_CLOSURE
|
1966
|
+
DISPATCH[136] = _LOAD_DEREF
|
1967
|
+
DISPATCH[140] = _CALL_FUNCTION_VAR
|
1968
|
+
DISPATCH[141] = _CALL_FUNCTION_KW
|
1969
|
+
DISPATCH[142] = _CALL_FUNCTION_VAR_KW
|