|
| 1 | +# Licensed under the LGPL: https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html |
| 2 | +# For details: https://github.com/PyCQA/astroid/blob/master/COPYING.LESSER |
| 3 | +""" |
| 4 | +Astroid hook for the Hypothesis library. |
| 5 | +
|
| 6 | +Without this hook pylint reports no-value-for-parameter for use of strategies |
| 7 | +defined using the `@hypothesis.strategies.composite` decorator. For example: |
| 8 | +
|
| 9 | + from hypothesis import strategies as st |
| 10 | +
|
| 11 | + @st.composite |
| 12 | + def a_strategy(draw): |
| 13 | + return draw(st.integers()) |
| 14 | +
|
| 15 | + a_strategy() |
| 16 | +
|
| 17 | +""" |
| 18 | + |
| 19 | +import astroid |
| 20 | + |
| 21 | +COMPOSITE_NAMES = ( |
| 22 | + "st.composite", |
| 23 | + "strategies.composite", |
| 24 | + "hypothesis.strategies.composite", |
| 25 | +) |
| 26 | + |
| 27 | + |
| 28 | +def is_decorated_with_st_composite(node): |
| 29 | + """Return True if a decorated node has @st.composite applied.""" |
| 30 | + if not node.decorators: |
| 31 | + return False |
| 32 | + for decorator_attribute in node.decorators.nodes: |
| 33 | + if decorator_attribute.as_string() in COMPOSITE_NAMES: |
| 34 | + return True |
| 35 | + return False |
| 36 | + |
| 37 | + |
| 38 | +def remove_draw_parameter_from_composite_strategy(node): |
| 39 | + """Given that the FunctionDef is decorated with @st.composite, remove the |
| 40 | + first argument (`draw`) - it's always supplied by Hypothesis so we don't |
| 41 | + need to emit the no-value-for-parameter lint. |
| 42 | + """ |
| 43 | + if node.args.args[0].name == "draw": |
| 44 | + del node.args.args[0] |
| 45 | + del node.args.annotations[0] |
| 46 | + del node.args.type_comment_args[0] |
| 47 | + return node |
| 48 | + |
| 49 | + |
| 50 | +astroid.MANAGER.register_transform( |
| 51 | + node_class=astroid.FunctionDef, |
| 52 | + transform=remove_draw_parameter_from_composite_strategy, |
| 53 | + predicate=is_decorated_with_st_composite, |
| 54 | +) |
0 commit comments