bee_python 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (503) hide show
  1. data/LICENSE +202 -0
  2. data/build/README +23 -0
  3. data/egg/egg/build.yml +70 -0
  4. data/egg/egg/ez_setup.py +280 -0
  5. data/egg/egg/script.py +12 -0
  6. data/egg/egg/setup.erb +11 -0
  7. data/egg/egg/suite.py +37 -0
  8. data/egg/egg/test.py +31 -0
  9. data/egg/egg.yml +69 -0
  10. data/egg/http/build.erb +53 -0
  11. data/egg/http/server.py +34 -0
  12. data/egg/http.yml +50 -0
  13. data/egg/mysql/mysql.py +43 -0
  14. data/egg/mysql.yml +44 -0
  15. data/egg/project/build.erb +77 -0
  16. data/egg/project/script.py +42 -0
  17. data/egg/project/test.py +31 -0
  18. data/egg/project.yml +59 -0
  19. data/egg/script/build.erb +35 -0
  20. data/egg/script/script.py +42 -0
  21. data/egg/script.yml +50 -0
  22. data/egg/soap/build.erb +52 -0
  23. data/egg/soap/client.py +18 -0
  24. data/egg/soap/server.py +30 -0
  25. data/egg/soap.yml +58 -0
  26. data/egg/source/source.py +42 -0
  27. data/egg/source.yml +47 -0
  28. data/egg/test/test.py +28 -0
  29. data/egg/test.yml +44 -0
  30. data/egg/xmlrpc/build.erb +52 -0
  31. data/egg/xmlrpc/client.py +22 -0
  32. data/egg/xmlrpc/server.py +24 -0
  33. data/egg/xmlrpc.yml +51 -0
  34. data/lib/bee_task_python.rb +390 -0
  35. data/test/build.yml +16 -0
  36. data/test/tc_bee_task_python.rb +27 -0
  37. data/test/test_build.rb +26 -0
  38. data/test/test_build_listener.rb +62 -0
  39. data/test/ts_bee_python.rb +26 -0
  40. data/tools/common/__init__.py +5 -0
  41. data/tools/common/common/__init__.py +140 -0
  42. data/tools/common/common/__pkginfo__.py +43 -0
  43. data/tools/common/common/adbh.py +35 -0
  44. data/tools/common/common/cache.py +114 -0
  45. data/tools/common/common/changelog.py +234 -0
  46. data/tools/common/common/clcommands.py +181 -0
  47. data/tools/common/common/cli.py +212 -0
  48. data/tools/common/common/compat.py +328 -0
  49. data/tools/common/common/configuration.py +1087 -0
  50. data/tools/common/common/contexts.py +58 -0
  51. data/tools/common/common/corbautils.py +117 -0
  52. data/tools/common/common/daemon.py +171 -0
  53. data/tools/common/common/date.py +279 -0
  54. data/tools/common/common/db.py +49 -0
  55. data/tools/common/common/dbf.py +229 -0
  56. data/tools/common/common/debugger.py +208 -0
  57. data/tools/common/common/decorators.py +190 -0
  58. data/tools/common/common/deprecation.py +118 -0
  59. data/tools/common/common/fileutils.py +409 -0
  60. data/tools/common/common/graph.py +259 -0
  61. data/tools/common/common/html.py +142 -0
  62. data/tools/common/common/interface.py +76 -0
  63. data/tools/common/common/logging_ext.py +166 -0
  64. data/tools/common/common/modutils.py +670 -0
  65. data/tools/common/common/optik_ext.py +383 -0
  66. data/tools/common/common/optparser.py +92 -0
  67. data/tools/common/common/pdf_ext.py +111 -0
  68. data/tools/common/common/proc.py +276 -0
  69. data/tools/common/common/pyro_ext.py +146 -0
  70. data/tools/common/common/pytest.py +754 -0
  71. data/tools/common/common/shellutils.py +383 -0
  72. data/tools/common/common/sphinx_ext.py +87 -0
  73. data/tools/common/common/sphinxutils.py +122 -0
  74. data/tools/common/common/sqlgen.py +31 -0
  75. data/tools/common/common/table.py +930 -0
  76. data/tools/common/common/tasksqueue.py +97 -0
  77. data/tools/common/common/test/__init__.py +1 -0
  78. data/tools/common/common/test/data/ChangeLog +184 -0
  79. data/tools/common/common/test/data/MyPyPa-0.1.0-py2.5.egg +0 -0
  80. data/tools/common/common/test/data/__init__.py +1 -0
  81. data/tools/common/common/test/data/content_differ_dir/NOTHING +0 -0
  82. data/tools/common/common/test/data/content_differ_dir/README +1 -0
  83. data/tools/common/common/test/data/content_differ_dir/subdir/coin +1 -0
  84. data/tools/common/common/test/data/content_differ_dir/subdir/toto.txt +53 -0
  85. data/tools/common/common/test/data/file_differ_dir/NOTHING +0 -0
  86. data/tools/common/common/test/data/file_differ_dir/README +1 -0
  87. data/tools/common/common/test/data/file_differ_dir/subdir/toto.txt +53 -0
  88. data/tools/common/common/test/data/file_differ_dir/subdirtwo/Hello +0 -0
  89. data/tools/common/common/test/data/find_test/__init__.py +0 -0
  90. data/tools/common/common/test/data/find_test/foo.txt +0 -0
  91. data/tools/common/common/test/data/find_test/module.py +0 -0
  92. data/tools/common/common/test/data/find_test/module2.py +0 -0
  93. data/tools/common/common/test/data/find_test/newlines.txt +0 -0
  94. data/tools/common/common/test/data/find_test/noendingnewline.py +0 -0
  95. data/tools/common/common/test/data/find_test/nonregr.py +0 -0
  96. data/tools/common/common/test/data/find_test/normal_file.txt +0 -0
  97. data/tools/common/common/test/data/find_test/spam.txt +0 -0
  98. data/tools/common/common/test/data/find_test/sub/doc.txt +0 -0
  99. data/tools/common/common/test/data/find_test/sub/momo.py +0 -0
  100. data/tools/common/common/test/data/find_test/test.ini +0 -0
  101. data/tools/common/common/test/data/find_test/test1.msg +0 -0
  102. data/tools/common/common/test/data/find_test/test2.msg +0 -0
  103. data/tools/common/common/test/data/find_test/write_protected_file.txt +0 -0
  104. data/tools/common/common/test/data/foo.txt +9 -0
  105. data/tools/common/common/test/data/module.py +88 -0
  106. data/tools/common/common/test/data/module2.py +77 -0
  107. data/tools/common/common/test/data/newlines.txt +3 -0
  108. data/tools/common/common/test/data/noendingnewline.py +36 -0
  109. data/tools/common/common/test/data/nonregr.py +14 -0
  110. data/tools/common/common/test/data/normal_file.txt +0 -0
  111. data/tools/common/common/test/data/reference_dir/NOTHING +0 -0
  112. data/tools/common/common/test/data/reference_dir/README +1 -0
  113. data/tools/common/common/test/data/reference_dir/subdir/coin +1 -0
  114. data/tools/common/common/test/data/reference_dir/subdir/toto.txt +53 -0
  115. data/tools/common/common/test/data/same_dir/NOTHING +0 -0
  116. data/tools/common/common/test/data/same_dir/README +1 -0
  117. data/tools/common/common/test/data/same_dir/subdir/coin +1 -0
  118. data/tools/common/common/test/data/same_dir/subdir/toto.txt +53 -0
  119. data/tools/common/common/test/data/spam.txt +9 -0
  120. data/tools/common/common/test/data/sub/doc.txt +1 -0
  121. data/tools/common/common/test/data/sub/momo.py +1 -0
  122. data/tools/common/common/test/data/subdir_differ_dir/NOTHING +0 -0
  123. data/tools/common/common/test/data/subdir_differ_dir/README +1 -0
  124. data/tools/common/common/test/data/subdir_differ_dir/subdir/coin +1 -0
  125. data/tools/common/common/test/data/subdir_differ_dir/subdir/toto.txt +53 -0
  126. data/tools/common/common/test/data/test.ini +20 -0
  127. data/tools/common/common/test/data/test1.msg +30 -0
  128. data/tools/common/common/test/data/test2.msg +42 -0
  129. data/tools/common/common/test/data/write_protected_file.txt +0 -0
  130. data/tools/common/common/test/foomod.py +17 -0
  131. data/tools/common/common/test/unittest_cache.py +129 -0
  132. data/tools/common/common/test/unittest_changelog.py +37 -0
  133. data/tools/common/common/test/unittest_compat.py +239 -0
  134. data/tools/common/common/test/unittest_configuration.py +348 -0
  135. data/tools/common/common/test/unittest_date.py +154 -0
  136. data/tools/common/common/test/unittest_decorators.py +62 -0
  137. data/tools/common/common/test/unittest_deprecation.py +76 -0
  138. data/tools/common/common/test/unittest_fileutils.py +133 -0
  139. data/tools/common/common/test/unittest_graph.py +50 -0
  140. data/tools/common/common/test/unittest_html.py +76 -0
  141. data/tools/common/common/test/unittest_interface.py +87 -0
  142. data/tools/common/common/test/unittest_modutils.py +244 -0
  143. data/tools/common/common/test/unittest_pytest.py +50 -0
  144. data/tools/common/common/test/unittest_shellutils.py +248 -0
  145. data/tools/common/common/test/unittest_table.py +448 -0
  146. data/tools/common/common/test/unittest_taskqueue.py +71 -0
  147. data/tools/common/common/test/unittest_testlib.py +956 -0
  148. data/tools/common/common/test/unittest_textutils.py +247 -0
  149. data/tools/common/common/test/unittest_tree.py +248 -0
  150. data/tools/common/common/test/unittest_umessage.py +55 -0
  151. data/tools/common/common/test/unittest_ureports_html.py +64 -0
  152. data/tools/common/common/test/unittest_ureports_text.py +105 -0
  153. data/tools/common/common/test/unittest_xmlutils.py +75 -0
  154. data/tools/common/common/test/utils.py +87 -0
  155. data/tools/common/common/testlib.py +1927 -0
  156. data/tools/common/common/textutils.py +476 -0
  157. data/tools/common/common/tree.py +372 -0
  158. data/tools/common/common/umessage.py +161 -0
  159. data/tools/common/common/ureports/__init__.py +174 -0
  160. data/tools/common/common/ureports/docbook_writer.py +139 -0
  161. data/tools/common/common/ureports/html_writer.py +131 -0
  162. data/tools/common/common/ureports/nodes.py +201 -0
  163. data/tools/common/common/ureports/text_writer.py +140 -0
  164. data/tools/common/common/vcgutils.py +216 -0
  165. data/tools/common/common/visitor.py +107 -0
  166. data/tools/common/common/xmlrpcutils.py +136 -0
  167. data/tools/common/common/xmlutils.py +61 -0
  168. data/tools/compile/compile.py +16 -0
  169. data/tools/coverage/coverage.py +602 -0
  170. data/tools/epydoc/__init__.py +227 -0
  171. data/tools/epydoc/__init__.pyc +0 -0
  172. data/tools/epydoc/apidoc.py +2203 -0
  173. data/tools/epydoc/apidoc.pyc +0 -0
  174. data/tools/epydoc/checker.py +349 -0
  175. data/tools/epydoc/checker.pyc +0 -0
  176. data/tools/epydoc/cli.py +1470 -0
  177. data/tools/epydoc/cli.pyc +0 -0
  178. data/tools/epydoc/compat.py +250 -0
  179. data/tools/epydoc/compat.pyc +0 -0
  180. data/tools/epydoc/docbuilder.py +1358 -0
  181. data/tools/epydoc/docbuilder.pyc +0 -0
  182. data/tools/epydoc/docintrospecter.py +1056 -0
  183. data/tools/epydoc/docintrospecter.pyc +0 -0
  184. data/tools/epydoc/docparser.py +2113 -0
  185. data/tools/epydoc/docparser.pyc +0 -0
  186. data/tools/epydoc/docstringparser.py +1111 -0
  187. data/tools/epydoc/docstringparser.pyc +0 -0
  188. data/tools/epydoc/docwriter/__init__.py +12 -0
  189. data/tools/epydoc/docwriter/__init__.pyc +0 -0
  190. data/tools/epydoc/docwriter/dotgraph.py +1351 -0
  191. data/tools/epydoc/docwriter/dotgraph.pyc +0 -0
  192. data/tools/epydoc/docwriter/html.py +3491 -0
  193. data/tools/epydoc/docwriter/html.pyc +0 -0
  194. data/tools/epydoc/docwriter/html_colorize.py +909 -0
  195. data/tools/epydoc/docwriter/html_colorize.pyc +0 -0
  196. data/tools/epydoc/docwriter/html_css.py +550 -0
  197. data/tools/epydoc/docwriter/html_css.pyc +0 -0
  198. data/tools/epydoc/docwriter/html_help.py +190 -0
  199. data/tools/epydoc/docwriter/html_help.pyc +0 -0
  200. data/tools/epydoc/docwriter/latex.py +1187 -0
  201. data/tools/epydoc/docwriter/latex.pyc +0 -0
  202. data/tools/epydoc/docwriter/plaintext.py +276 -0
  203. data/tools/epydoc/docwriter/plaintext.pyc +0 -0
  204. data/tools/epydoc/docwriter/xlink.py +505 -0
  205. data/tools/epydoc/docwriter/xlink.pyc +0 -0
  206. data/tools/epydoc/gui.py +1148 -0
  207. data/tools/epydoc/gui.pyc +0 -0
  208. data/tools/epydoc/log.py +204 -0
  209. data/tools/epydoc/log.pyc +0 -0
  210. data/tools/epydoc/markup/__init__.py +623 -0
  211. data/tools/epydoc/markup/__init__.pyc +0 -0
  212. data/tools/epydoc/markup/doctest.py +311 -0
  213. data/tools/epydoc/markup/doctest.pyc +0 -0
  214. data/tools/epydoc/markup/epytext.py +2116 -0
  215. data/tools/epydoc/markup/epytext.pyc +0 -0
  216. data/tools/epydoc/markup/javadoc.py +250 -0
  217. data/tools/epydoc/markup/javadoc.pyc +0 -0
  218. data/tools/epydoc/markup/plaintext.py +78 -0
  219. data/tools/epydoc/markup/plaintext.pyc +0 -0
  220. data/tools/epydoc/markup/pyval_repr.py +532 -0
  221. data/tools/epydoc/markup/pyval_repr.pyc +0 -0
  222. data/tools/epydoc/markup/restructuredtext.py +906 -0
  223. data/tools/epydoc/markup/restructuredtext.pyc +0 -0
  224. data/tools/epydoc/test/__init__.py +97 -0
  225. data/tools/epydoc/test/__init__.pyc +0 -0
  226. data/tools/epydoc/test/util.py +226 -0
  227. data/tools/epydoc/test/util.pyc +0 -0
  228. data/tools/epydoc/util.py +289 -0
  229. data/tools/epydoc/util.pyc +0 -0
  230. data/tools/logilab/logilab/__init__.py +5 -0
  231. data/tools/logilab/logilab/astng/__init__.py +82 -0
  232. data/tools/logilab/logilab/astng/__pkginfo__.py +76 -0
  233. data/tools/logilab/logilab/astng/_exceptions.py +64 -0
  234. data/tools/logilab/logilab/astng/_nodes_ast.py +667 -0
  235. data/tools/logilab/logilab/astng/_nodes_compiler.py +758 -0
  236. data/tools/logilab/logilab/astng/bases.py +608 -0
  237. data/tools/logilab/logilab/astng/builder.py +239 -0
  238. data/tools/logilab/logilab/astng/inference.py +426 -0
  239. data/tools/logilab/logilab/astng/inspector.py +289 -0
  240. data/tools/logilab/logilab/astng/manager.py +421 -0
  241. data/tools/logilab/logilab/astng/mixins.py +165 -0
  242. data/tools/logilab/logilab/astng/node_classes.py +848 -0
  243. data/tools/logilab/logilab/astng/nodes.py +85 -0
  244. data/tools/logilab/logilab/astng/nodes_as_string.py +389 -0
  245. data/tools/logilab/logilab/astng/patchcomptransformer.py +159 -0
  246. data/tools/logilab/logilab/astng/protocols.py +333 -0
  247. data/tools/logilab/logilab/astng/raw_building.py +212 -0
  248. data/tools/logilab/logilab/astng/rebuilder.py +307 -0
  249. data/tools/logilab/logilab/astng/scoped_nodes.py +951 -0
  250. data/tools/logilab/logilab/astng/test/__init__.py +19 -0
  251. data/tools/logilab/logilab/astng/test/data/MyPyPa-0.1.0-py2.5.egg +0 -0
  252. data/tools/logilab/logilab/astng/test/data/MyPyPa-0.1.0-py2.5.zip +0 -0
  253. data/tools/logilab/logilab/astng/test/data/SSL1/Connection1.py +33 -0
  254. data/tools/logilab/logilab/astng/test/data/SSL1/__init__.py +20 -0
  255. data/tools/logilab/logilab/astng/test/data/__init__.py +20 -0
  256. data/tools/logilab/logilab/astng/test/data/all.py +29 -0
  257. data/tools/logilab/logilab/astng/test/data/appl/__init__.py +23 -0
  258. data/tools/logilab/logilab/astng/test/data/appl/myConnection.py +30 -0
  259. data/tools/logilab/logilab/astng/test/data/format.py +34 -0
  260. data/tools/logilab/logilab/astng/test/data/module.py +90 -0
  261. data/tools/logilab/logilab/astng/test/data/module2.py +112 -0
  262. data/tools/logilab/logilab/astng/test/data/noendingnewline.py +57 -0
  263. data/tools/logilab/logilab/astng/test/data/nonregr.py +76 -0
  264. data/tools/logilab/logilab/astng/test/data/notall.py +28 -0
  265. data/tools/logilab/logilab/astng/test/data2/__init__.py +20 -0
  266. data/tools/logilab/logilab/astng/test/data2/clientmodule_test.py +51 -0
  267. data/tools/logilab/logilab/astng/test/data2/suppliermodule_test.py +32 -0
  268. data/tools/logilab/logilab/astng/test/regrtest.py +135 -0
  269. data/tools/logilab/logilab/astng/test/regrtest_data/absimport.py +22 -0
  270. data/tools/logilab/logilab/astng/test/regrtest_data/descriptor_crash.py +31 -0
  271. data/tools/logilab/logilab/astng/test/regrtest_data/import_package_subpackage_module.py +68 -0
  272. data/tools/logilab/logilab/astng/test/regrtest_data/package/__init__.py +24 -0
  273. data/tools/logilab/logilab/astng/test/regrtest_data/package/subpackage/__init__.py +20 -0
  274. data/tools/logilab/logilab/astng/test/regrtest_data/package/subpackage/module.py +20 -0
  275. data/tools/logilab/logilab/astng/test/unittest_builder.py +684 -0
  276. data/tools/logilab/logilab/astng/test/unittest_inference.py +1112 -0
  277. data/tools/logilab/logilab/astng/test/unittest_inspector.py +105 -0
  278. data/tools/logilab/logilab/astng/test/unittest_lookup.py +302 -0
  279. data/tools/logilab/logilab/astng/test/unittest_manager.py +98 -0
  280. data/tools/logilab/logilab/astng/test/unittest_nodes.py +302 -0
  281. data/tools/logilab/logilab/astng/test/unittest_scoped_nodes.py +501 -0
  282. data/tools/logilab/logilab/astng/test/unittest_utils.py +104 -0
  283. data/tools/logilab/logilab/astng/utils.py +342 -0
  284. data/tools/logilab/logilab/common/__init__.py +140 -0
  285. data/tools/logilab/logilab/common/__pkginfo__.py +43 -0
  286. data/tools/logilab/logilab/common/adbh.py +35 -0
  287. data/tools/logilab/logilab/common/cache.py +114 -0
  288. data/tools/logilab/logilab/common/changelog.py +234 -0
  289. data/tools/logilab/logilab/common/clcommands.py +181 -0
  290. data/tools/logilab/logilab/common/cli.py +212 -0
  291. data/tools/logilab/logilab/common/compat.py +328 -0
  292. data/tools/logilab/logilab/common/configuration.py +1087 -0
  293. data/tools/logilab/logilab/common/contexts.py +58 -0
  294. data/tools/logilab/logilab/common/corbautils.py +117 -0
  295. data/tools/logilab/logilab/common/daemon.py +171 -0
  296. data/tools/logilab/logilab/common/date.py +279 -0
  297. data/tools/logilab/logilab/common/db.py +49 -0
  298. data/tools/logilab/logilab/common/dbf.py +229 -0
  299. data/tools/logilab/logilab/common/debugger.py +208 -0
  300. data/tools/logilab/logilab/common/decorators.py +190 -0
  301. data/tools/logilab/logilab/common/deprecation.py +118 -0
  302. data/tools/logilab/logilab/common/fileutils.py +409 -0
  303. data/tools/logilab/logilab/common/graph.py +259 -0
  304. data/tools/logilab/logilab/common/html.py +142 -0
  305. data/tools/logilab/logilab/common/interface.py +76 -0
  306. data/tools/logilab/logilab/common/logging_ext.py +166 -0
  307. data/tools/logilab/logilab/common/modutils.py +670 -0
  308. data/tools/logilab/logilab/common/optik_ext.py +383 -0
  309. data/tools/logilab/logilab/common/optparser.py +92 -0
  310. data/tools/logilab/logilab/common/pdf_ext.py +111 -0
  311. data/tools/logilab/logilab/common/proc.py +276 -0
  312. data/tools/logilab/logilab/common/pyro_ext.py +146 -0
  313. data/tools/logilab/logilab/common/pytest.py +754 -0
  314. data/tools/logilab/logilab/common/shellutils.py +383 -0
  315. data/tools/logilab/logilab/common/sphinx_ext.py +87 -0
  316. data/tools/logilab/logilab/common/sphinxutils.py +122 -0
  317. data/tools/logilab/logilab/common/sqlgen.py +31 -0
  318. data/tools/logilab/logilab/common/table.py +930 -0
  319. data/tools/logilab/logilab/common/tasksqueue.py +97 -0
  320. data/tools/logilab/logilab/common/test/__init__.py +1 -0
  321. data/tools/logilab/logilab/common/test/data/ChangeLog +184 -0
  322. data/tools/logilab/logilab/common/test/data/MyPyPa-0.1.0-py2.5.egg +0 -0
  323. data/tools/logilab/logilab/common/test/data/__init__.py +1 -0
  324. data/tools/logilab/logilab/common/test/data/content_differ_dir/NOTHING +0 -0
  325. data/tools/logilab/logilab/common/test/data/content_differ_dir/README +1 -0
  326. data/tools/logilab/logilab/common/test/data/content_differ_dir/subdir/coin +1 -0
  327. data/tools/logilab/logilab/common/test/data/content_differ_dir/subdir/toto.txt +53 -0
  328. data/tools/logilab/logilab/common/test/data/file_differ_dir/NOTHING +0 -0
  329. data/tools/logilab/logilab/common/test/data/file_differ_dir/README +1 -0
  330. data/tools/logilab/logilab/common/test/data/file_differ_dir/subdir/toto.txt +53 -0
  331. data/tools/logilab/logilab/common/test/data/file_differ_dir/subdirtwo/Hello +0 -0
  332. data/tools/logilab/logilab/common/test/data/find_test/__init__.py +0 -0
  333. data/tools/logilab/logilab/common/test/data/find_test/foo.txt +0 -0
  334. data/tools/logilab/logilab/common/test/data/find_test/module.py +0 -0
  335. data/tools/logilab/logilab/common/test/data/find_test/module2.py +0 -0
  336. data/tools/logilab/logilab/common/test/data/find_test/newlines.txt +0 -0
  337. data/tools/logilab/logilab/common/test/data/find_test/noendingnewline.py +0 -0
  338. data/tools/logilab/logilab/common/test/data/find_test/nonregr.py +0 -0
  339. data/tools/logilab/logilab/common/test/data/find_test/normal_file.txt +0 -0
  340. data/tools/logilab/logilab/common/test/data/find_test/spam.txt +0 -0
  341. data/tools/logilab/logilab/common/test/data/find_test/sub/doc.txt +0 -0
  342. data/tools/logilab/logilab/common/test/data/find_test/sub/momo.py +0 -0
  343. data/tools/logilab/logilab/common/test/data/find_test/test.ini +0 -0
  344. data/tools/logilab/logilab/common/test/data/find_test/test1.msg +0 -0
  345. data/tools/logilab/logilab/common/test/data/find_test/test2.msg +0 -0
  346. data/tools/logilab/logilab/common/test/data/find_test/write_protected_file.txt +0 -0
  347. data/tools/logilab/logilab/common/test/data/foo.txt +9 -0
  348. data/tools/logilab/logilab/common/test/data/module.py +88 -0
  349. data/tools/logilab/logilab/common/test/data/module2.py +77 -0
  350. data/tools/logilab/logilab/common/test/data/newlines.txt +3 -0
  351. data/tools/logilab/logilab/common/test/data/noendingnewline.py +36 -0
  352. data/tools/logilab/logilab/common/test/data/nonregr.py +14 -0
  353. data/tools/logilab/logilab/common/test/data/normal_file.txt +0 -0
  354. data/tools/logilab/logilab/common/test/data/reference_dir/NOTHING +0 -0
  355. data/tools/logilab/logilab/common/test/data/reference_dir/README +1 -0
  356. data/tools/logilab/logilab/common/test/data/reference_dir/subdir/coin +1 -0
  357. data/tools/logilab/logilab/common/test/data/reference_dir/subdir/toto.txt +53 -0
  358. data/tools/logilab/logilab/common/test/data/same_dir/NOTHING +0 -0
  359. data/tools/logilab/logilab/common/test/data/same_dir/README +1 -0
  360. data/tools/logilab/logilab/common/test/data/same_dir/subdir/coin +1 -0
  361. data/tools/logilab/logilab/common/test/data/same_dir/subdir/toto.txt +53 -0
  362. data/tools/logilab/logilab/common/test/data/spam.txt +9 -0
  363. data/tools/logilab/logilab/common/test/data/sub/doc.txt +1 -0
  364. data/tools/logilab/logilab/common/test/data/sub/momo.py +1 -0
  365. data/tools/logilab/logilab/common/test/data/subdir_differ_dir/NOTHING +0 -0
  366. data/tools/logilab/logilab/common/test/data/subdir_differ_dir/README +1 -0
  367. data/tools/logilab/logilab/common/test/data/subdir_differ_dir/subdir/coin +1 -0
  368. data/tools/logilab/logilab/common/test/data/subdir_differ_dir/subdir/toto.txt +53 -0
  369. data/tools/logilab/logilab/common/test/data/test.ini +20 -0
  370. data/tools/logilab/logilab/common/test/data/test1.msg +30 -0
  371. data/tools/logilab/logilab/common/test/data/test2.msg +42 -0
  372. data/tools/logilab/logilab/common/test/data/write_protected_file.txt +0 -0
  373. data/tools/logilab/logilab/common/test/foomod.py +17 -0
  374. data/tools/logilab/logilab/common/test/unittest_cache.py +129 -0
  375. data/tools/logilab/logilab/common/test/unittest_changelog.py +37 -0
  376. data/tools/logilab/logilab/common/test/unittest_compat.py +239 -0
  377. data/tools/logilab/logilab/common/test/unittest_configuration.py +348 -0
  378. data/tools/logilab/logilab/common/test/unittest_date.py +154 -0
  379. data/tools/logilab/logilab/common/test/unittest_decorators.py +62 -0
  380. data/tools/logilab/logilab/common/test/unittest_deprecation.py +76 -0
  381. data/tools/logilab/logilab/common/test/unittest_fileutils.py +133 -0
  382. data/tools/logilab/logilab/common/test/unittest_graph.py +50 -0
  383. data/tools/logilab/logilab/common/test/unittest_html.py +76 -0
  384. data/tools/logilab/logilab/common/test/unittest_interface.py +87 -0
  385. data/tools/logilab/logilab/common/test/unittest_modutils.py +244 -0
  386. data/tools/logilab/logilab/common/test/unittest_pytest.py +50 -0
  387. data/tools/logilab/logilab/common/test/unittest_shellutils.py +248 -0
  388. data/tools/logilab/logilab/common/test/unittest_table.py +448 -0
  389. data/tools/logilab/logilab/common/test/unittest_taskqueue.py +71 -0
  390. data/tools/logilab/logilab/common/test/unittest_testlib.py +956 -0
  391. data/tools/logilab/logilab/common/test/unittest_textutils.py +247 -0
  392. data/tools/logilab/logilab/common/test/unittest_tree.py +248 -0
  393. data/tools/logilab/logilab/common/test/unittest_umessage.py +55 -0
  394. data/tools/logilab/logilab/common/test/unittest_ureports_html.py +64 -0
  395. data/tools/logilab/logilab/common/test/unittest_ureports_text.py +105 -0
  396. data/tools/logilab/logilab/common/test/unittest_xmlutils.py +75 -0
  397. data/tools/logilab/logilab/common/test/utils.py +87 -0
  398. data/tools/logilab/logilab/common/testlib.py +1927 -0
  399. data/tools/logilab/logilab/common/textutils.py +476 -0
  400. data/tools/logilab/logilab/common/tree.py +372 -0
  401. data/tools/logilab/logilab/common/umessage.py +161 -0
  402. data/tools/logilab/logilab/common/ureports/__init__.py +174 -0
  403. data/tools/logilab/logilab/common/ureports/docbook_writer.py +139 -0
  404. data/tools/logilab/logilab/common/ureports/html_writer.py +131 -0
  405. data/tools/logilab/logilab/common/ureports/nodes.py +201 -0
  406. data/tools/logilab/logilab/common/ureports/text_writer.py +140 -0
  407. data/tools/logilab/logilab/common/vcgutils.py +216 -0
  408. data/tools/logilab/logilab/common/visitor.py +107 -0
  409. data/tools/logilab/logilab/common/xmlrpcutils.py +136 -0
  410. data/tools/logilab/logilab/common/xmlutils.py +61 -0
  411. data/tools/pychecker/COPYRIGHT +31 -0
  412. data/tools/pychecker/ChangeLog +349 -0
  413. data/tools/pychecker/CodeChecks.py +1969 -0
  414. data/tools/pychecker/CodeChecks.pyc +0 -0
  415. data/tools/pychecker/CodeChecks.pyo +0 -0
  416. data/tools/pychecker/Config.py +475 -0
  417. data/tools/pychecker/Config.pyc +0 -0
  418. data/tools/pychecker/Config.pyo +0 -0
  419. data/tools/pychecker/KNOWN_BUGS +100 -0
  420. data/tools/pychecker/MAINTAINERS +81 -0
  421. data/tools/pychecker/NEWS +406 -0
  422. data/tools/pychecker/OP.py +131 -0
  423. data/tools/pychecker/OP.pyc +0 -0
  424. data/tools/pychecker/OP.pyo +0 -0
  425. data/tools/pychecker/OptionTypes.py +117 -0
  426. data/tools/pychecker/OptionTypes.pyc +0 -0
  427. data/tools/pychecker/OptionTypes.pyo +0 -0
  428. data/tools/pychecker/README +152 -0
  429. data/tools/pychecker/Stack.py +115 -0
  430. data/tools/pychecker/Stack.pyc +0 -0
  431. data/tools/pychecker/Stack.pyo +0 -0
  432. data/tools/pychecker/TODO +101 -0
  433. data/tools/pychecker/VERSION +1 -0
  434. data/tools/pychecker/Warning.py +50 -0
  435. data/tools/pychecker/Warning.pyc +0 -0
  436. data/tools/pychecker/Warning.pyo +0 -0
  437. data/tools/pychecker/__init__.py +17 -0
  438. data/tools/pychecker/__init__.pyc +0 -0
  439. data/tools/pychecker/__init__.pyo +0 -0
  440. data/tools/pychecker/checker.py +961 -0
  441. data/tools/pychecker/checker.pyc +0 -0
  442. data/tools/pychecker/checker.pyo +0 -0
  443. data/tools/pychecker/function.py +159 -0
  444. data/tools/pychecker/function.pyc +0 -0
  445. data/tools/pychecker/function.pyo +0 -0
  446. data/tools/pychecker/msgs.py +175 -0
  447. data/tools/pychecker/msgs.pyc +0 -0
  448. data/tools/pychecker/msgs.pyo +0 -0
  449. data/tools/pychecker/options.py +275 -0
  450. data/tools/pychecker/options.pyc +0 -0
  451. data/tools/pychecker/options.pyo +0 -0
  452. data/tools/pychecker/pcmodules.py +19 -0
  453. data/tools/pychecker/pcmodules.pyc +0 -0
  454. data/tools/pychecker/pcmodules.pyo +0 -0
  455. data/tools/pychecker/printer.py +47 -0
  456. data/tools/pychecker/printer.pyc +0 -0
  457. data/tools/pychecker/printer.pyo +0 -0
  458. data/tools/pychecker/python.py +427 -0
  459. data/tools/pychecker/python.pyc +0 -0
  460. data/tools/pychecker/python.pyo +0 -0
  461. data/tools/pychecker/utils.py +102 -0
  462. data/tools/pychecker/utils.pyc +0 -0
  463. data/tools/pychecker/utils.pyo +0 -0
  464. data/tools/pychecker/warn.py +778 -0
  465. data/tools/pychecker/warn.pyc +0 -0
  466. data/tools/pychecker/warn.pyo +0 -0
  467. data/tools/pylint2/pylint/__init__.py +16 -0
  468. data/tools/pylint2/pylint/__pkginfo__.py +67 -0
  469. data/tools/pylint2/pylint/checkers/__init__.py +155 -0
  470. data/tools/pylint2/pylint/checkers/base.py +749 -0
  471. data/tools/pylint2/pylint/checkers/classes.py +527 -0
  472. data/tools/pylint2/pylint/checkers/design_analysis.py +344 -0
  473. data/tools/pylint2/pylint/checkers/exceptions.py +183 -0
  474. data/tools/pylint2/pylint/checkers/format.py +367 -0
  475. data/tools/pylint2/pylint/checkers/imports.py +379 -0
  476. data/tools/pylint2/pylint/checkers/logging.py +98 -0
  477. data/tools/pylint2/pylint/checkers/misc.py +128 -0
  478. data/tools/pylint2/pylint/checkers/newstyle.py +107 -0
  479. data/tools/pylint2/pylint/checkers/raw_metrics.py +125 -0
  480. data/tools/pylint2/pylint/checkers/similar.py +333 -0
  481. data/tools/pylint2/pylint/checkers/string_format.py +239 -0
  482. data/tools/pylint2/pylint/checkers/typecheck.py +364 -0
  483. data/tools/pylint2/pylint/checkers/utils.py +208 -0
  484. data/tools/pylint2/pylint/checkers/variables.py +498 -0
  485. data/tools/pylint2/pylint/config.py +149 -0
  486. data/tools/pylint2/pylint/epylint.py +149 -0
  487. data/tools/pylint2/pylint/gui.py +433 -0
  488. data/tools/pylint2/pylint/interfaces.py +98 -0
  489. data/tools/pylint2/pylint/lint.py +914 -0
  490. data/tools/pylint2/pylint/pyreverse/__init__.py +5 -0
  491. data/tools/pylint2/pylint/pyreverse/diadefslib.py +229 -0
  492. data/tools/pylint2/pylint/pyreverse/diagrams.py +247 -0
  493. data/tools/pylint2/pylint/pyreverse/main.py +123 -0
  494. data/tools/pylint2/pylint/pyreverse/utils.py +131 -0
  495. data/tools/pylint2/pylint/pyreverse/writer.py +196 -0
  496. data/tools/pylint2/pylint/reporters/__init__.py +67 -0
  497. data/tools/pylint2/pylint/reporters/guireporter.py +36 -0
  498. data/tools/pylint2/pylint/reporters/html.py +69 -0
  499. data/tools/pylint2/pylint/reporters/text.py +156 -0
  500. data/tools/pylint2/pylint/utils.py +518 -0
  501. data/tools/pylint2/pylint.py +16 -0
  502. data/tools/test/suite.py +35 -0
  503. metadata +566 -0
