Development of an internal social media platform with personalised dashboards for students
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

test_check_raise_docs.py 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529
  1. # Copyright (c) 2016-2017 Claudiu Popa <pcmanticore@gmail.com>
  2. # Copyright (c) 2016 Derek Gustafson <degustaf@gmail.com>
  3. # Copyright (c) 2016 Glenn Matthews <glenn@e-dad.net>
  4. # Copyright (c) 2016 Ashley Whetter <ashley@awhetter.co.uk>
  5. # Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  6. # For details: https://github.com/PyCQA/pylint/blob/master/COPYING
  7. """Unit tests for the raised exception documentation checking in the
  8. `DocstringChecker` in :mod:`pylint.extensions.check_docs`
  9. """
  10. from __future__ import division, print_function, absolute_import
  11. import astroid
  12. from pylint.testutils import CheckerTestCase, Message, set_config
  13. from pylint.extensions.docparams import DocstringParameterChecker
  14. class TestDocstringCheckerRaise(CheckerTestCase):
  15. """Tests for pylint_plugin.RaiseDocChecker"""
  16. CHECKER_CLASS = DocstringParameterChecker
  17. def test_ignores_no_docstring(self):
  18. raise_node = astroid.extract_node('''
  19. def my_func(self):
  20. raise RuntimeError('hi') #@
  21. ''')
  22. with self.assertNoMessages():
  23. self.checker.visit_raise(raise_node)
  24. def test_ignores_unknown_style(self):
  25. node = astroid.extract_node('''
  26. def my_func(self):
  27. """This is a docstring."""
  28. raise RuntimeError('hi')
  29. ''')
  30. raise_node = node.body[0]
  31. with self.assertNoMessages():
  32. self.checker.visit_raise(raise_node)
  33. @set_config(accept_no_raise_doc=False)
  34. def test_warns_unknown_style(self):
  35. node = astroid.extract_node('''
  36. def my_func(self):
  37. """This is a docstring."""
  38. raise RuntimeError('hi')
  39. ''')
  40. raise_node = node.body[0]
  41. with self.assertAddsMessages(
  42. Message(
  43. msg_id='missing-raises-doc',
  44. node=node,
  45. args=('RuntimeError', ))):
  46. self.checker.visit_raise(raise_node)
  47. def test_find_missing_sphinx_raises(self):
  48. node = astroid.extract_node('''
  49. def my_func(self):
  50. """This is a docstring.
  51. :raises NameError: Never
  52. """
  53. raise RuntimeError('hi')
  54. raise NameError('hi')
  55. ''')
  56. raise_node = node.body[0]
  57. with self.assertAddsMessages(
  58. Message(
  59. msg_id='missing-raises-doc',
  60. node=node,
  61. args=('RuntimeError', ))):
  62. self.checker.visit_raise(raise_node)
  63. def test_find_missing_google_raises(self):
  64. node = astroid.extract_node('''
  65. def my_func(self):
  66. """This is a docstring.
  67. Raises:
  68. NameError: Never
  69. """
  70. raise RuntimeError('hi')
  71. raise NameError('hi')
  72. ''')
  73. raise_node = node.body[0]
  74. with self.assertAddsMessages(
  75. Message(
  76. msg_id='missing-raises-doc',
  77. node=node,
  78. args=('RuntimeError', ))):
  79. self.checker.visit_raise(raise_node)
  80. def test_find_missing_numpy_raises(self):
  81. node = astroid.extract_node('''
  82. def my_func(self):
  83. """This is a docstring.
  84. Raises
  85. ------
  86. NameError
  87. Never
  88. """
  89. raise RuntimeError('hi')
  90. raise NameError('hi')
  91. ''')
  92. raise_node = node.body[0]
  93. with self.assertAddsMessages(
  94. Message(
  95. msg_id='missing-raises-doc',
  96. node=node,
  97. args=('RuntimeError', ))):
  98. self.checker.visit_raise(raise_node)
  99. def test_ignore_spurious_sphinx_raises(self):
  100. raise_node = astroid.extract_node('''
  101. def my_func(self):
  102. """This is a docstring.
  103. :raises RuntimeError: Always
  104. :except NameError: Never
  105. :raise OSError: Never
  106. :exception ValueError: Never
  107. """
  108. raise RuntimeError('Blah') #@
  109. ''')
  110. with self.assertNoMessages():
  111. self.checker.visit_raise(raise_node)
  112. def test_find_all_sphinx_raises(self):
  113. raise_node = astroid.extract_node('''
  114. def my_func(self):
  115. """This is a docstring.
  116. :raises RuntimeError: Always
  117. :except NameError: Never
  118. :raise OSError: Never
  119. :exception ValueError: Never
  120. """
  121. raise RuntimeError('hi') #@
  122. raise NameError('hi')
  123. raise OSError(2, 'abort!')
  124. raise ValueError('foo')
  125. ''')
  126. with self.assertNoMessages():
  127. self.checker.visit_raise(raise_node)
  128. def test_find_all_google_raises(self):
  129. raise_node = astroid.extract_node('''
  130. def my_func(self):
  131. """This is a docstring.
  132. Raises:
  133. RuntimeError: Always
  134. NameError: Never
  135. """
  136. raise RuntimeError('hi') #@
  137. raise NameError('hi')
  138. ''')
  139. with self.assertNoMessages():
  140. self.checker.visit_raise(raise_node)
  141. def test_find_all_numpy_raises(self):
  142. raise_node = astroid.extract_node('''
  143. def my_func(self):
  144. """This is a docstring.
  145. Raises
  146. ------
  147. RuntimeError
  148. Always
  149. NameError
  150. Never
  151. """
  152. raise RuntimeError('hi') #@
  153. raise NameError('hi')
  154. ''')
  155. with self.assertNoMessages():
  156. self.checker.visit_raise(raise_node)
  157. def test_finds_rethrown_sphinx_raises(self):
  158. raise_node = astroid.extract_node('''
  159. def my_func(self):
  160. """This is a docstring.
  161. :raises NameError: Sometimes
  162. """
  163. try:
  164. fake_func()
  165. except RuntimeError:
  166. raise #@
  167. raise NameError('hi')
  168. ''')
  169. node = raise_node.frame()
  170. with self.assertAddsMessages(
  171. Message(
  172. msg_id='missing-raises-doc',
  173. node=node,
  174. args=('RuntimeError', ))):
  175. self.checker.visit_raise(raise_node)
  176. def test_find_rethrown_google_raises(self):
  177. raise_node = astroid.extract_node('''
  178. def my_func(self):
  179. """This is a docstring.
  180. Raises:
  181. NameError: Sometimes
  182. """
  183. try:
  184. fake_func()
  185. except RuntimeError:
  186. raise #@
  187. raise NameError('hi')
  188. ''')
  189. node = raise_node.frame()
  190. with self.assertAddsMessages(
  191. Message(
  192. msg_id='missing-raises-doc',
  193. node=node,
  194. args=('RuntimeError', ))):
  195. self.checker.visit_raise(raise_node)
  196. def test_find_rethrown_numpy_raises(self):
  197. raise_node = astroid.extract_node('''
  198. def my_func(self):
  199. """This is a docstring.
  200. Raises
  201. ------
  202. NameError
  203. Sometimes
  204. """
  205. try:
  206. fake_func()
  207. except RuntimeError:
  208. raise #@
  209. raise NameError('hi')
  210. ''')
  211. node = raise_node.frame()
  212. with self.assertAddsMessages(
  213. Message(
  214. msg_id='missing-raises-doc',
  215. node=node,
  216. args=('RuntimeError', ))):
  217. self.checker.visit_raise(raise_node)
  218. def test_finds_rethrown_sphinx_multiple_raises(self):
  219. raise_node = astroid.extract_node('''
  220. def my_func(self):
  221. """This is a docstring.
  222. :raises NameError: Sometimes
  223. """
  224. try:
  225. fake_func()
  226. except (RuntimeError, ValueError):
  227. raise #@
  228. raise NameError('hi')
  229. ''')
  230. node = raise_node.frame()
  231. with self.assertAddsMessages(
  232. Message(
  233. msg_id='missing-raises-doc',
  234. node=node,
  235. args=('RuntimeError, ValueError', ))):
  236. self.checker.visit_raise(raise_node)
  237. def test_find_rethrown_google_multiple_raises(self):
  238. raise_node = astroid.extract_node('''
  239. def my_func(self):
  240. """This is a docstring.
  241. Raises:
  242. NameError: Sometimes
  243. """
  244. try:
  245. fake_func()
  246. except (RuntimeError, ValueError):
  247. raise #@
  248. raise NameError('hi')
  249. ''')
  250. node = raise_node.frame()
  251. with self.assertAddsMessages(
  252. Message(
  253. msg_id='missing-raises-doc',
  254. node=node,
  255. args=('RuntimeError, ValueError', ))):
  256. self.checker.visit_raise(raise_node)
  257. def test_find_rethrown_numpy_multiple_raises(self):
  258. raise_node = astroid.extract_node('''
  259. def my_func(self):
  260. """This is a docstring.
  261. Raises
  262. ------
  263. NameError
  264. Sometimes
  265. """
  266. try:
  267. fake_func()
  268. except (RuntimeError, ValueError):
  269. raise #@
  270. raise NameError('hi')
  271. ''')
  272. node = raise_node.frame()
  273. with self.assertAddsMessages(
  274. Message(
  275. msg_id='missing-raises-doc',
  276. node=node,
  277. args=('RuntimeError, ValueError', ))):
  278. self.checker.visit_raise(raise_node)
  279. def test_ignores_caught_sphinx_raises(self):
  280. raise_node = astroid.extract_node('''
  281. def my_func(self):
  282. """This is a docstring.
  283. :raises NameError: Sometimes
  284. """
  285. try:
  286. raise RuntimeError('hi') #@
  287. except RuntimeError:
  288. pass
  289. raise NameError('hi')
  290. ''')
  291. with self.assertNoMessages():
  292. self.checker.visit_raise(raise_node)
  293. def test_ignores_caught_google_raises(self):
  294. raise_node = astroid.extract_node('''
  295. def my_func(self):
  296. """This is a docstring.
  297. Raises:
  298. NameError: Sometimes
  299. """
  300. try:
  301. raise RuntimeError('hi') #@
  302. except RuntimeError:
  303. pass
  304. raise NameError('hi')
  305. ''')
  306. with self.assertNoMessages():
  307. self.checker.visit_raise(raise_node)
  308. def test_ignores_caught_numpy_raises(self):
  309. raise_node = astroid.extract_node('''
  310. def my_func(self):
  311. """This is a docstring.
  312. Raises
  313. ------
  314. NameError
  315. Sometimes
  316. """
  317. try:
  318. raise RuntimeError('hi') #@
  319. except RuntimeError:
  320. pass
  321. raise NameError('hi')
  322. ''')
  323. with self.assertNoMessages():
  324. self.checker.visit_raise(raise_node)
  325. def test_find_missing_sphinx_raises_infer_from_instance(self):
  326. raise_node = astroid.extract_node('''
  327. def my_func(self):
  328. """This is a docstring.
  329. :raises NameError: Never
  330. """
  331. my_exception = RuntimeError('hi')
  332. raise my_exception #@
  333. raise NameError('hi')
  334. ''')
  335. node = raise_node.frame()
  336. with self.assertAddsMessages(
  337. Message(
  338. msg_id='missing-raises-doc',
  339. node=node,
  340. args=('RuntimeError', ))):
  341. self.checker.visit_raise(raise_node)
  342. def test_find_missing_sphinx_raises_infer_from_function(self):
  343. raise_node = astroid.extract_node('''
  344. def my_func(self):
  345. """This is a docstring.
  346. :raises NameError: Never
  347. """
  348. def ex_func(val):
  349. return RuntimeError(val)
  350. raise ex_func('hi') #@
  351. raise NameError('hi')
  352. ''')
  353. node = raise_node.frame()
  354. with self.assertAddsMessages(
  355. Message(
  356. msg_id='missing-raises-doc',
  357. node=node,
  358. args=('RuntimeError', ))):
  359. self.checker.visit_raise(raise_node)
  360. def test_ignores_raise_uninferable(self):
  361. raise_node = astroid.extract_node('''
  362. from unknown import Unknown
  363. def my_func(self):
  364. """This is a docstring.
  365. :raises NameError: Never
  366. """
  367. raise Unknown('hi') #@
  368. raise NameError('hi')
  369. ''')
  370. with self.assertNoMessages():
  371. self.checker.visit_raise(raise_node)
  372. def test_ignores_returns_from_inner_functions(self):
  373. raise_node = astroid.extract_node('''
  374. def my_func(self):
  375. """This is a docstring.
  376. :raises NameError: Never
  377. """
  378. def ex_func(val):
  379. def inner_func(value):
  380. return OSError(value)
  381. return RuntimeError(val)
  382. raise ex_func('hi') #@
  383. raise NameError('hi')
  384. ''')
  385. node = raise_node.frame()
  386. with self.assertAddsMessages(
  387. Message(
  388. msg_id='missing-raises-doc',
  389. node=node,
  390. args=('RuntimeError', ))):
  391. # we do NOT expect a warning about the OSError in inner_func!
  392. self.checker.visit_raise(raise_node)
  393. def test_ignores_returns_use_only_names(self):
  394. raise_node = astroid.extract_node('''
  395. def myfunc():
  396. """This is a docstring
  397. :raises NameError: Never
  398. """
  399. def inner_func():
  400. return 42
  401. raise inner_func() #@
  402. ''')
  403. with self.assertNoMessages():
  404. self.checker.visit_raise(raise_node)
  405. def test_ignores_returns_use_only_exception_instances(self):
  406. raise_node = astroid.extract_node('''
  407. def myfunc():
  408. """This is a docstring
  409. :raises MyException: Never
  410. """
  411. class MyException(Exception):
  412. pass
  413. def inner_func():
  414. return MyException
  415. raise inner_func() #@
  416. ''')
  417. with self.assertNoMessages():
  418. self.checker.visit_raise(raise_node)
  419. def test_no_crash_when_inferring_handlers(self):
  420. raise_node = astroid.extract_node('''
  421. import collections
  422. def test():
  423. """raises
  424. :raise U: pass
  425. """
  426. try:
  427. pass
  428. except collections.U as exc:
  429. raise #@
  430. ''')
  431. with self.assertNoMessages():
  432. self.checker.visit_raise(raise_node)
  433. def test_no_crash_when_cant_find_exception(self):
  434. raise_node = astroid.extract_node('''
  435. import collections
  436. def test():
  437. """raises
  438. :raise U: pass
  439. """
  440. try:
  441. pass
  442. except U as exc:
  443. raise #@
  444. ''')
  445. with self.assertNoMessages():
  446. self.checker.visit_raise(raise_node)
  447. def test_no_error_notimplemented_documented(self):
  448. raise_node = astroid.extract_node('''
  449. def my_func():
  450. """
  451. Raises:
  452. NotImplementedError: When called.
  453. """
  454. raise NotImplementedError #@
  455. ''')
  456. with self.assertNoMessages():
  457. self.checker.visit_raise(raise_node)