@@ -0,0 +1,1927 @@
1
+ # -*- coding: utf-8 -*-
2
+ # copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
3
+ # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
4
+ #
5
+ # This file is part of logilab-common.
6
+ #
7
+ # logilab-common is free software: you can redistribute it and/or modify it under
8
+ # the terms of the GNU Lesser General Public License as published by the Free
9
+ # Software Foundation, either version 2.1 of the License, or (at your option) any
10
+ # later version.
11
+ #
12
+ # logilab-common is distributed in the hope that it will be useful, but WITHOUT
13
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14
+ # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
15
+ # details.
16
+ #
17
+ # You should have received a copy of the GNU Lesser General Public License along
18
+ # with logilab-common. If not, see <http://www.gnu.org/licenses/>.
19
+ """Run tests.
20
+
21
+ This will find all modules whose name match a given prefix in the test
22
+ directory, and run them. Various command line options provide
23
+ additional facilities.
24
+
25
+ Command line options:
26
+
27
+ -v verbose -- run tests in verbose mode with output to stdout
28
+ -q quiet -- don't print anything except if a test fails
29
+ -t testdir -- directory where the tests will be found
30
+ -x exclude -- add a test to exclude
31
+ -p profile -- profiled execution
32
+ -c capture -- capture standard out/err during tests
33
+ -d dbc -- enable design-by-contract
34
+ -m match -- only run test matching the tag pattern which follow
35
+
36
+ If no non-option arguments are present, prefixes used are 'test',
37
+ 'regrtest', 'smoketest' and 'unittest'.
38
+
39
+ """
40
+ __docformat__ = "restructuredtext en"
41
+ # modified copy of some functions from test/regrtest.py from PyXml
42
+ # disable camel case warning
43
+ # pylint: disable-msg=C0103
44
+
45
+ import sys
46
+ import os, os.path as osp
47
+ import re
48
+ import time
49
+ import getopt
50
+ import traceback
51
+ import inspect
52
+ import unittest
53
+ import difflib
54
+ import types
55
+ import tempfile
56
+ import math
57
+ from shutil import rmtree
58
+ from operator import itemgetter
59
+ import warnings
60
+ from compiler.consts import CO_GENERATOR
61
+ from ConfigParser import ConfigParser
62
+ from itertools import dropwhile
63
+ from functools import wraps
64
+
65
+ try:
66
+ from test import test_support
67
+ except ImportError:
68
+ # not always available
69
+ class TestSupport:
70
+ def unload(self, test):
71
+ pass
72
+ test_support = TestSupport()
73
+
74
+ # pylint: disable-msg=W0622
75
+ from logilab.common.compat import set, enumerate, any, sorted
76
+ # pylint: enable-msg=W0622
77
+ from logilab.common.modutils import load_module_from_name
78
+ from logilab.common.debugger import Debugger, colorize_source
79
+ from logilab.common.decorators import cached, classproperty
80
+ from logilab.common import textutils
81
+
82
+
83
+ __all__ = ['main', 'unittest_main', 'find_tests', 'run_test', 'spawn']
84
+
85
+ DEFAULT_PREFIXES = ('test', 'regrtest', 'smoketest', 'unittest',
86
+ 'func', 'validation')
87
+
88
+ ENABLE_DBC = False
89
+
90
+ FILE_RESTART = ".pytest.restart"
91
+
92
+ # used by unittest to count the number of relevant levels in the traceback
93
+ __unittest = 1
94
+
95
+
96
+ def with_tempdir(callable):
97
+ """A decorator ensuring no temporary file left when the function return
98
+ Work only for temporary file create with the tempfile module"""
99
+ @wraps(callable)
100
+ def proxy(*args, **kargs):
101
+
102
+ old_tmpdir = tempfile.gettempdir()
103
+ new_tmpdir = tempfile.mkdtemp(prefix="temp-lgc-")
104
+ tempfile.tempdir = new_tmpdir
105
+ try:
106
+ return callable(*args, **kargs)
107
+ finally:
108
+ try:
109
+ rmtree(new_tmpdir, ignore_errors=True)
110
+ finally:
111
+ tempfile.tempdir = old_tmpdir
112
+ return proxy
113
+
114
+ def in_tempdir(callable):
115
+ """A decorator moving the enclosed function inside the tempfile.tempfdir
116
+ """
117
+ @wraps(callable)
118
+ def proxy(*args, **kargs):
119
+
120
+ old_cwd = os.getcwd()
121
+ os.chdir(tempfile.tempdir)
122
+ try:
123
+ return callable(*args, **kargs)
124
+ finally:
125
+ os.chdir(old_cwd)
126
+ return proxy
127
+
128
+ def within_tempdir(callable):
129
+ """A decorator run the enclosed function inside a tmpdir removed after execution
130
+ """
131
+ proxy = with_tempdir(in_tempdir(callable))
132
+ proxy.__name__ = callable.__name__
133
+ return proxy
134
+
135
+ def run_tests(tests, quiet, verbose, runner=None, capture=0):
136
+ """Execute a list of tests.
137
+
138
+ :rtype: tuple
139
+ :return: tuple (list of passed tests, list of failed tests, list of skipped tests)
140
+ """
141
+ good = []
142
+ bad = []
143
+ skipped = []
144
+ all_result = None
145
+ for test in tests:
146
+ if not quiet:
147
+ print
148
+ print '-'*80
149
+ print "Executing", test
150
+ result = run_test(test, verbose, runner, capture)
151
+ if type(result) is type(''):
152
+ # an unexpected error occurred
153
+ skipped.append( (test, result))
154
+ else:
155
+ if all_result is None:
156
+ all_result = result
157
+ else:
158
+ all_result.testsRun += result.testsRun
159
+ all_result.failures += result.failures
160
+ all_result.errors += result.errors
161
+ all_result.skipped += result.skipped
162
+ if result.errors or result.failures:
163
+ bad.append(test)
164
+ if verbose:
165
+ print "test", test, \
166
+ "failed -- %s errors, %s failures" % (
167
+ len(result.errors), len(result.failures))
168
+ else:
169
+ good.append(test)
170
+
171
+ return good, bad, skipped, all_result
172
+
173
+ def find_tests(testdir,
174
+ prefixes=DEFAULT_PREFIXES, suffix=".py",
175
+ excludes=(),
176
+ remove_suffix=True):
177
+ """
178
+ Return a list of all applicable test modules.
179
+ """
180
+ tests = []
181
+ for name in os.listdir(testdir):
182
+ if not suffix or name.endswith(suffix):
183
+ for prefix in prefixes:
184
+ if name.startswith(prefix):
185
+ if remove_suffix and name.endswith(suffix):
186
+ name = name[:-len(suffix)]
187
+ if name not in excludes:
188
+ tests.append(name)
189
+ tests.sort()
190
+ return tests
191
+
192
+
193
+ def run_test(test, verbose, runner=None, capture=0):
194
+ """
195
+ Run a single test.
196
+
197
+ test -- the name of the test
198
+ verbose -- if true, print more messages
199
+ """
200
+ test_support.unload(test)
201
+ try:
202
+ m = load_module_from_name(test, path=sys.path)
203
+ # m = __import__(test, globals(), locals(), sys.path)
204
+ try:
205
+ suite = m.suite
206
+ if callable(suite):
207
+ suite = suite()
208
+ except AttributeError:
209
+ loader = unittest.TestLoader()
210
+ suite = loader.loadTestsFromModule(m)
211
+ if runner is None:
212
+ runner = SkipAwareTextTestRunner(capture=capture) # verbosity=0)
213
+ return runner.run(suite)
214
+ except KeyboardInterrupt, v:
215
+ raise KeyboardInterrupt, v, sys.exc_info()[2]
216
+ except:
217
+ # raise
218
+ type, value = sys.exc_info()[:2]
219
+ msg = "test %s crashed -- %s : %s" % (test, type, value)
220
+ if verbose:
221
+ traceback.print_exc()
222
+ return msg
223
+
224
+ def _count(n, word):
225
+ """format word according to n"""
226
+ if n == 1:
227
+ return "%d %s" % (n, word)
228
+ else:
229
+ return "%d %ss" % (n, word)
230
+
231
+
232
+
233
+
234
+ ## PostMortem Debug facilities #####
235
+ def start_interactive_mode(result):
236
+ """starts an interactive shell so that the user can inspect errors
237
+ """
238
+ debuggers = result.debuggers
239
+ descrs = result.error_descrs + result.fail_descrs
240
+ if len(debuggers) == 1:
241
+ # don't ask for test name if there's only one failure
242
+ debuggers[0].start()
243
+ else:
244
+ while True:
245
+ testindex = 0
246
+ print "Choose a test to debug:"
247
+ # order debuggers in the same way than errors were printed
248
+ print "\n".join(['\t%s : %s' % (i, descr) for i, (_, descr)
249
+ in enumerate(descrs)])
250
+ print "Type 'exit' (or ^D) to quit"
251
+ print
252
+ try:
253
+ todebug = raw_input('Enter a test name: ')
254
+ if todebug.strip().lower() == 'exit':
255
+ print
256
+ break
257
+ else:
258
+ try:
259
+ testindex = int(todebug)
260
+ debugger = debuggers[descrs[testindex][0]]
261
+ except (ValueError, IndexError):
262
+ print "ERROR: invalid test number %r" % (todebug, )
263
+ else:
264
+ debugger.start()
265
+ except (EOFError, KeyboardInterrupt):
266
+ print
267
+ break
268
+
269
+
270
+ # test utils ##################################################################
271
+ from cStringIO import StringIO
272
+
273
+ class SkipAwareTestResult(unittest._TextTestResult):
274
+
275
+ def __init__(self, stream, descriptions, verbosity,
276
+ exitfirst=False, capture=0, printonly=None,
277
+ pdbmode=False, cvg=None, colorize=False):
278
+ super(SkipAwareTestResult, self).__init__(stream,
279
+ descriptions, verbosity)
280
+ self.skipped = []
281
+ self.debuggers = []
282
+ self.fail_descrs = []
283
+ self.error_descrs = []
284
+ self.exitfirst = exitfirst
285
+ self.capture = capture
286
+ self.printonly = printonly
287
+ self.pdbmode = pdbmode
288
+ self.cvg = cvg
289
+ self.colorize = colorize
290
+ self.pdbclass = Debugger
291
+ self.verbose = verbosity > 1
292
+
293
+ def descrs_for(self, flavour):
294
+ return getattr(self, '%s_descrs' % flavour.lower())
295
+
296
+ def _create_pdb(self, test_descr, flavour):
297
+ self.descrs_for(flavour).append( (len(self.debuggers), test_descr) )
298
+ if self.pdbmode:
299
+ self.debuggers.append(self.pdbclass(sys.exc_info()[2]))
300
+
301
+
302
+ def _iter_valid_frames(self, frames):
303
+ """only consider non-testlib frames when formatting traceback"""
304
+ lgc_testlib = osp.abspath(__file__)
305
+ std_testlib = osp.abspath(unittest.__file__)
306
+ invalid = lambda fi: osp.abspath(fi[1]) in (lgc_testlib, std_testlib)
307
+ for frameinfo in dropwhile(invalid, frames):
308
+ yield frameinfo
309
+
310
+ def _exc_info_to_string(self, err, test):
311
+ """Converts a sys.exc_info()-style tuple of values into a string.
312
+
313
+ This method is overridden here because we want to colorize
314
+ lines if --color is passed, and display local variables if
315
+ --verbose is passed
316
+ """
317
+ exctype, exc, tb = err
318
+ output = ['Traceback (most recent call last)']
319
+ frames = inspect.getinnerframes(tb)
320
+ colorize = self.colorize
321
+ frames = enumerate(self._iter_valid_frames(frames))
322
+ for index, (frame, filename, lineno, funcname, ctx, ctxindex) in frames:
323
+ filename = osp.abspath(filename)
324
+ if ctx is None: # pyc files or C extensions for instance
325
+ source = '<no source available>'
326
+ else:
327
+ source = ''.join(ctx)
328
+ if colorize:
329
+ filename = textutils.colorize_ansi(filename, 'magenta')
330
+ source = colorize_source(source)
331
+ output.append(' File "%s", line %s, in %s' % (filename, lineno, funcname))
332
+ output.append(' %s' % source.strip())
333
+ if self.verbose:
334
+ output.append('%r == %r' % (dir(frame), test.__module__))
335
+ output.append('')
336
+ output.append(' ' + ' local variables '.center(66, '-'))
337
+ for varname, value in sorted(frame.f_locals.items()):
338
+ output.append(' %s: %r' % (varname, value))
339
+ if varname == 'self': # special handy processing for self
340
+ for varname, value in sorted(vars(value).items()):
341
+ output.append(' self.%s: %r' % (varname, value))
342
+ output.append(' ' + '-' * 66)
343
+ output.append('')
344
+ output.append(''.join(traceback.format_exception_only(exctype, exc)))
345
+ return '\n'.join(output)
346
+
347
+ def addError(self, test, err):
348
+ """err == (exc_type, exc, tcbk)"""
349
+ exc_type, exc, _ = err #
350
+ if exc_type == TestSkipped:
351
+ self.addSkipped(test, exc)
352
+ else:
353
+ if self.exitfirst:
354
+ self.shouldStop = True
355
+ descr = self.getDescription(test)
356
+ super(SkipAwareTestResult, self).addError(test, err)
357
+ self._create_pdb(descr, 'error')
358
+
359
+ def addFailure(self, test, err):
360
+ if self.exitfirst:
361
+ self.shouldStop = True
362
+ descr = self.getDescription(test)
363
+ super(SkipAwareTestResult, self).addFailure(test, err)
364
+ self._create_pdb(descr, 'fail')
365
+
366
+ def addSkipped(self, test, reason):
367
+ self.skipped.append((test, self.getDescription(test), reason))
368
+ if self.showAll:
369
+ self.stream.writeln("SKIPPED")
370
+ elif self.dots:
371
+ self.stream.write('S')
372
+
373
+ def printErrors(self):
374
+ super(SkipAwareTestResult, self).printErrors()
375
+ self.printSkippedList()
376
+
377
+ def printSkippedList(self):
378
+ for _, descr, err in self.skipped: # test, descr, err
379
+ self.stream.writeln(self.separator1)
380
+ self.stream.writeln("%s: %s" % ('SKIPPED', descr))
381
+ self.stream.writeln("\t%s" % err)
382
+
383
+ def printErrorList(self, flavour, errors):
384
+ for (_, descr), (test, err) in zip(self.descrs_for(flavour), errors):
385
+ self.stream.writeln(self.separator1)
386
+ if self.colorize:
387
+ self.stream.writeln("%s: %s" % (
388
+ textutils.colorize_ansi(flavour, color='red'), descr))
389
+ else:
390
+ self.stream.writeln("%s: %s" % (flavour, descr))
391
+
392
+ self.stream.writeln(self.separator2)
393
+ self.stream.writeln(err)
394
+ try:
395
+ output, errput = test.captured_output()
396
+ except AttributeError:
397
+ pass # original unittest
398
+ else:
399
+ if output:
400
+ self.stream.writeln(self.separator2)
401
+ self.stream.writeln("captured stdout".center(
402
+ len(self.separator2)))
403
+ self.stream.writeln(self.separator2)
404
+ self.stream.writeln(output)
405
+ else:
406
+ self.stream.writeln('no stdout'.center(
407
+ len(self.separator2)))
408
+ if errput:
409
+ self.stream.writeln(self.separator2)
410
+ self.stream.writeln("captured stderr".center(
411
+ len(self.separator2)))
412
+ self.stream.writeln(self.separator2)
413
+ self.stream.writeln(errput)
414
+ else:
415
+ self.stream.writeln('no stderr'.center(
416
+ len(self.separator2)))
417
+
418
+
419
+ def run(self, result, runcondition=None, options=None):
420
+ for test in self._tests:
421
+ if result.shouldStop:
422
+ break
423
+ try:
424
+ test(result, runcondition, options)
425
+ except TypeError:
426
+ # this might happen if a raw unittest.TestCase is defined
427
+ # and used with python (and not pytest)
428
+ warnings.warn("%s should extend lgc.testlib.TestCase instead of unittest.TestCase"
429
+ % test)
430
+ test(result)
431
+ return result
432
+ unittest.TestSuite.run = run
433
+
434
+ # backward compatibility: TestSuite might be imported from lgc.testlib
435
+ TestSuite = unittest.TestSuite
436
+
437
+ # python2.3 compat
438
+ def __call__(self, *args, **kwds):
439
+ return self.run(*args, **kwds)
440
+ unittest.TestSuite.__call__ = __call__
441
+
442
+
443
+ class SkipAwareTextTestRunner(unittest.TextTestRunner):
444
+
445
+ def __init__(self, stream=sys.stderr, verbosity=1,
446
+ exitfirst=False, capture=False, printonly=None,
447
+ pdbmode=False, cvg=None, test_pattern=None,
448
+ skipped_patterns=(), colorize=False, batchmode=False,
449
+ options=None):
450
+ super(SkipAwareTextTestRunner, self).__init__(stream=stream,
451
+ verbosity=verbosity)
452
+ self.exitfirst = exitfirst
453
+ self.capture = capture
454
+ self.printonly = printonly
455
+ self.pdbmode = pdbmode
456
+ self.cvg = cvg
457
+ self.test_pattern = test_pattern
458
+ self.skipped_patterns = skipped_patterns
459
+ self.colorize = colorize
460
+ self.batchmode = batchmode
461
+ self.options = options
462
+
463
+ def _this_is_skipped(self, testedname):
464
+ return any([(pat in testedname) for pat in self.skipped_patterns])
465
+
466
+ def _runcondition(self, test, skipgenerator=True):
467
+ if isinstance(test, InnerTest):
468
+ testname = test.name
469
+ else:
470
+ if isinstance(test, TestCase):
471
+ meth = test._get_test_method()
472
+ func = meth.im_func
473
+ testname = '%s.%s' % (meth.im_class.__name__, func.__name__)
474
+ elif isinstance(test, types.FunctionType):
475
+ func = test
476
+ testname = func.__name__
477
+ elif isinstance(test, types.MethodType):
478
+ func = test.im_func
479
+ testname = '%s.%s' % (test.im_class.__name__, func.__name__)
480
+ else:
481
+ return True # Not sure when this happens
482
+
483
+ if is_generator(func) and skipgenerator:
484
+ return self.does_match_tags(func) # Let inner tests decide at run time
485
+
486
+ # print 'testname', testname, self.test_pattern
487
+ if self._this_is_skipped(testname):
488
+ return False # this was explicitly skipped
489
+ if self.test_pattern is not None:
490
+ try:
491
+ classpattern, testpattern = self.test_pattern.split('.')
492
+ klass, name = testname.split('.')
493
+ if classpattern not in klass or testpattern not in name:
494
+ return False
495
+ except ValueError:
496
+ if self.test_pattern not in testname:
497
+ return False
498
+
499
+ return self.does_match_tags(test)
500
+
501
+ def does_match_tags(self, test):
502
+ if self.options is not None:
503
+ tags_pattern = getattr(self.options, 'tags_pattern', None)
504
+ if tags_pattern is not None:
505
+ tags = getattr(test, 'tags', None)
506
+ if tags is not None:
507
+ return tags.match(tags_pattern)
508
+ if isinstance(test, types.MethodType):
509
+ tags = getattr(test.im_class, 'tags', Tags())
510
+ return tags.match(tags_pattern)
511
+ return False
512
+ return True # no pattern
513
+
514
+ def _makeResult(self):
515
+ return SkipAwareTestResult(self.stream, self.descriptions,
516
+ self.verbosity, self.exitfirst, self.capture,
517
+ self.printonly, self.pdbmode, self.cvg,
518
+ self.colorize)
519
+
520
+ def run(self, test):
521
+ "Run the given test case or test suite."
522
+ result = self._makeResult()
523
+ startTime = time.time()
524
+ test(result, self._runcondition, self.options)
525
+ stopTime = time.time()
526
+ timeTaken = stopTime - startTime
527
+ result.printErrors()
528
+ if not self.batchmode:
529
+ self.stream.writeln(result.separator2)
530
+ run = result.testsRun
531
+ self.stream.writeln("Ran %d test%s in %.3fs" %
532
+ (run, run != 1 and "s" or "", timeTaken))
533
+ self.stream.writeln()
534
+ if not result.wasSuccessful():
535
+ if self.colorize:
536
+ self.stream.write(textutils.colorize_ansi("FAILED", color='red'))
537
+ else:
538
+ self.stream.write("FAILED")
539
+ else:
540
+ if self.colorize:
541
+ self.stream.write(textutils.colorize_ansi("OK", color='green'))
542
+ else:
543
+ self.stream.write("OK")
544
+ failed, errored, skipped = map(len, (result.failures, result.errors,
545
+ result.skipped))
546
+
547
+ det_results = []
548
+ for name, value in (("failures", result.failures),
549
+ ("errors",result.errors),
550
+ ("skipped", result.skipped)):
551
+ if value:
552
+ det_results.append("%s=%i" % (name, len(value)))
553
+ if det_results:
554
+ self.stream.write(" (")
555
+ self.stream.write(', '.join(det_results))
556
+ self.stream.write(")")
557
+ self.stream.writeln("")
558
+ return result
559
+
560
+
561
+ class keywords(dict):
562
+ """Keyword args (**kwargs) support for generative tests."""
563
+
564
+ class starargs(tuple):
565
+ """Variable arguments (*args) for generative tests."""
566
+ def __new__(cls, *args):
567
+ return tuple.__new__(cls, args)
568
+
569
+
570
+
571
+ class NonStrictTestLoader(unittest.TestLoader):
572
+ """
573
+ Overrides default testloader to be able to omit classname when
574
+ specifying tests to run on command line.
575
+
576
+ For example, if the file test_foo.py contains ::
577
+
578
+ class FooTC(TestCase):
579
+ def test_foo1(self): # ...
580
+ def test_foo2(self): # ...
581
+ def test_bar1(self): # ...
582
+
583
+ class BarTC(TestCase):
584
+ def test_bar2(self): # ...
585
+
586
+ 'python test_foo.py' will run the 3 tests in FooTC
587
+ 'python test_foo.py FooTC' will run the 3 tests in FooTC
588
+ 'python test_foo.py test_foo' will run test_foo1 and test_foo2
589
+ 'python test_foo.py test_foo1' will run test_foo1
590
+ 'python test_foo.py test_bar' will run FooTC.test_bar1 and BarTC.test_bar2
591
+ """
592
+
593
+ def __init__(self):
594
+ self.skipped_patterns = []
595
+
596
+ def loadTestsFromNames(self, names, module=None):
597
+ suites = []
598
+ for name in names:
599
+ suites.extend(self.loadTestsFromName(name, module))
600
+ return self.suiteClass(suites)
601
+
602
+ def _collect_tests(self, module):
603
+ tests = {}
604
+ for obj in vars(module).values():
605
+ if (issubclass(type(obj), (types.ClassType, type)) and
606
+ issubclass(obj, unittest.TestCase)):
607
+ classname = obj.__name__
608
+ if classname[0] == '_' or self._this_is_skipped(classname):
609
+ continue
610
+ methodnames = []
611
+ # obj is a TestCase class
612
+ for attrname in dir(obj):
613
+ if attrname.startswith(self.testMethodPrefix):
614
+ attr = getattr(obj, attrname)
615
+ if callable(attr):
616
+ methodnames.append(attrname)
617
+ # keep track of class (obj) for convenience
618
+ tests[classname] = (obj, methodnames)
619
+ return tests
620
+
621
+ def loadTestsFromSuite(self, module, suitename):
622
+ try:
623
+ suite = getattr(module, suitename)()
624
+ except AttributeError:
625
+ return []
626
+ assert hasattr(suite, '_tests'), \
627
+ "%s.%s is not a valid TestSuite" % (module.__name__, suitename)
628
+ # python2.3 does not implement __iter__ on suites, we need to return
629
+ # _tests explicitly
630
+ return suite._tests
631
+
632
+ def loadTestsFromName(self, name, module=None):
633
+ parts = name.split('.')
634
+ if module is None or len(parts) > 2:
635
+ # let the base class do its job here
636
+ return [super(NonStrictTestLoader, self).loadTestsFromName(name)]
637
+ tests = self._collect_tests(module)
638
+ # import pprint
639
+ # pprint.pprint(tests)
640
+ collected = []
641
+ if len(parts) == 1:
642
+ pattern = parts[0]
643
+ if callable(getattr(module, pattern, None)
644
+ ) and pattern not in tests:
645
+ # consider it as a suite
646
+ return self.loadTestsFromSuite(module, pattern)
647
+ if pattern in tests:
648
+ # case python unittest_foo.py MyTestTC
649
+ klass, methodnames = tests[pattern]
650
+ for methodname in methodnames:
651
+ collected = [klass(methodname)
652
+ for methodname in methodnames]
653
+ else:
654
+ # case python unittest_foo.py something
655
+ for klass, methodnames in tests.values():
656
+ collected += [klass(methodname)
657
+ for methodname in methodnames]
658
+ elif len(parts) == 2:
659
+ # case "MyClass.test_1"
660
+ classname, pattern = parts
661
+ klass, methodnames = tests.get(classname, (None, []))
662
+ for methodname in methodnames:
663
+ collected = [klass(methodname) for methodname in methodnames]
664
+ return collected
665
+
666
+ def _this_is_skipped(self, testedname):
667
+ return any([(pat in testedname) for pat in self.skipped_patterns])
668
+
669
+ def getTestCaseNames(self, testCaseClass):
670
+ """Return a sorted sequence of method names found within testCaseClass
671
+ """
672
+ is_skipped = self._this_is_skipped
673
+ classname = testCaseClass.__name__
674
+ if classname[0] == '_' or is_skipped(classname):
675
+ return []
676
+ testnames = super(NonStrictTestLoader, self).getTestCaseNames(
677
+ testCaseClass)
678
+ return [testname for testname in testnames if not is_skipped(testname)]
679
+
680
+
681
+ class SkipAwareTestProgram(unittest.TestProgram):
682
+ # XXX: don't try to stay close to unittest.py, use optparse
683
+ USAGE = """\
684
+ Usage: %(progName)s [options] [test] [...]
685
+
686
+ Options:
687
+ -h, --help Show this message
688
+ -v, --verbose Verbose output
689
+ -i, --pdb Enable test failure inspection
690
+ -x, --exitfirst Exit on first failure
691
+ -c, --capture Captures and prints standard out/err only on errors
692
+ -p, --printonly Only prints lines matching specified pattern
693
+ (implies capture)
694
+ -s, --skip skip test matching this pattern (no regexp for now)
695
+ -q, --quiet Minimal output
696
+ --color colorize tracebacks
697
+
698
+ -m, --match Run only test whose tag match this pattern
699
+
700
+ -P, --profile FILE: Run the tests using cProfile and saving results
701
+ in FILE
702
+
703
+ Examples:
704
+ %(progName)s - run default set of tests
705
+ %(progName)s MyTestSuite - run suite 'MyTestSuite'
706
+ %(progName)s MyTestCase.testSomething - run MyTestCase.testSomething
707
+ %(progName)s MyTestCase - run all 'test*' test methods
708
+ in MyTestCase
709
+ """
710
+ def __init__(self, module='__main__', defaultTest=None, batchmode=False,
711
+ cvg=None, options=None, outstream=sys.stderr):
712
+ self.batchmode = batchmode
713
+ self.cvg = cvg
714
+ self.options = options
715
+ self.outstream = outstream
716
+ super(SkipAwareTestProgram, self).__init__(
717
+ module=module, defaultTest=defaultTest,
718
+ testLoader=NonStrictTestLoader())
719
+
720
+ def parseArgs(self, argv):
721
+ self.pdbmode = False
722
+ self.exitfirst = False
723
+ self.capture = 0
724
+ self.printonly = None
725
+ self.skipped_patterns = []
726
+ self.test_pattern = None
727
+ self.tags_pattern = None
728
+ self.colorize = False
729
+ self.profile_name = None
730
+ import getopt
731
+ try:
732
+ options, args = getopt.getopt(argv[1:], 'hHvixrqcp:s:m:P:',
733
+ ['help', 'verbose', 'quiet', 'pdb',
734
+ 'exitfirst', 'restart', 'capture', 'printonly=',
735
+ 'skip=', 'color', 'match=', 'profile='])
736
+ for opt, value in options:
737
+ if opt in ('-h', '-H', '--help'):
738
+ self.usageExit()
739
+ if opt in ('-i', '--pdb'):
740
+ self.pdbmode = True
741
+ if opt in ('-x', '--exitfirst'):
742
+ self.exitfirst = True
743
+ if opt in ('-r', '--restart'):
744
+ self.restart = True
745
+ self.exitfirst = True
746
+ if opt in ('-q', '--quiet'):
747
+ self.verbosity = 0
748
+ if opt in ('-v', '--verbose'):
749
+ self.verbosity = 2
750
+ if opt in ('-c', '--capture'):
751
+ self.capture += 1
752
+ if opt in ('-p', '--printonly'):
753
+ self.printonly = re.compile(value)
754
+ if opt in ('-s', '--skip'):
755
+ self.skipped_patterns = [pat.strip() for pat in
756
+ value.split(', ')]
757
+ if opt == '--color':
758
+ self.colorize = True
759
+ if opt in ('-m', '--match'):
760
+ #self.tags_pattern = value
761
+ self.options["tag_pattern"] = value
762
+ if opt in ('-P', '--profile'):
763
+ self.profile_name = value
764
+ self.testLoader.skipped_patterns = self.skipped_patterns
765
+ if self.printonly is not None:
766
+ self.capture += 1
767
+ if len(args) == 0 and self.defaultTest is None:
768
+ suitefunc = getattr(self.module, 'suite', None)
769
+ if isinstance(suitefunc, (types.FunctionType,
770
+ types.MethodType)):
771
+ self.test = self.module.suite()
772
+ else:
773
+ self.test = self.testLoader.loadTestsFromModule(self.module)
774
+ return
775
+ if len(args) > 0:
776
+ self.test_pattern = args[0]
777
+ self.testNames = args
778
+ else:
779
+ self.testNames = (self.defaultTest, )
780
+ self.createTests()
781
+ except getopt.error, msg:
782
+ self.usageExit(msg)
783
+
784
+
785
+ def runTests(self):
786
+ if self.profile_name:
787
+ import cProfile
788
+ cProfile.runctx('self._runTests()', globals(), locals(), self.profile_name )
789
+ else:
790
+ return self._runTests()
791
+
792
+ def _runTests(self):
793
+ if hasattr(self.module, 'setup_module'):
794
+ try:
795
+ self.module.setup_module(self.options)
796
+ except Exception, exc:
797
+ print 'setup_module error:', exc
798
+ sys.exit(1)
799
+ self.testRunner = SkipAwareTextTestRunner(verbosity=self.verbosity,
800
+ stream=self.outstream,
801
+ exitfirst=self.exitfirst,
802
+ capture=self.capture,
803
+ printonly=self.printonly,
804
+ pdbmode=self.pdbmode,
805
+ cvg=self.cvg,
806
+ test_pattern=self.test_pattern,
807
+ skipped_patterns=self.skipped_patterns,
808
+ colorize=self.colorize,
809
+ batchmode=self.batchmode,
810
+ options=self.options)
811
+
812
+ def removeSucceededTests(obj, succTests):
813
+ """ Recursive function that removes succTests from
814
+ a TestSuite or TestCase
815
+ """
816
+ if isinstance(obj, TestSuite):
817
+ removeSucceededTests(obj._tests, succTests)
818
+ if isinstance(obj, list):
819
+ for el in obj[:]:
820
+ if isinstance(el, TestSuite):
821
+ removeSucceededTests(el, succTests)
822
+ elif isinstance(el, TestCase):
823
+ descr = '.'.join((el.__class__.__module__,
824
+ el.__class__.__name__,
825
+ el._testMethodName))
826
+ if descr in succTests:
827
+ obj.remove(el)
828
+ # take care, self.options may be None
829
+ if getattr(self.options, 'restart', False):
830
+ # retrieve succeeded tests from FILE_RESTART
831
+ try:
832
+ restartfile = open(FILE_RESTART, 'r')
833
+ try:
834
+ try:
835
+ succeededtests = list(elem.rstrip('\n\r') for elem in
836
+ restartfile.readlines())
837
+ removeSucceededTests(self.test, succeededtests)
838
+ except Exception, e:
839
+ raise e
840
+ finally:
841
+ restartfile.close()
842
+ except Exception ,e:
843
+ raise "Error while reading \
844
+ succeeded tests into", osp.join(os.getcwd(),FILE_RESTART)
845
+
846
+ result = self.testRunner.run(self.test)
847
+ # help garbage collection: we want TestSuite, which hold refs to every
848
+ # executed TestCase, to be gc'ed
849
+ del self.test
850
+ if hasattr(self.module, 'teardown_module'):
851
+ try:
852
+ self.module.teardown_module(self.options, result)
853
+ except Exception, exc:
854
+ print 'teardown_module error:', exc
855
+ sys.exit(1)
856
+ if result.debuggers and self.pdbmode:
857
+ start_interactive_mode(result)
858
+ if not self.batchmode:
859
+ sys.exit(not result.wasSuccessful())
860
+ self.result = result
861
+
862
+
863
+
864
+
865
+ class FDCapture:
866
+ """adapted from py lib (http://codespeak.net/py)
867
+ Capture IO to/from a given os-level filedescriptor.
868
+ """
869
+ def __init__(self, fd, attr='stdout', printonly=None):
870
+ self.targetfd = fd
871
+ self.tmpfile = os.tmpfile() # self.maketempfile()
872
+ self.printonly = printonly
873
+ # save original file descriptor
874
+ self._savefd = os.dup(fd)
875
+ # override original file descriptor
876
+ os.dup2(self.tmpfile.fileno(), fd)
877
+ # also modify sys module directly
878
+ self.oldval = getattr(sys, attr)
879
+ setattr(sys, attr, self) # self.tmpfile)
880
+ self.attr = attr
881
+
882
+ def write(self, msg):
883
+ # msg might be composed of several lines
884
+ for line in msg.splitlines():
885
+ line += '\n' # keepdend=True is not enough
886
+ if self.printonly is None or self.printonly.search(line) is None:
887
+ self.tmpfile.write(line)
888
+ else:
889
+ os.write(self._savefd, line)
890
+
891
+ ## def maketempfile(self):
892
+ ## tmpf = os.tmpfile()
893
+ ## fd = os.dup(tmpf.fileno())
894
+ ## newf = os.fdopen(fd, tmpf.mode, 0) # No buffering
895
+ ## tmpf.close()
896
+ ## return newf
897
+
898
+ def restore(self):
899
+ """restore original fd and returns captured output"""
900
+ #XXX: hack hack hack
901
+ self.tmpfile.flush()
902
+ try:
903
+ ref_file = getattr(sys, '__%s__' % self.attr)
904
+ ref_file.flush()
905
+ except AttributeError:
906
+ pass
907
+ if hasattr(self.oldval, 'flush'):
908
+ self.oldval.flush()
909
+ # restore original file descriptor
910
+ os.dup2(self._savefd, self.targetfd)
911
+ # restore sys module
912
+ setattr(sys, self.attr, self.oldval)
913
+ # close backup descriptor
914
+ os.close(self._savefd)
915
+ # go to beginning of file and read it
916
+ self.tmpfile.seek(0)
917
+ return self.tmpfile.read()
918
+
919
+
920
+ def _capture(which='stdout', printonly=None):
921
+ """private method, should not be called directly
922
+ (cf. capture_stdout() and capture_stderr())
923
+ """
924
+ assert which in ('stdout', 'stderr'
925
+ ), "Can only capture stdout or stderr, not %s" % which
926
+ if which == 'stdout':
927
+ fd = 1
928
+ else:
929
+ fd = 2
930
+ return FDCapture(fd, which, printonly)
931
+
932
+ def capture_stdout(printonly=None):
933
+ """captures the standard output
934
+
935
+ returns a handle object which has a `restore()` method.
936
+ The restore() method returns the captured stdout and restores it
937
+ """
938
+ return _capture('stdout', printonly)
939
+
940
+ def capture_stderr(printonly=None):
941
+ """captures the standard error output
942
+
943
+ returns a handle object which has a `restore()` method.
944
+ The restore() method returns the captured stderr and restores it
945
+ """
946
+ return _capture('stderr', printonly)
947
+
948
+
949
+ def unittest_main(module='__main__', defaultTest=None,
950
+ batchmode=False, cvg=None, options=None,
951
+ outstream=sys.stderr):
952
+ """use this function if you want to have the same functionality
953
+ as unittest.main"""
954
+ return SkipAwareTestProgram(module, defaultTest, batchmode,
955
+ cvg, options, outstream)
956
+
957
+ class TestSkipped(Exception):
958
+ """raised when a test is skipped"""
959
+
960
+ class InnerTestSkipped(TestSkipped):
961
+ """raised when a test is skipped"""
962
+
963
+ def is_generator(function):
964
+ flags = function.func_code.co_flags
965
+ return flags & CO_GENERATOR
966
+
967
+
968
+ def parse_generative_args(params):
969
+ args = []
970
+ varargs = ()
971
+ kwargs = {}
972
+ flags = 0 # 2 <=> starargs, 4 <=> kwargs
973
+ for param in params:
974
+ if isinstance(param, starargs):
975
+ varargs = param
976
+ if flags:
977
+ raise TypeError('found starargs after keywords !')
978
+ flags |= 2
979
+ args += list(varargs)
980
+ elif isinstance(param, keywords):
981
+ kwargs = param
982
+ if flags & 4:
983
+ raise TypeError('got multiple keywords parameters')
984
+ flags |= 4
985
+ elif flags & 2 or flags & 4:
986
+ raise TypeError('found parameters after kwargs or args')
987
+ else:
988
+ args.append(param)
989
+
990
+ return args, kwargs
991
+
992
+ class InnerTest(tuple):
993
+ def __new__(cls, name, *data):
994
+ instance = tuple.__new__(cls, data)
995
+ instance.name = name
996
+ return instance
997
+
998
+
999
+ class TestCase(unittest.TestCase):
1000
+ """unittest.TestCase with some additional methods"""
1001
+
1002
+ capture = False
1003
+ pdbclass = Debugger
1004
+
1005
+ def __init__(self, methodName='runTest'):
1006
+ super(TestCase, self).__init__(methodName)
1007
+ # internal API changed in python2.5
1008
+ if sys.version_info >= (2, 5):
1009
+ self.__exc_info = self._exc_info
1010
+ self.__testMethodName = self._testMethodName
1011
+ else:
1012
+ # let's give easier access to _testMethodName to every subclasses
1013
+ self._testMethodName = self.__testMethodName
1014
+ self._captured_stdout = ""
1015
+ self._captured_stderr = ""
1016
+ self._out = []
1017
+ self._err = []
1018
+ self._current_test_descr = None
1019
+ self._options_ = None
1020
+
1021
+ def datadir(cls): # pylint: disable-msg=E0213
1022
+ """helper attribute holding the standard test's data directory
1023
+
1024
+ NOTE: this is a logilab's standard
1025
+ """
1026
+ mod = __import__(cls.__module__)
1027
+ return osp.join(osp.dirname(osp.abspath(mod.__file__)), 'data')
1028
+ # cache it (use a class method to cache on class since TestCase is
1029
+ # instantiated for each test run)
1030
+ datadir = classproperty(cached(datadir))
1031
+
1032
+ def datapath(cls, *fname):
1033
+ """joins the object's datadir and `fname`"""
1034
+ return osp.join(cls.datadir, *fname)
1035
+ datapath = classmethod(datapath)
1036
+
1037
+ def set_description(self, descr):
1038
+ """sets the current test's description.
1039
+ This can be useful for generative tests because it allows to specify
1040
+ a description per yield
1041
+ """
1042
+ self._current_test_descr = descr
1043
+
1044
+ # override default's unittest.py feature
1045
+ def shortDescription(self):
1046
+ """override default unitest shortDescription to handle correctly
1047
+ generative tests
1048
+ """
1049
+ if self._current_test_descr is not None:
1050
+ return self._current_test_descr
1051
+ return super(TestCase, self).shortDescription()
1052
+
1053
+
1054
+ def captured_output(self):
1055
+ """return a two tuple with standard output and error stripped"""
1056
+ return self._captured_stdout.strip(), self._captured_stderr.strip()
1057
+
1058
+ def _start_capture(self):
1059
+ """start_capture if enable"""
1060
+ if self.capture:
1061
+ warnings.simplefilter('ignore', DeprecationWarning)
1062
+ self.start_capture()
1063
+
1064
+ def _stop_capture(self):
1065
+ """stop_capture and restore previous output"""
1066
+ self._force_output_restore()
1067
+
1068
+ def start_capture(self, printonly=None):
1069
+ """start_capture"""
1070
+ self._out.append(capture_stdout(printonly or self._printonly))
1071
+ self._err.append(capture_stderr(printonly or self._printonly))
1072
+
1073
+ def printonly(self, pattern, flags=0):
1074
+ """set the pattern of line to print"""
1075
+ rgx = re.compile(pattern, flags)
1076
+ if self._out:
1077
+ self._out[-1].printonly = rgx
1078
+ self._err[-1].printonly = rgx
1079
+ else:
1080
+ self.start_capture(printonly=rgx)
1081
+
1082
+ def stop_capture(self):
1083
+ """stop output and error capture"""
1084
+ if self._out:
1085
+ _out = self._out.pop()
1086
+ _err = self._err.pop()
1087
+ return _out.restore(), _err.restore()
1088
+ return '', ''
1089
+
1090
+ def _force_output_restore(self):
1091
+ """remove all capture set"""
1092
+ while self._out:
1093
+ self._captured_stdout += self._out.pop().restore()
1094
+ self._captured_stderr += self._err.pop().restore()
1095
+
1096
+ def quiet_run(self, result, func, *args, **kwargs):
1097
+ self._start_capture()
1098
+ try:
1099
+ func(*args, **kwargs)
1100
+ except (KeyboardInterrupt, SystemExit):
1101
+ self._stop_capture()
1102
+ raise
1103
+ except:
1104
+ self._stop_capture()
1105
+ result.addError(self, self.__exc_info())
1106
+ return False
1107
+ self._stop_capture()
1108
+ return True
1109
+
1110
+ def _get_test_method(self):
1111
+ """return the test method"""
1112
+ return getattr(self, self.__testMethodName)
1113
+
1114
+
1115
+ def optval(self, option, default=None):
1116
+ """return the option value or default if the option is not define"""
1117
+ return getattr(self._options_, option, default)
1118
+
1119
+ def __call__(self, result=None, runcondition=None, options=None):
1120
+ """rewrite TestCase.__call__ to support generative tests
1121
+ This is mostly a copy/paste from unittest.py (i.e same
1122
+ variable names, same logic, except for the generative tests part)
1123
+ """
1124
+ if result is None:
1125
+ result = self.defaultTestResult()
1126
+ result.pdbclass = self.pdbclass
1127
+ # if self.capture is True here, it means it was explicitly specified
1128
+ # in the user's TestCase class. If not, do what was asked on cmd line
1129
+ self.capture = self.capture or getattr(result, 'capture', False)
1130
+ self._options_ = options
1131
+ self._printonly = getattr(result, 'printonly', None)
1132
+ # if result.cvg:
1133
+ # result.cvg.start()
1134
+ testMethod = self._get_test_method()
1135
+ if runcondition and not runcondition(testMethod):
1136
+ return # test is skipped
1137
+ result.startTest(self)
1138
+ try:
1139
+ if not self.quiet_run(result, self.setUp):
1140
+ return
1141
+ generative = is_generator(testMethod.im_func)
1142
+ # generative tests
1143
+ if generative:
1144
+ self._proceed_generative(result, testMethod,
1145
+ runcondition)
1146
+ else:
1147
+ status = self._proceed(result, testMethod)
1148
+ success = (status == 0)
1149
+ if not self.quiet_run(result, self.tearDown):
1150
+ return
1151
+ if not generative and success:
1152
+ if hasattr(options, "exitfirst") and options.exitfirst:
1153
+ # add this test to restart file
1154
+ try:
1155
+ restartfile = open(FILE_RESTART, 'a')
1156
+ try:
1157
+ try:
1158
+ descr = '.'.join((self.__class__.__module__,
1159
+ self.__class__.__name__,
1160
+ self._testMethodName))
1161
+ restartfile.write(descr+os.linesep)
1162
+ except Exception, e:
1163
+ raise e
1164
+ finally:
1165
+ restartfile.close()
1166
+ except Exception, e:
1167
+ print >> sys.__stderr__, "Error while saving \
1168
+ succeeded test into", osp.join(os.getcwd(),FILE_RESTART)
1169
+ raise e
1170
+ result.addSuccess(self)
1171
+ finally:
1172
+ # if result.cvg:
1173
+ # result.cvg.stop()
1174
+ result.stopTest(self)
1175
+
1176
+
1177
+
1178
+ def _proceed_generative(self, result, testfunc, runcondition=None):
1179
+ # cancel startTest()'s increment
1180
+ result.testsRun -= 1
1181
+ self._start_capture()
1182
+ success = True
1183
+ try:
1184
+ for params in testfunc():
1185
+ if runcondition and not runcondition(testfunc,
1186
+ skipgenerator=False):
1187
+ if not (isinstance(params, InnerTest)
1188
+ and runcondition(params)):
1189
+ continue
1190
+ if not isinstance(params, (tuple, list)):
1191
+ params = (params, )
1192
+ func = params[0]
1193
+ args, kwargs = parse_generative_args(params[1:])
1194
+ # increment test counter manually
1195
+ result.testsRun += 1
1196
+ status = self._proceed(result, func, args, kwargs)
1197
+ if status == 0:
1198
+ result.addSuccess(self)
1199
+ success = True
1200
+ else:
1201
+ success = False
1202
+ if status == 2:
1203
+ result.shouldStop = True
1204
+ if result.shouldStop: # either on error or on exitfirst + error
1205
+ break
1206
+ except:
1207
+ # if an error occurs between two yield
1208
+ result.addError(self, self.__exc_info())
1209
+ success = False
1210
+ self._stop_capture()
1211
+ return success
1212
+
1213
+ def _proceed(self, result, testfunc, args=(), kwargs=None):
1214
+ """proceed the actual test
1215
+ returns 0 on success, 1 on failure, 2 on error
1216
+
1217
+ Note: addSuccess can't be called here because we have to wait
1218
+ for tearDown to be successfully executed to declare the test as
1219
+ successful
1220
+ """
1221
+ self._start_capture()
1222
+ kwargs = kwargs or {}
1223
+ try:
1224
+ testfunc(*args, **kwargs)
1225
+ self._stop_capture()
1226
+ except self.failureException:
1227
+ self._stop_capture()
1228
+ result.addFailure(self, self.__exc_info())
1229
+ return 1
1230
+ except KeyboardInterrupt:
1231
+ self._stop_capture()
1232
+ raise
1233
+ except InnerTestSkipped, e:
1234
+ result.addSkipped(self, e)
1235
+ return 1
1236
+ except:
1237
+ self._stop_capture()
1238
+ result.addError(self, self.__exc_info())
1239
+ return 2
1240
+ return 0
1241
+
1242
+ def defaultTestResult(self):
1243
+ """return a new instance of the defaultTestResult"""
1244
+ return SkipAwareTestResult()
1245
+
1246
+ def skip(self, msg=None):
1247
+ """mark a test as skipped for the <msg> reason"""
1248
+ msg = msg or 'test was skipped'
1249
+ raise TestSkipped(msg)
1250
+
1251
+ def innerSkip(self, msg=None):
1252
+ """mark a generative test as skipped for the <msg> reason"""
1253
+ msg = msg or 'test was skipped'
1254
+ raise InnerTestSkipped(msg)
1255
+
1256
+ def assertIn(self, object, set):
1257
+ """assert <object> are in <set>"""
1258
+ self.assert_(object in set, "%s not in %s" % (object, set))
1259
+
1260
+ def assertNotIn(self, object, set):
1261
+ """assert <object> are not in <set>"""
1262
+ self.assert_(object not in set, "%s in %s" % (object, set))
1263
+
1264
+ def assertDictEquals(self, dict1, dict2):
1265
+ """compares two dicts
1266
+
1267
+ If the two dict differ, the first difference is shown in the error
1268
+ message
1269
+ """
1270
+ dict1 = dict(dict1)
1271
+ msgs = []
1272
+ for key, value in dict2.items():
1273
+ try:
1274
+ if dict1[key] != value:
1275
+ msgs.append('%r != %r for key %r' % (dict1[key], value,
1276
+ key))
1277
+ del dict1[key]
1278
+ except KeyError:
1279
+ msgs.append('missing %r key' % key)
1280
+ if dict1:
1281
+ msgs.append('dict2 is lacking %r' % dict1)
1282
+ if msgs:
1283
+ self.fail('\n'.join(msgs))
1284
+ assertDictEqual = assertDictEquals
1285
+
1286
+
1287
+
1288
+ def assertUnorderedIterableEquals(self, got, expected, msg=None):
1289
+ """compares two iterable and shows difference between both"""
1290
+ got, expected = list(got), list(expected)
1291
+ self.assertSetEqual(set(got), set(expected), msg)
1292
+ if len(got) != len(expected):
1293
+ if msg is None:
1294
+ msg = ['Iterable have the same elements but not the same number',
1295
+ '\t<element>\t<expected>i\t<got>']
1296
+ got_count = {}
1297
+ expected_count = {}
1298
+ for element in got:
1299
+ got_count[element] = got_count.get(element,0) + 1
1300
+ for element in expected:
1301
+ expected_count[element] = expected_count.get(element,0) + 1
1302
+ # we know that got_count.key() == expected_count.key()
1303
+ # because of assertSetEquals
1304
+ for element, count in got_count.iteritems():
1305
+ other_count = expected_count[element]
1306
+ if other_count != count:
1307
+ msg.append('\t%s\t%s\t%s' % (element, other_count, count))
1308
+
1309
+ self.fail(msg)
1310
+
1311
+ assertUnorderedIterableEqual = assertUnorderedIterableEquals
1312
+ assertUnordIterEquals = assertUnordIterEqual = assertUnorderedIterableEqual
1313
+
1314
+ def assertSetEquals(self,got,expected, msg=None):
1315
+ if not(isinstance(got, set) and isinstance(expected, set)):
1316
+ warnings.warn("the assertSetEquals function if now intended for set only."\
1317
+ "use assertUnorderedIterableEquals instead.",
1318
+ DeprecationWarning, 2)
1319
+ return self.assertUnorderedIterableEquals(got,expected, msg)
1320
+
1321
+ items={}
1322
+ items['missing'] = expected - got
1323
+ items['unexpected'] = got - expected
1324
+ if any(items.itervalues()):
1325
+ if msg is None:
1326
+ msg = '\n'.join('%s:\n\t%s' % (key,"\n\t".join(str(value) for value in values))
1327
+ for key, values in items.iteritems() if values)
1328
+ self.fail(msg)
1329
+
1330
+
1331
+ assertSetEqual = assertSetEquals
1332
+
1333
+ def assertListEquals(self, list_1, list_2, msg=None):
1334
+ """compares two lists
1335
+
1336
+ If the two list differ, the first difference is shown in the error
1337
+ message
1338
+ """
1339
+ _l1 = list_1[:]
1340
+ for i, value in enumerate(list_2):
1341
+ try:
1342
+ if _l1[0] != value:
1343
+ from pprint import pprint
1344
+ pprint(list_1)
1345
+ pprint(list_2)
1346
+ self.fail('%r != %r for index %d' % (_l1[0], value, i))
1347
+ del _l1[0]
1348
+ except IndexError:
1349
+ if msg is None:
1350
+ msg = 'list_1 has only %d elements, not %s '\
1351
+ '(at least %r missing)'% (i, len(list_2), value)
1352
+ self.fail(msg)
1353
+ if _l1:
1354
+ if msg is None:
1355
+ msg = 'list_2 is lacking %r' % _l1
1356
+ self.fail(msg)
1357
+ assertListEqual = assertListEquals
1358
+
1359
+ def assertLinesEquals(self, list_1, list_2, msg=None, striplines=False):
1360
+ """assert list of lines are equal"""
1361
+ lines1 = list_1.splitlines()
1362
+ if striplines:
1363
+ lines1 = [l.strip() for l in lines1]
1364
+ lines2 = list_2.splitlines()
1365
+ if striplines:
1366
+ lines2 = [l.strip() for l in lines2]
1367
+ self.assertListEquals(lines1, lines2, msg)
1368
+ assertLineEqual = assertLinesEquals
1369
+
1370
+ def assertXMLWellFormed(self, stream, msg=None, context=2):
1371
+ """asserts the XML stream is well-formed (no DTD conformance check)
1372
+ :context: number of context lines in standard msg. all data if negativ
1373
+ only available with element tree
1374
+ """
1375
+ try:
1376
+ from xml.etree.ElementTree import parse
1377
+ self._assertETXMLWellFormed(stream, parse, msg)
1378
+ except ImportError:
1379
+ from xml.sax import make_parser, SAXParseException
1380
+ parser = make_parser()
1381
+ try:
1382
+ parser.parse(stream)
1383
+ except SAXParseException, ex:
1384
+ if msg is None:
1385
+ stream.seek(0)
1386
+ for _ in xrange(ex.getLineNumber()):
1387
+ line = stream.readline()
1388
+ pointer = ('' * (ex.getLineNumber() - 1)) + '^'
1389
+ msg = 'XML stream not well formed: %s\n%s%s' % (ex, line, pointer)
1390
+ self.fail(msg)
1391
+
1392
+ def assertXMLStringWellFormed(self, xml_string, msg=None, context=2):
1393
+ """asserts the XML string is well-formed (no DTD conformance check)
1394
+ :context: number of context lines in standard msg. all data if negativ
1395
+ only available with element tree
1396
+ """
1397
+ try:
1398
+ from xml.etree.ElementTree import fromstring
1399
+ self._assertETXMLWellFormed(xml_string, fromstring, msg)
1400
+ except ImportError:
1401
+ raise
1402
+ stream = StringIO(xml_string)
1403
+ self.assertXMLWellFormed(stream, msg)
1404
+
1405
+ def _assertETXMLWellFormed(self, data, parse, msg=None, context=2):
1406
+ """internal function used by /assertXML(String)?WellFormed/ functions
1407
+ :data: xml_data
1408
+ :parse: appropriate parser function for this data
1409
+ :msg: error message
1410
+ :context: number of context lines in standard msg. all data if negativ
1411
+ only available with element tree
1412
+ """
1413
+ from xml.parsers.expat import ExpatError
1414
+ try:
1415
+ parse(data)
1416
+ except ExpatError, ex:
1417
+ if msg is None:
1418
+ if hasattr(data, 'readlines'): #file like object
1419
+ stream.seek(0)
1420
+ lines = stream.readlines()
1421
+ else:
1422
+ lines =data.splitlines(True)
1423
+ nb_lines = len(lines)
1424
+ context_lines = []
1425
+
1426
+ if context < 0:
1427
+ start = 1
1428
+ end = nb_lines
1429
+ else:
1430
+ start = max(ex.lineno-context, 1)
1431
+ end = min(ex.lineno+context, nb_lines)
1432
+ line_number_length = len('%i' % end)
1433
+ line_pattern = " %%%ii: %%s" % line_number_length
1434
+
1435
+ for line_no in xrange(start, ex.lineno):
1436
+ context_lines.append(line_pattern % (line_no, lines[line_no-1]))
1437
+ context_lines.append(line_pattern % (ex.lineno, lines[ex.lineno-1]))
1438
+ context_lines.append('%s^\n' % (' ' * (1 + line_number_length + 2 +ex.offset)))
1439
+ for line_no in xrange(ex.lineno+1, end+1):
1440
+ context_lines.append(line_pattern % (line_no, lines[line_no-1]))
1441
+
1442
+ rich_context = ''.join(context_lines)
1443
+ msg = 'XML stream not well formed: %s\n%s' % (ex, rich_context)
1444
+ self.fail(msg)
1445
+
1446
+
1447
+ def assertXMLEqualsTuple(self, element, tup):
1448
+ """compare an ElementTree Element to a tuple formatted as follow:
1449
+ (tagname, [attrib[, children[, text[, tail]]]])"""
1450
+ # check tag
1451
+ self.assertTextEquals(element.tag, tup[0])
1452
+ # check attrib
1453
+ if len(element.attrib) or len(tup)>1:
1454
+ if len(tup)<=1:
1455
+ self.fail( "tuple %s has no attributes (%s expected)"%(tup,
1456
+ dict(element.attrib)))
1457
+ self.assertDictEquals(element.attrib, tup[1])
1458
+ # check children
1459
+ if len(element) or len(tup)>2:
1460
+ if len(tup)<=2:
1461
+ self.fail( "tuple %s has no children (%i expected)"%(tup,
1462
+ len(element)))
1463
+ if len(element) != len(tup[2]):
1464
+ self.fail( "tuple %s has %i children%s (%i expected)"%(tup,
1465
+ len(tup[2]),
1466
+ ('', 's')[len(tup[2])>1], len(element)))
1467
+ for index in xrange(len(tup[2])):
1468
+ self.assertXMLEqualsTuple(element[index], tup[2][index])
1469
+ #check text
1470
+ if element.text or len(tup)>3:
1471
+ if len(tup)<=3:
1472
+ self.fail( "tuple %s has no text value (%r expected)"%(tup,
1473
+ element.text))
1474
+ self.assertTextEquals(element.text, tup[3])
1475
+ #check tail
1476
+ if element.tail or len(tup)>4:
1477
+ if len(tup)<=4:
1478
+ self.fail( "tuple %s has no tail value (%r expected)"%(tup,
1479
+ element.tail))
1480
+ self.assertTextEquals(element.tail, tup[4])
1481
+
1482
+ def _difftext(self, lines1, lines2, junk=None, msg_prefix='Texts differ'):
1483
+ junk = junk or (' ', '\t')
1484
+ # result is a generator
1485
+ result = difflib.ndiff(lines1, lines2, charjunk=lambda x: x in junk)
1486
+ read = []
1487
+ for line in result:
1488
+ read.append(line)
1489
+ # lines that don't start with a ' ' are diff ones
1490
+ if not line.startswith(' '):
1491
+ self.fail('\n'.join(['%s\n'%msg_prefix]+read + list(result)))
1492
+
1493
+ def assertTextEquals(self, text1, text2, junk=None,
1494
+ msg_prefix='Text differ', striplines=False):
1495
+ """compare two multiline strings (using difflib and splitlines())"""
1496
+ msg = []
1497
+ if not isinstance(text1, basestring):
1498
+ msg.append('text1 is not a string (%s)'%(type(text1)))
1499
+ if not isinstance(text2, basestring):
1500
+ msg.append('text2 is not a string (%s)'%(type(text2)))
1501
+ if msg:
1502
+ self.fail('\n'.join(msg))
1503
+ lines1 = text1.strip().splitlines(True)
1504
+ lines2 = text2.strip().splitlines(True)
1505
+ if striplines:
1506
+ lines1 = [line.strip() for line in lines1]
1507
+ lines2 = [line.strip() for line in lines2]
1508
+ self._difftext(lines1, lines2, junk, msg_prefix)
1509
+ assertTextEqual = assertTextEquals
1510
+
1511
+ def assertStreamEquals(self, stream1, stream2, junk=None,
1512
+ msg_prefix='Stream differ'):
1513
+ """compare two streams (using difflib and readlines())"""
1514
+ # if stream2 is stream2, readlines() on stream1 will also read lines
1515
+ # in stream2, so they'll appear different, although they're not
1516
+ if stream1 is stream2:
1517
+ return
1518
+ # make sure we compare from the beginning of the stream
1519
+ stream1.seek(0)
1520
+ stream2.seek(0)
1521
+ # compare
1522
+ self._difftext(stream1.readlines(), stream2.readlines(), junk,
1523
+ msg_prefix)
1524
+
1525
+ assertStreamEqual = assertStreamEquals
1526
+ def assertFileEquals(self, fname1, fname2, junk=(' ', '\t')):
1527
+ """compares two files using difflib"""
1528
+ self.assertStreamEqual(file(fname1), file(fname2), junk,
1529
+ msg_prefix='Files differs\n-:%s\n+:%s\n'%(fname1, fname2))
1530
+ assertFileEqual = assertFileEquals
1531
+
1532
+
1533
+ def assertDirEquals(self, path_a, path_b):
1534
+ """compares two files using difflib"""
1535
+ assert osp.exists(path_a), "%s doesn't exists" % path_a
1536
+ assert osp.exists(path_b), "%s doesn't exists" % path_b
1537
+
1538
+ all_a = [ (ipath[len(path_a):].lstrip('/'), idirs, ifiles)
1539
+ for ipath, idirs, ifiles in os.walk(path_a)]
1540
+ all_a.sort(key=itemgetter(0))
1541
+
1542
+ all_b = [ (ipath[len(path_b):].lstrip('/'), idirs, ifiles)
1543
+ for ipath, idirs, ifiles in os.walk(path_b)]
1544
+ all_b.sort(key=itemgetter(0))
1545
+
1546
+ iter_a, iter_b = iter(all_a), iter(all_b)
1547
+ partial_iter = True
1548
+ ipath_a, idirs_a, ifiles_a = data_a = None, None, None
1549
+ while True:
1550
+ try:
1551
+ ipath_a, idirs_a, ifiles_a = datas_a = iter_a.next()
1552
+ partial_iter = False
1553
+ ipath_b, idirs_b, ifiles_b = datas_b = iter_b.next()
1554
+ partial_iter = True
1555
+
1556
+
1557
+ self.assert_(ipath_a == ipath_b,
1558
+ "unexpected %s in %s while looking %s from %s" %
1559
+ (ipath_a, path_a, ipath_b, path_b))
1560
+
1561
+
1562
+ errors = {}
1563
+ sdirs_a = set(idirs_a)
1564
+ sdirs_b = set(idirs_b)
1565
+ errors["unexpected directories"] = sdirs_a - sdirs_b
1566
+ errors["missing directories"] = sdirs_b - sdirs_a
1567
+
1568
+ sfiles_a = set(ifiles_a)
1569
+ sfiles_b = set(ifiles_b)
1570
+ errors["unexpected files"] = sfiles_a - sfiles_b
1571
+ errors["missing files"] = sfiles_b - sfiles_a
1572
+
1573
+
1574
+ msgs = [ "%s: %s"% (name, items)
1575
+ for name, items in errors.iteritems() if items]
1576
+
1577
+ if msgs:
1578
+ msgs.insert(0,"%s and %s differ :" % (
1579
+ osp.join(path_a, ipath_a),
1580
+ osp.join(path_b, ipath_b),
1581
+ ))
1582
+ self.fail("\n".join(msgs))
1583
+
1584
+ for files in (ifiles_a, ifiles_b):
1585
+ files.sort()
1586
+
1587
+ for index, path in enumerate(ifiles_a):
1588
+ self.assertFileEquals(osp.join(path_a, ipath_a, path),
1589
+ osp.join(path_b, ipath_b, ifiles_b[index]))
1590
+
1591
+ except StopIteration:
1592
+ break
1593
+
1594
+
1595
+ assertDirEqual = assertDirEquals
1596
+
1597
+
1598
+ def assertIsInstance(self, obj, klass, msg=None, strict=False):
1599
+ """compares two files using difflib"""
1600
+ if msg is None:
1601
+ if strict:
1602
+ msg = '%r is not of class %s but of %s'
1603
+ else:
1604
+ msg = '%r is not an instance of %s but of %s'
1605
+ msg = msg % (obj, klass, type(obj))
1606
+ if strict:
1607
+ self.assert_(obj.__class__ is klass, msg)
1608
+ else:
1609
+ self.assert_(isinstance(obj, klass), msg)
1610
+
1611
+ def assertIs(self, obj, other, msg=None):
1612
+ """compares identity of two reference"""
1613
+ if msg is None:
1614
+ msg = "%r is not %r"%(obj, other)
1615
+ self.assert_(obj is other, msg)
1616
+
1617
+
1618
+ def assertIsNot(self, obj, other, msg=None):
1619
+ """compares identity of two reference"""
1620
+ if msg is None:
1621
+ msg = "%r is %r"%(obj, other)
1622
+ self.assert_(obj is not other, msg )
1623
+
1624
+ def assertNone(self, obj, msg=None):
1625
+ """assert obj is None"""
1626
+ if msg is None:
1627
+ msg = "reference to %r when None expected"%(obj,)
1628
+ self.assert_( obj is None, msg )
1629
+
1630
+ def assertNotNone(self, obj, msg=None):
1631
+ """assert obj is not None"""
1632
+ if msg is None:
1633
+ msg = "unexpected reference to None"
1634
+ self.assert_( obj is not None, msg )
1635
+
1636
+ def assertFloatAlmostEquals(self, obj, other, prec=1e-5, msg=None):
1637
+ """compares two floats"""
1638
+ if msg is None:
1639
+ msg = "%r != %r" % (obj, other)
1640
+ self.assert_(math.fabs(obj - other) < prec, msg)
1641
+
1642
+ def failUnlessRaises(self, excClass, callableObj, *args, **kwargs):
1643
+ """override default failUnlessRaise method to return the raised
1644
+ exception instance.
1645
+
1646
+ Fail unless an exception of class excClass is thrown
1647
+ by callableObj when invoked with arguments args and keyword
1648
+ arguments kwargs. If a different type of exception is
1649
+ thrown, it will not be caught, and the test case will be
1650
+ deemed to have suffered an error, exactly as for an
1651
+ unexpected exception.
1652
+ """
1653
+ try:
1654
+ callableObj(*args, **kwargs)
1655
+ except excClass, exc:
1656
+ return exc
1657
+ else:
1658
+ if hasattr(excClass, '__name__'):
1659
+ excName = excClass.__name__
1660
+ else:
1661
+ excName = str(excClass)
1662
+ raise self.failureException, "%s not raised" % excName
1663
+
1664
+ assertRaises = failUnlessRaises
1665
+
1666
+ import doctest
1667
+
1668
+ class SkippedSuite(unittest.TestSuite):
1669
+ def test(self):
1670
+ """just there to trigger test execution"""
1671
+ self.skipped_test('doctest module has no DocTestSuite class')
1672
+
1673
+
1674
+ # DocTestFinder was introduced in python2.4
1675
+ if sys.version_info >= (2, 4):
1676
+ class DocTestFinder(doctest.DocTestFinder):
1677
+
1678
+ def __init__(self, *args, **kwargs):
1679
+ self.skipped = kwargs.pop('skipped', ())
1680
+ doctest.DocTestFinder.__init__(self, *args, **kwargs)
1681
+
1682
+ def _get_test(self, obj, name, module, globs, source_lines):
1683
+ """override default _get_test method to be able to skip tests
1684
+ according to skipped attribute's value
1685
+
1686
+ Note: Python (<=2.4) use a _name_filter which could be used for that
1687
+ purpose but it's no longer available in 2.5
1688
+ Python 2.5 seems to have a [SKIP] flag
1689
+ """
1690
+ if getattr(obj, '__name__', '') in self.skipped:
1691
+ return None
1692
+ return doctest.DocTestFinder._get_test(self, obj, name, module,
1693
+ globs, source_lines)
1694
+ else:
1695
+ # this is a hack to make skipped work with python <= 2.3
1696
+ class DocTestFinder(object):
1697
+ def __init__(self, skipped):
1698
+ self.skipped = skipped
1699
+ self.original_find_tests = doctest._find_tests
1700
+ doctest._find_tests = self._find_tests
1701
+
1702
+ def _find_tests(self, module, prefix=None):
1703
+ tests = []
1704
+ for testinfo in self.original_find_tests(module, prefix):
1705
+ testname, _, _, _ = testinfo
1706
+ # testname looks like A.B.C.function_name
1707
+ testname = testname.split('.')[-1]
1708
+ if testname not in self.skipped:
1709
+ tests.append(testinfo)
1710
+ return tests
1711
+
1712
+
1713
+ class DocTest(TestCase):
1714
+ """trigger module doctest
1715
+ I don't know how to make unittest.main consider the DocTestSuite instance
1716
+ without this hack
1717
+ """
1718
+ skipped = ()
1719
+ def __call__(self, result=None, runcondition=None, options=None):\
1720
+ # pylint: disable-msg=W0613
1721
+ try:
1722
+ finder = DocTestFinder(skipped=self.skipped)
1723
+ if sys.version_info >= (2, 4):
1724
+ suite = doctest.DocTestSuite(self.module, test_finder=finder)
1725
+ else:
1726
+ suite = doctest.DocTestSuite(self.module)
1727
+ except AttributeError:
1728
+ suite = SkippedSuite()
1729
+ return suite.run(result)
1730
+ run = __call__
1731
+
1732
+ def test(self):
1733
+ """just there to trigger test execution"""
1734
+
1735
+ MAILBOX = None
1736
+
1737
+ class MockSMTP:
1738
+ """fake smtplib.SMTP"""
1739
+
1740
+ def __init__(self, host, port):
1741
+ self.host = host
1742
+ self.port = port
1743
+ global MAILBOX
1744
+ self.reveived = MAILBOX = []
1745
+
1746
+ def set_debuglevel(self, debuglevel):
1747
+ """ignore debug level"""
1748
+
1749
+ def sendmail(self, fromaddr, toaddres, body):
1750
+ """push sent mail in the mailbox"""
1751
+ self.reveived.append((fromaddr, toaddres, body))
1752
+
1753
+ def quit(self):
1754
+ """ignore quit"""
1755
+
1756
+
1757
+ class MockConfigParser(ConfigParser):
1758
+ """fake ConfigParser.ConfigParser"""
1759
+
1760
+ def __init__(self, options):
1761
+ ConfigParser.__init__(self)
1762
+ for section, pairs in options.iteritems():
1763
+ self.add_section(section)
1764
+ for key, value in pairs.iteritems():
1765
+ self.set(section,key,value)
1766
+ def write(self, _):
1767
+ raise NotImplementedError()
1768
+
1769
+
1770
+ class MockConnection:
1771
+ """fake DB-API 2.0 connexion AND cursor (i.e. cursor() return self)"""
1772
+
1773
+ def __init__(self, results):
1774
+ self.received = []
1775
+ self.states = []
1776
+ self.results = results
1777
+
1778
+ def cursor(self):
1779
+ """Mock cursor method"""
1780
+ return self
1781
+ def execute(self, query, args=None):
1782
+ """Mock execute method"""
1783
+ self.received.append( (query, args) )
1784
+ def fetchone(self):
1785
+ """Mock fetchone method"""
1786
+ return self.results[0]
1787
+ def fetchall(self):
1788
+ """Mock fetchall method"""
1789
+ return self.results
1790
+ def commit(self):
1791
+ """Mock commiy method"""
1792
+ self.states.append( ('commit', len(self.received)) )
1793
+ def rollback(self):
1794
+ """Mock rollback method"""
1795
+ self.states.append( ('rollback', len(self.received)) )
1796
+ def close(self):
1797
+ """Mock close method"""
1798
+ pass
1799
+
1800
+
1801
+ def mock_object(**params):
1802
+ """creates an object using params to set attributes
1803
+ >>> option = mock_object(verbose=False, index=range(5))
1804
+ >>> option.verbose
1805
+ False
1806
+ >>> option.index
1807
+ [0, 1, 2, 3, 4]
1808
+ """
1809
+ return type('Mock', (), params)()
1810
+
1811
+
1812
+ def create_files(paths, chroot):
1813
+ """Creates directories and files found in <path>.
1814
+
1815
+ :param paths: list of relative paths to files or directories
1816
+ :param chroot: the root directory in which paths will be created
1817
+
1818
+ >>> from os.path import isdir, isfile
1819
+ >>> isdir('/tmp/a')
1820
+ False
1821
+ >>> create_files(['a/b/foo.py', 'a/b/c/', 'a/b/c/d/e.py'], '/tmp')
1822
+ >>> isdir('/tmp/a')
1823
+ True
1824
+ >>> isdir('/tmp/a/b/c')
1825
+ True
1826
+ >>> isfile('/tmp/a/b/c/d/e.py')
1827
+ True
1828
+ >>> isfile('/tmp/a/b/foo.py')
1829
+ True
1830
+ """
1831
+ dirs, files = set(), set()
1832
+ for path in paths:
1833
+ path = osp.join(chroot, path)
1834
+ filename = osp.basename(path)
1835
+ # path is a directory path
1836
+ if filename == '':
1837
+ dirs.add(path)
1838
+ # path is a filename path
1839
+ else:
1840
+ dirs.add(osp.dirname(path))
1841
+ files.add(path)
1842
+ for dirpath in dirs:
1843
+ if not osp.isdir(dirpath):
1844
+ os.makedirs(dirpath)
1845
+ for filepath in files:
1846
+ file(filepath, 'w').close()
1847
+
1848
+ def enable_dbc(*args):
1849
+ """
1850
+ Without arguments, return True if contracts can be enabled and should be
1851
+ enabled (see option -d), return False otherwise.
1852
+
1853
+ With arguments, return False if contracts can't or shouldn't be enabled,
1854
+ otherwise weave ContractAspect with items passed as arguments.
1855
+ """
1856
+ if not ENABLE_DBC:
1857
+ return False
1858
+ try:
1859
+ from logilab.aspects.weaver import weaver
1860
+ from logilab.aspects.lib.contracts import ContractAspect
1861
+ except ImportError:
1862
+ sys.stderr.write(
1863
+ 'Warning: logilab.aspects is not available. Contracts disabled.')
1864
+ return False
1865
+ for arg in args:
1866
+ weaver.weave_module(arg, ContractAspect)
1867
+ return True
1868
+
1869
+
1870
+ class AttrObject: # XXX cf mock_object
1871
+ def __init__(self, **kwargs):
1872
+ self.__dict__.update(kwargs)
1873
+
1874
+ def tag(*args):
1875
+ """descriptor adding tag to a function"""
1876
+ def desc(func):
1877
+ assert not hasattr(func, 'tags')
1878
+ func.tags = Tags(args)
1879
+ return func
1880
+ return desc
1881
+
1882
+ class Tags(set):
1883
+ """A set of tag able validate an expression"""
1884
+ def __getitem__(self, key):
1885
+ return key in self
1886
+
1887
+ def match(self, exp):
1888
+ return eval(exp, {}, self)
1889
+
1890
+ def require_version(version):
1891
+ """ Compare version of python interpreter to the given one. Skip the test
1892
+ if older.
1893
+ """
1894
+ def check_require_version(f):
1895
+ version_elements = version.split('.')
1896
+ try:
1897
+ compare = tuple([int(v) for v in version_elements])
1898
+ except ValueError:
1899
+ raise ValueError('%s is not a correct version : should be X.Y[.Z].' % version)
1900
+ current = sys.version_info[:3]
1901
+ #print 'comp', current, compare
1902
+ if current < compare:
1903
+ #print 'version too old'
1904
+ def new_f(self, *args, **kwargs):
1905
+ self.skip('Need at least %s version of python. Current version is %s.' % (version, '.'.join([str(element) for element in current])))
1906
+ new_f.__name__ = f.__name__
1907
+ return new_f
1908
+ else:
1909
+ #print 'version young enough'
1910
+ return f
1911
+ return check_require_version
1912
+
1913
+ def require_module(module):
1914
+ """ Check if the given module is loaded. Skip the test if not.
1915
+ """
1916
+ def check_require_module(f):
1917
+ try:
1918
+ __import__(module)
1919
+ #print module, 'imported'
1920
+ return f
1921
+ except ImportError:
1922
+ #print module, 'can not be imported'
1923
+ def new_f(self, *args, **kwargs):
1924
+ self.skip('%s can not be imported.' % module)
1925
+ new_f.__name__ = f.__name__
1926
+ return new_f
1927
+ return check_require_module