├── .coveragerc ├── .git-blame-ignore-revs ├── .github ├── PULL_REQUEST_TEMPLATE.md ├── dependabot.yml └── workflows │ ├── publish.yml │ └── test.yml ├── .gitignore ├── .pre-commit-config.yaml ├── .prettierignore ├── .prettierrc ├── CHANGELOG.md ├── CITATION.cff ├── LICENSE ├── MANIFEST.in ├── PRIVACY_POLICY.md ├── README.md ├── docs ├── Makefile ├── _static │ └── css │ │ └── pyta-custom.css ├── cfg │ ├── images │ │ ├── if_else.svg │ │ └── method_only.svg │ └── index.md ├── checkers │ └── index.md ├── conf.py ├── contracts │ └── index.md ├── debug │ └── index.md ├── demos │ └── sample.py ├── images │ ├── csfaculty.jpg │ ├── favicon.png │ ├── pyta_logo.svg │ ├── pyta_logo_markdown.png │ └── sample_report.png ├── index.md ├── make.bat ├── publications │ ├── index.md │ └── static │ │ ├── A Static Analysis Tool in CS 1 - Student Usage and Perceptions of PythonTA - ACE 2025.pdf │ │ └── Are a Static Analysis Tool Studys Findings Static - ITiCSE 2024.pdf └── usage │ ├── api.md │ ├── configuration.md │ └── quick_start.md ├── examples ├── README.md ├── __init__.py ├── custom_checkers │ ├── c9103_naming_convention_violation.py │ ├── c9104_ModuleNameViolation.py │ ├── c9960_unmentioned_parameter.py │ ├── e9950_forbidden_python_syntax.py │ ├── e9959_redundant_assignment.py │ ├── e9969_possibly_undefined.py │ ├── e9970_missing_param_type.py │ ├── e9971_missing_return_type.py │ ├── e9972_missing_attribute_type.py │ ├── e9973_missing_space_in_doctest.py │ ├── e9984_invalid_for_target.py │ ├── e9988_shadowing_in_comprehension.py │ ├── e9989_pep8_errors.py │ ├── e9989_pycodestyle │ │ ├── e115_error.py │ │ ├── e115_no_error.py │ │ ├── e122_error.py │ │ ├── e122_no_error.py │ │ ├── e123_error.py │ │ ├── e123_no_error.py │ │ ├── e125_error.py │ │ ├── e125_no_error.py │ │ ├── e127_error.py │ │ ├── e127_no_error.py │ │ ├── e129_error.py │ │ ├── e129_no_error.py │ │ ├── e131_error.py │ │ ├── e131_no_error.py │ │ ├── e203_error.py │ │ ├── e203_no_error.py │ │ ├── e222_error.py │ │ ├── e222_no_error.py │ │ ├── e223_error.py │ │ ├── e223_no_error.py │ │ ├── e224_error.py │ │ ├── e224_no_error.py │ │ ├── e226_error.py │ │ ├── e226_no_error.py │ │ ├── e227_error.py │ │ ├── e227_no_error.py │ │ ├── e228_error.py │ │ ├── e228_no_error.py │ │ ├── e262_error.py │ │ ├── e262_no_error.py │ │ ├── e265_error.py │ │ ├── e265_no_error.py │ │ ├── e266_error.py │ │ ├── e266_no_error.py │ │ ├── e275_error.py │ │ ├── e275_no_error.py │ │ ├── e301_error.py │ │ ├── e301_no_error.py │ │ ├── e303_error.py │ │ ├── e303_no_error.py │ │ ├── e304_error.py │ │ └── e304_no_error.py │ ├── e9992_forbidden_top_level_code.py │ ├── e9993_invalid_range_index.py │ ├── e9994_unnecessary_indexing.py │ ├── e9995_type_is_assigned.py │ ├── e9996_one_iteration.py │ ├── e9997_forbidden_global_variables.py │ ├── e9998_forbidden_IO_function.py │ ├── e9999_forbidden_import.py │ ├── e9999_forbidden_import_local.py │ ├── r9710_inconsistent_returns.py │ ├── r9711_missing_return_statement.py │ ├── r9900_redundant_condition.py │ ├── r9901_impossible_condition.py │ └── static_type_checker_examples │ │ ├── e9951_incompatible_argument_type.py │ │ ├── e9952_incompatible_assignment.py │ │ ├── e9953_list_item_type_mismatch.py │ │ ├── e9954_unsupported_operand_types.py │ │ ├── e9955_union_attr_error.py │ │ ├── e9956_dict_item_type_mismatch.py │ │ ├── imports_no_error.py │ │ └── static_type_checker_no_error.py ├── ending_locations │ ├── arguments.py │ ├── assert.py │ ├── assign.py │ ├── assign_attr.py │ ├── assign_name.py │ ├── async_for.py │ ├── async_function_def.py │ ├── async_with.py │ ├── attribute.py │ ├── aug_assign.py │ ├── await.py │ ├── bin_op.py │ ├── bool_op.py │ ├── break.py │ ├── call.py │ ├── class_def.py │ ├── compare.py │ ├── comprehension.py │ ├── const.py │ ├── continue.py │ ├── decorators.py │ ├── del_attr.py │ ├── del_name.py │ ├── delete.py │ ├── dict.py │ ├── dict_comp.py │ ├── except_handler.py │ ├── expr.py │ ├── for.py │ ├── function_def.py │ ├── generator_exp.py │ ├── global.py │ ├── if.py │ ├── if_exp.py │ ├── import.py │ ├── import_from.py │ ├── keyword.py │ ├── lambda.py │ ├── list.py │ ├── list_comp.py │ ├── module.py │ ├── name.py │ ├── nonlocal.py │ ├── pass.py │ ├── raise.py │ ├── return.py │ ├── set.py │ ├── set_comp.py │ ├── slice.py │ ├── starred.py │ ├── subscript.py │ ├── try.py │ ├── tuple.py │ ├── unary_op.py │ ├── while.py │ ├── with.py │ ├── yield.py │ └── yield_from.py ├── nodes │ ├── README.md │ ├── ann_assign.py │ ├── arguments.py │ ├── assert.py │ ├── assign.py │ ├── assign_attr.py │ ├── assign_name.py │ ├── async_for.py │ ├── async_function_def.py │ ├── async_with.py │ ├── attribute.py │ ├── aug_assign.py │ ├── await.py │ ├── bin_op.py │ ├── bool_op.py │ ├── break.py │ ├── call.py │ ├── class_def.py │ ├── compare.py │ ├── comprehension.py │ ├── const.py │ ├── continue.py │ ├── decorators.py │ ├── del_attr.py │ ├── del_name.py │ ├── delete.py │ ├── dict.py │ ├── dict_comp.py │ ├── dict_unpack.py │ ├── except_handler.py │ ├── expr.py │ ├── for.py │ ├── formatted_value.py │ ├── function_def.py │ ├── generator_exp.py │ ├── global.py │ ├── if.py │ ├── if_exp.py │ ├── import.py │ ├── import_from.py │ ├── joined_str.py │ ├── keyword.py │ ├── lambda.py │ ├── list.py │ ├── list_comp.py │ ├── module.py │ ├── name.py │ ├── nonlocal.py │ ├── pass.py │ ├── raise.py │ ├── return.py │ ├── set.py │ ├── set_comp.py │ ├── slice.py │ ├── starred.py │ ├── subscript.py │ ├── try.py │ ├── tuple.py │ ├── unary_op.py │ ├── while.py │ ├── with.py │ ├── yield.py │ └── yield_from.py ├── pylint │ ├── c0103_naming_convention_violation.py │ ├── c0104_disallowed_name.py │ ├── c0112_empty_docstring.py │ ├── c0114_missing_module_docstring.py │ ├── c0115_missing_class_docstring.py │ ├── c0116_missing_function_docstring.py │ ├── c0117_unnecessary_negation.py │ ├── c0121_singleton_comparison.py │ ├── c0123_unidiomatic_typecheck.py │ ├── c0201_consider_iterating_dictionary.py │ ├── c0209_consider_using_f_string.py │ ├── c0301_line_too_long.py │ ├── c0302_too_many_lines.py │ ├── c0303_trailing_whitespace.py │ ├── c0304_missing_final_newline.py │ ├── c0305_trailing_newlines.py │ ├── c0321_multiple_statements.py │ ├── c0325_superfluous_parens.py │ ├── c0410_multiple_imports.py │ ├── c0411_wrong_import_order.py │ ├── c0412_ungrouped_imports.py │ ├── c0413_wrong_import_position.py │ ├── c0414_useless_import_alias.py │ ├── c0415_import_outside_toplevel.py │ ├── c1802_use_implicit_booleaness_not_len.py │ ├── c2503_non_ascii_name.py │ ├── cyclic_import_helper.py │ ├── e0101_return_in_init.py │ ├── e0102_function_redefined.py │ ├── e0103_not_in_loop.py │ ├── e0104_return_outside_function.py │ ├── e0107_nonexistent_operator.py │ ├── e0108_duplicate_argument_name.py │ ├── e0111_bad_reversed_sequence.py │ ├── e0118_used_prior_global_declaration.py │ ├── e0119_misplaced_format_function.py │ ├── e0202_method_hidden.py │ ├── e0203_access_member_before_definition.py │ ├── e0211_no_method_argument.py │ ├── e0213_no_self_argument.py │ ├── e0239_inherit_non_class.py │ ├── e0241_duplicate_bases.py │ ├── e0301_non_iterator_returned.py │ ├── e0302_unexpected_special_method_signature.py │ ├── e0303_invalid_length_returned.py │ ├── e0304_invalid_bool_returned.py │ ├── e0306_invalid_repr_returned.py │ ├── e0307_invalid_str_returned.py │ ├── e0401_import_error.py │ ├── e0601_used_before_assignment.py │ ├── e0602_undefined_variable.py │ ├── e0611_no_name_in_module.py │ ├── e0632_unbalanced_tuple_unpacking.py │ ├── e0633_unpacking_non_sequence.py │ ├── e0643_potential_index_error.py │ ├── e0701_bad_except_order.py │ ├── e0702_raising_bad_type.py │ ├── e0704_misplaced_bare_raise.py │ ├── e0710_raising_non_exception.py │ ├── e0711_notimplemented_raised.py │ ├── e0712_catching_non_exception.py │ ├── e1003_bad_super_call.py │ ├── e1101_no_member.py │ ├── e1102_not_callable.py │ ├── e1111_assignment_from_no_return.py │ ├── e1120_no_value_for_parameter.py │ ├── e1121_too_many_function_args.py │ ├── e1123_unexpected_keyword_arg.py │ ├── e1126_invalid_sequence_index.py │ ├── e1127_invalid_slice_index.py │ ├── e1128_assignment_from_none.py │ ├── e1129_not_context_manager.py │ ├── e1130_invalid_unary_operand_type.py │ ├── e1131_unsupported_binary_operation.py │ ├── e1133_not_an_iterable.py │ ├── e1134_not_a_mapping.py │ ├── e1135_unsupported_membership_test.py │ ├── e1136_unsubscriptable_object.py │ ├── e1137_unsupported_assignment_operation.py │ ├── e1138_unsupported_delete_operation.py │ ├── e1141_dict_iter_missing_items.py │ ├── e1143_unhashable_member.py │ ├── e1144_invalid_slice_step.py │ ├── e1305_too_many_format_args.py │ ├── e1306_too_few_format_args.py │ ├── e1307_bad_string_format_type.py │ ├── e1310_bad_str_strip_call.py │ ├── e3701_invalid_field_call.py │ ├── e4702_modified_iterating_dict.py │ ├── e4703_modified_iterating_set.py │ ├── r0123_literal_comparison.py │ ├── r0124_comparison_with_itself.py │ ├── r0133_comparison_of_constants.py │ ├── r0201_no_self_use.py │ ├── r0205_useless_object_inheritance.py │ ├── r0401_cyclic_import.py │ ├── r0402_consider_using_from_import.py │ ├── r0902_too_many_instance_attributes.py │ ├── r0912_too_many_branches.py │ ├── r0913_too_many_arguments.py │ ├── r0914_too_many_locals.py │ ├── r0915_too_many_statements.py │ ├── r0916_too_many_boolean_expressions.py │ ├── r1701_consider_merging_isinstance.py │ ├── r1702_too_many_nested_blocks.py │ ├── r1704_redefined_argument_from_local.py │ ├── r1707_trailing_comma_tuple.py │ ├── r1712_consider_swap_variables.py │ ├── r1713_consider_using_join.py │ ├── r1714_consider_using_in.py │ ├── r1715_consider_using_get.py │ ├── r1716_chained_comparison.py │ ├── r1721_unnecessary_comprehension.py │ ├── r1725_super_with_arguments.py │ ├── r1726_simplifiable_condition.py │ ├── r1727_condition_evals_to_constant.py │ ├── r1732_consider_using_with.py │ ├── r1733_unnecessary_dict_index_lookup.py │ ├── r1734_use_list_literal.py │ ├── r1735_use_dict_literal.py │ ├── r1736_unnecessary_list_index_lookup.py │ ├── w0101_unreachable.py │ ├── w0102_dangerous_default_value.py │ ├── w0104_pointless_statement.py │ ├── w0105_pointless_string_statement.py │ ├── w0106_expression_not_assigned.py │ ├── w0107_unnecessary_pass.py │ ├── w0108_unnecessary_lambda.py │ ├── w0109_duplicate_key.py │ ├── w0122_exec_used.py │ ├── w0123_eval_used.py │ ├── w0124_confusing_with_statement.py │ ├── w0125_using_constant_test.py │ ├── w0126_missing_parentheses_for_call_in_test.py │ ├── w0127_self_assigning_variable.py │ ├── w0128_redeclared_assigned_name.py │ ├── w0130_duplicate_value.py │ ├── w0133_pointless_exception_statement.py │ ├── w0134_return_in_finally.py │ ├── w0143_comparison_with_callable.py │ ├── w0183_broad_exception_caught.py │ ├── w0199_assert_on_tuple.py │ ├── w0201_attribute_defined_outside_init.py │ ├── w0211_bad_staticmethod_argument.py │ ├── w0212_protected_access.py │ ├── w0221_arguments_differ.py │ ├── w0222_signature_differs.py │ ├── w0223_abstract_method.py │ ├── w0231_super_init_not_called.py │ ├── w0233_non_parent_init_called.py │ ├── w0245_super_without_brackets.py │ ├── w0301_unnecessary_semicolon.py │ ├── w0311_bad_indentation.py │ ├── w0401_wildcard_import.py │ ├── w0404_reimported.py │ ├── w0406_import_self.py │ ├── w0410_misplaced_future.py │ ├── w0416_shadowed_import.py │ ├── w0511_fixme.py │ ├── w0604_global_at_module_level.py │ ├── w0611_unused_import.py │ ├── w0612_unused_variable.py │ ├── w0613_unused_argument.py │ ├── w0621_redefined_outer_name.py │ ├── w0622_redefined_builtin.py │ ├── w0631_undefined_loop_variable.py │ ├── w0632_unbalanced_tuple_unpacking.py │ ├── w0642_self_cls_assignment.py │ ├── w0644_unbalanced_dict_unpacking.py │ ├── w0702_bare_except.py │ ├── w0705_duplicate_except.py │ ├── w0706_try_except_raise.py │ ├── w0711_binary_op_exception.py │ ├── w0715_raising_format_tuple.py │ ├── w0716_wrong_exception_operation.py │ ├── w0718_broad_exception_caught.py │ ├── w0719_broad_exception_raised.py │ ├── w1114_arguments_out_of_order.py │ ├── w1117_kwarg_superseded_by_positional_arg.py │ ├── w1303_missing_format_argument_key.py │ ├── w1304_unused_format_string_argument.py │ ├── w1305_format_combined_specification.py │ ├── w1308_duplicate_string_formatting_argument.py │ ├── w1309_f_string_without_interpolation.py │ ├── w1310_format_string_without_interpolation.py │ ├── w1401_anomalous_backslash_in_string.py │ ├── w1402_anomalous_unicode_escape_in_string.py │ ├── w1404_implicit_str_concat.py │ ├── w1501_bad_open_mode.py │ ├── w1503_redundant_unittest_assert.py │ ├── w1515_forgotten_debug_statement.py │ ├── w2301_unnecessary_ellipsis.py │ ├── w3301_nested_min_max.py │ ├── w3601_bad_chained_comparison.py │ └── w4701_modified_iterating_list.py ├── sample_usage │ ├── README.md │ ├── TODO.md │ ├── __init__.py │ ├── draw_cfg.py │ ├── print_ast.py │ ├── print_nodes.py │ ├── print_table.py │ ├── pyta_stats.py │ └── stats_analysis.py └── syntax_errors │ ├── assignment_inside_condition.py │ ├── assignment_to_keyword.py │ ├── assignment_to_literal.py │ ├── missing_colon.py │ ├── missing_parentheses_in_call_to_print.py │ ├── missing_quote.py │ ├── undefined_operator.py │ ├── unexpected_indent.py │ └── unindent_does_not_match_indentation.py ├── pyproject.toml ├── python_ta ├── __init__.py ├── __main__.py ├── cfg │ ├── __init__.py │ ├── cfg_generator.py │ ├── graph.py │ └── visitor.py ├── check │ ├── __init__.py │ ├── helpers.py │ └── watch.py ├── checkers │ ├── __init__.py │ ├── condition_logic_checker.py │ ├── forbidden_import_checker.py │ ├── forbidden_io_function_checker.py │ ├── forbidden_python_syntax_checker.py │ ├── global_variables_checker.py │ ├── inconsistent_or_missing_returns_checker.py │ ├── invalid_for_target_checker.py │ ├── invalid_name_checker.py │ ├── invalid_range_index_checker.py │ ├── missing_space_in_doctest_checker.py │ ├── one_iteration_checker.py │ ├── possibly_undefined_checker.py │ ├── pycodestyle_checker.py │ ├── redundant_assignment_checker.py │ ├── shadowing_in_comprehension_checker.py │ ├── static_type_checker.py │ ├── top_level_code_checker.py │ ├── type_annotation_checker.py │ ├── unmentioned_parameter_checker.py │ └── unnecessary_indexing_checker.py ├── config │ ├── .pylintrc │ ├── __init__.py │ └── messages_config.toml ├── contracts │ ├── __init__.py │ └── __main__.py ├── debug │ ├── __init__.py │ ├── accumulation_table.py │ ├── recursion_table.py │ ├── snapshot.py │ ├── snapshot_tracer.py │ └── webstepper │ │ ├── 99ee5c67fd0c522b4b6a.png │ │ ├── fd6133fe40f4f90440d6.png │ │ ├── index.bundle.js │ │ ├── index.bundle.js.LICENSE.txt │ │ └── index.html ├── patches │ ├── __init__.py │ ├── checkers.py │ ├── messages.py │ └── transforms.py ├── reporters │ ├── README.md │ ├── TODO.md │ ├── __init__.py │ ├── color_reporter.py │ ├── core.py │ ├── html_reporter.py │ ├── json_reporter.py │ ├── node_printers.py │ ├── one_shot_server.py │ ├── persistent_server.py │ ├── plain_reporter.py │ ├── stat_reporter.py │ └── templates │ │ ├── pyta_logo_markdown.png │ │ ├── script.js │ │ ├── stylesheet.css │ │ └── template.html.jinja ├── transforms │ ├── __init__.py │ ├── setendings.py │ └── z3_visitor.py ├── upload.py ├── util │ ├── __init__.py │ ├── autoformat.py │ └── tree.py ├── utils.py └── z3 │ ├── __init__.py │ └── z3_parser.py ├── setup.py └── tests ├── __init__.py ├── conftest.py ├── fixtures ├── contracts │ └── modules_not_in_arg.py ├── no_errors.py ├── precondition_inline_comment.py ├── pylint_comment.py ├── reporters │ ├── no_watch_integration.py │ └── watch_integration.py ├── sample_dir │ ├── assignment_inside_condition.py │ ├── c0114_missing_module_docstring.py │ ├── custom_checkers │ │ ├── e9989_pycodestyle │ │ │ └── e123_error.py │ │ └── e9992_forbidden_top_level_code.py │ ├── pylint │ │ └── c0121_singleton_comparison.py │ └── watch │ │ └── watch_enabled_configuration.py ├── unicode_decode_error.py └── unused_imports.py ├── test.pylintrc ├── test_black.py ├── test_cfg ├── file_fixtures │ ├── funcs_only.py │ └── my_file.py ├── snapshots │ ├── funcs_only.gv │ └── my_file.gv ├── test_cfg_generator.py ├── test_classdef_.py ├── test_edge_feasibility.py ├── test_for_.py ├── test_functions_.py ├── test_functions_preconditions.py ├── test_if.py ├── test_jump.py ├── test_label_if.py ├── test_label_while.py ├── test_tryexcept.py ├── test_unreachable.py ├── test_while.py ├── test_with.py └── test_z3_constraints.py ├── test_check.py ├── test_config ├── file_fixtures │ ├── funcs_with_errors.py │ ├── test.pylintrc │ ├── test_f0011.pylintrc │ ├── test_json_with_errors.pylintrc │ ├── test_plain_with_errors.pylintrc │ └── test_with_errors.pylintrc ├── test_config.py ├── test_file.py └── test_num_error_occurrences.py ├── test_contracts ├── nested_preconditions_example.py ├── test_class_contracts.py ├── test_class_forward_reference.py ├── test_contracts.py ├── test_contracts_attr_value_restoration.py ├── test_contracts_debug.py ├── test_contracts_type_alias_abstract_network.py └── test_contracts_type_alias_abstract_ring.py ├── test_custom_checkers ├── file_fixtures │ └── badModuleName.py ├── test_e9999_local_import │ └── imported_module.py ├── test_forbidden_import_checker.py ├── test_forbidden_io_function_checker.py ├── test_forbidden_python_syntax_checker.py ├── test_global_variables_checker.py ├── test_impossible_condition_checker.py ├── test_inconsistent_returns.py ├── test_invalid_for_target_checker.py ├── test_invalid_name_checker.py ├── test_invalid_range_index_checker.py ├── test_missing_return_statements.py ├── test_missing_space_in_doctest_checker.py ├── test_one_iteration_checker.py ├── test_possibly_undefined_checker.py ├── test_pycodestyle_checker.py ├── test_redundant_assignment_checker.py ├── test_redundant_condition_checker.py ├── test_shadowing_in_comprehension_checker.py ├── test_static_type_checker.py ├── test_top_level_code_checker.py ├── test_type_annotation_checker.py ├── test_unmentioned_parameter_checker.py └── test_unnecessary_indexing_checker.py ├── test_debug ├── snapshot_main_frame.py ├── snapshot_save_file.py ├── snapshot_save_stdout.py ├── snapshot_testing_snapshots │ ├── snapshot_testing_snapshots_expected.svg │ └── snapshot_testing_snapshots_expected_stdout.svg ├── snapshot_tracer_testing_snapshots │ ├── func_for_loop │ │ ├── snapshot-0.svg │ │ ├── snapshot-1.svg │ │ ├── snapshot-2.svg │ │ ├── snapshot-3.svg │ │ ├── snapshot-4.svg │ │ ├── snapshot-5.svg │ │ ├── snapshot-6.svg │ │ ├── snapshot-7.svg │ │ └── snapshot-8.svg │ ├── func_if_else │ │ ├── snapshot-0.svg │ │ ├── snapshot-1.svg │ │ ├── snapshot-2.svg │ │ └── snapshot-3.svg │ ├── func_multi_line │ │ ├── snapshot-0.svg │ │ ├── snapshot-1.svg │ │ ├── snapshot-2.svg │ │ ├── snapshot-3.svg │ │ └── snapshot-4.svg │ ├── func_mutation │ │ ├── snapshot-0.svg │ │ ├── snapshot-1.svg │ │ └── snapshot-2.svg │ ├── func_no_output_dir │ │ └── snapshot-0.svg │ ├── func_one_line │ │ ├── snapshot-0.svg │ │ └── snapshot-1.svg │ ├── func_open_webstepper │ │ ├── index.html │ │ ├── snapshot-0.svg │ │ ├── snapshot-1.svg │ │ ├── snapshot-2.svg │ │ ├── snapshot-3.svg │ │ ├── snapshot-4.svg │ │ ├── snapshot-5.svg │ │ ├── snapshot-6.svg │ │ ├── snapshot-7.svg │ │ └── snapshot-8.svg │ └── func_while │ │ ├── snapshot-0.svg │ │ ├── snapshot-1.svg │ │ ├── snapshot-2.svg │ │ ├── snapshot-3.svg │ │ ├── snapshot-4.svg │ │ ├── snapshot-5.svg │ │ ├── snapshot-6.svg │ │ ├── snapshot-7.svg │ │ └── snapshot-8.svg ├── test_accumulation_table.py ├── test_recursion_table.py ├── test_snapshot.py └── test_snapshot_tracer.py ├── test_examples.py ├── test_init_logging.py ├── test_main.py ├── test_messages_config ├── test.messages_config.toml ├── test.messages_config_incorrect_section_header.toml ├── test.messages_config_no_section_header.toml ├── test.messages_config_no_section_header_incorrect_error_message.toml ├── test_messages_config.py ├── test_no_user_config_no_pyta_overwrite.pylintrc ├── test_no_user_config_pyta_overwrite.pylintrc ├── test_user_config_incorrect_section_header.pylintrc ├── test_user_config_no_pyta_overwrite.pylintrc ├── test_user_config_no_section_header_incorrect_error_message.pylintrc ├── test_user_config_no_section_header_no_pyta_overwrite.pylintrc ├── test_user_config_no_section_header_pyta_overwrite.pylintrc ├── test_user_config_pyta_overwrite.pylintrc └── testing_code.py ├── test_reporters ├── snapshots │ └── test_html_server │ │ ├── test_no_watch_server_is_non_persistent │ │ └── no_watch_html_server_snapshot.html │ │ ├── test_open_html_in_browser_no_watch │ │ └── no_watch_html_server_snapshot.html │ │ ├── test_open_html_in_browser_watch │ │ └── watch_html_server_snapshot.html │ │ ├── test_watch_persistence │ │ └── watch_html_server_snapshot.html │ │ └── test_watch_update │ │ ├── watch_html_server_snapshot.html │ │ └── watch_html_server_snapshot_updated.html └── test_html_server.py ├── test_setendings.py ├── test_subclass_contracts.py ├── test_validate_invariants.py ├── test_watch └── test_watch.py ├── test_z3 └── test_z3_parser.py └── test_z3_visitor.py /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | omit = 3 | python_ta/debug/* 4 | python_ta/reporters/templates/* 5 | python_ta/util/* 6 | python_ta/upload.py 7 | python_ta/utils.py 8 | -------------------------------------------------------------------------------- /.git-blame-ignore-revs: -------------------------------------------------------------------------------- 1 | # pre-commit, black, isort, prettier 2 | 5de08ff34774dd03d58d7167175eb005b33ef166 3 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "pip" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "monthly" 12 | 13 | - package-ecosystem: "github-actions" 14 | directory: "/" 15 | schedule: 16 | interval: "monthly" 17 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish PythonTA package to PyPI 2 | 3 | on: 4 | release: 5 | types: [published] 6 | 7 | jobs: 8 | build: 9 | name: Build distribution 📦 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - uses: actions/checkout@v4 14 | - name: Set up Python 15 | uses: actions/setup-python@v5 16 | with: 17 | python-version: "3.x" 18 | - name: Install pypa/build 19 | run: >- 20 | python3 -m 21 | pip install 22 | build 23 | --user 24 | - name: Build a binary wheel and a source tarball 25 | run: python3 -m build 26 | - name: Store the distribution packages 27 | uses: actions/upload-artifact@v4 28 | with: 29 | name: python-package-distributions 30 | path: dist/ 31 | publish-to-pypi: 32 | name: >- 33 | Publish Python 🐍 distribution 📦 to PyPI 34 | if: startsWith(github.ref, 'refs/tags/') # only publish to PyPI on tag pushes 35 | needs: 36 | - build 37 | runs-on: ubuntu-latest 38 | environment: 39 | name: pypi 40 | url: https://pypi.org/p/python-ta 41 | permissions: 42 | id-token: write # IMPORTANT: mandatory for trusted publishing 43 | steps: 44 | - name: Download all the dists 45 | uses: actions/download-artifact@v4 46 | with: 47 | name: python-package-distributions 48 | path: dist/ 49 | - name: Publish distribution 📦 to PyPI 50 | uses: pypa/gh-action-pypi-publish@release/v1 51 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # PyCharm configuration 2 | .idea/ 3 | 4 | # Compiled python modules. 5 | *.pyc 6 | __pycache__/ 7 | 8 | # Setuptools folders. 9 | /dist/ 10 | /build/ 11 | 12 | # Python egg metadata, regenerated from source files by setuptools. 13 | /*.egg-info 14 | 15 | # Hypothesis caches 16 | .hypothesis/ 17 | 18 | # Test coverage cache 19 | .coverage 20 | 21 | # DS_Store 22 | *.DS_Store 23 | 24 | # Sphinx documentation build files 25 | docs/_build 26 | 27 | # Environments 28 | venv/ 29 | 30 | # For prettier 31 | node_modules/ 32 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/pre-commit/pre-commit-hooks 3 | rev: v5.0.0 4 | hooks: 5 | - id: check-yaml 6 | - id: end-of-file-fixer 7 | - id: trailing-whitespace 8 | - repo: https://github.com/PyCQA/isort 9 | rev: 6.0.1 10 | hooks: 11 | - id: isort 12 | - repo: https://github.com/psf/black-pre-commit-mirror 13 | rev: 25.1.0 14 | hooks: 15 | - id: black 16 | args: [--safe, --quiet] 17 | - repo: https://github.com/pre-commit/mirrors-prettier 18 | rev: v4.0.0-alpha.8 19 | hooks: 20 | - id: prettier 21 | exclude: | 22 | (?x)^( 23 | examples| 24 | tests/fixtures/| 25 | tests/test_debug/snapshot_testing_snapshots| 26 | tests/test_debug/snapshot_tracer_testing_snapshots| 27 | tests/test_reporters/snapshots/test_html_server/test_no_watch_server_is_non_persistent/no_watch_html_server_snapshot.html| 28 | tests/test_reporters/snapshots/test_html_server/test_watch_persistence/watch_html_server_snapshot.html| 29 | tests/test_reporters/snapshots/test_html_server/test_watch_update/ 30 | ) 31 | 32 | ci: 33 | autoupdate_schedule: quarterly 34 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # Ignore artifacts 2 | build 3 | dist 4 | 5 | # Ignore minified Javascript assets 6 | *.min.js 7 | *.bundle.js 8 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": false 3 | } 4 | -------------------------------------------------------------------------------- /CITATION.cff: -------------------------------------------------------------------------------- 1 | # This CITATION.cff file was generated with cffinit. 2 | # Visit https://bit.ly/cffinit to generate yours today! 3 | 4 | cff-version: 1.2.0 5 | title: PythonTA 6 | message: >- 7 | If you use this software, please cite it using the 8 | metadata from this file. 9 | type: software 10 | authors: 11 | - given-names: David 12 | family-names: Liu 13 | email: david@cs.toronto.edu 14 | affiliation: University of Toronto 15 | orcid: "https://orcid.org/0000-0001-5777-5833" 16 | repository-code: "https://github.com/pyta-uoft/pyta" 17 | url: "https://www.cs.toronto.edu/~david/pyta/" 18 | abstract: Code checking tool for teaching Python. 19 | license: GPL-3.0 20 | commit: 23cd60ce7bad47a5edffed7c7e2bed7d3e4da46a 21 | version: 2.6.1 22 | date-released: "2023-08-13" 23 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include README.md 2 | include python_ta/config/.pylintrc 3 | include python_ta/config/messages_config.toml 4 | include python_ta/reporters/templates/* 5 | include python_ta/debug/webstepper/* 6 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = . 9 | BUILDDIR = _build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /docs/_static/css/pyta-custom.css: -------------------------------------------------------------------------------- 1 | .wy-side-nav-search .wy-dropdown > a.icon img.logo, 2 | .wy-side-nav-search > a.icon img.logo { 3 | display: inline; 4 | margin-top: 0; 5 | width: 3em; 6 | } 7 | -------------------------------------------------------------------------------- /docs/demos/sample.py: -------------------------------------------------------------------------------- 1 | """This file illustrates basic usage of PythonTA's code analysis.""" 2 | 3 | 4 | def add_two(x: int, y: int) -> int: 5 | """Return the sum of x and y. 6 | 7 | PythonTA's analysis of this code will report three issues: 8 | 9 | 1. A missing return statement (a logical error) 10 | 2. Missing whitespace around the + (a formatting issue) 11 | 3. The presence of a print call (a code style issue) 12 | """ 13 | result = x + y 14 | print(result) 15 | 16 | 17 | if __name__ == "__main__": 18 | import python_ta 19 | 20 | python_ta.check_all() 21 | -------------------------------------------------------------------------------- /docs/images/csfaculty.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyta-uoft/pyta/0539d23be047c12316158304e4837b80e1384d75/docs/images/csfaculty.jpg -------------------------------------------------------------------------------- /docs/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyta-uoft/pyta/0539d23be047c12316158304e4837b80e1384d75/docs/images/favicon.png -------------------------------------------------------------------------------- /docs/images/pyta_logo_markdown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyta-uoft/pyta/0539d23be047c12316158304e4837b80e1384d75/docs/images/pyta_logo_markdown.png -------------------------------------------------------------------------------- /docs/images/sample_report.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyta-uoft/pyta/0539d23be047c12316158304e4837b80e1384d75/docs/images/sample_report.png -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=. 11 | set BUILDDIR=_build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.http://sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /docs/publications/static/A Static Analysis Tool in CS 1 - Student Usage and Perceptions of PythonTA - ACE 2025.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyta-uoft/pyta/0539d23be047c12316158304e4837b80e1384d75/docs/publications/static/A Static Analysis Tool in CS 1 - Student Usage and Perceptions of PythonTA - ACE 2025.pdf -------------------------------------------------------------------------------- /docs/publications/static/Are a Static Analysis Tool Studys Findings Static - ITiCSE 2024.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyta-uoft/pyta/0539d23be047c12316158304e4837b80e1384d75/docs/publications/static/Are a Static Analysis Tool Studys Findings Static - ITiCSE 2024.pdf -------------------------------------------------------------------------------- /docs/usage/api.md: -------------------------------------------------------------------------------- 1 | # API 2 | 3 | The main entrypoint for running PythonTA's code analysis is the `check_all` function. 4 | 5 | ```{eval-rst} 6 | .. autofunction:: python_ta.check_all 7 | ``` 8 | 9 | Notes: 10 | 11 | - For information on using the `config` argument, see {doc}`Configuration <./configuration>`. 12 | - If using the `ColorReporter`, writing to a file using the `output` argument is not recommended. 13 | This reporter uses terminal-specific characters to colourize text displayed on your screen, and these characters will look strange when opening the output file in a text editor. 14 | 15 | The `doc` function can be used to open the {doc}`PythonTA Checks webpage <../checkers/index>` to look up a specific error. 16 | 17 | ```{eval-rst} 18 | .. autofunction:: python_ta.doc 19 | ``` 20 | -------------------------------------------------------------------------------- /examples/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyta-uoft/pyta/0539d23be047c12316158304e4837b80e1384d75/examples/__init__.py -------------------------------------------------------------------------------- /examples/custom_checkers/c9103_naming_convention_violation.py: -------------------------------------------------------------------------------- 1 | """Examples for C9103 naming-convention-violation.""" 2 | 3 | not_upper_for_const = "CONSTANT" # naming-convention-violation 4 | 5 | 6 | def NotSnakeCase(): # naming-convention-violation 7 | pass 8 | 9 | 10 | class not_pascal_case: # naming-convention-violation 11 | pass 12 | -------------------------------------------------------------------------------- /examples/custom_checkers/c9104_ModuleNameViolation.py: -------------------------------------------------------------------------------- 1 | """Example of C9104 module-name-violation.""" 2 | # The name of this file is not in snake_case, hence violates conventions for module names. 3 | -------------------------------------------------------------------------------- /examples/custom_checkers/c9960_unmentioned_parameter.py: -------------------------------------------------------------------------------- 1 | """Example for C9960 unmentioned-parameter""" 2 | 3 | 4 | def multiply(a: int, b: int) -> int: # C9960: 'a' and 'b' are not mentioned 5 | """Multiply two numbers.""" 6 | return a * b 7 | 8 | 9 | def divide(numerator: int, denominator: int) -> float: # C9960: 'denominator' is not mentioned 10 | """Divide the numerator as specified. 11 | 12 | Parameters: 13 | numerator: The number to be divided. 14 | """ 15 | return numerator / denominator 16 | 17 | 18 | def generate_list(n: int) -> list: # C9960: 'n' is not mentioned in the main docstring (only in doctests) 19 | """Generate a list of numbers 20 | 21 | >>> n = 3 22 | >>> generate_list(n) 23 | [0, 1, 2] 24 | """ 25 | return [i for i in range(n)] 26 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9950_forbidden_python_syntax.py: -------------------------------------------------------------------------------- 1 | """Examples for E9950 forbidden-python-syntax.""" 2 | 3 | count = 10 4 | while count > -1: # forbidden python syntax 5 | if count == 5: 6 | continue # forbidden python syntax 7 | 8 | for i in range(1, 10): # forbidden python syntax 9 | if i == 5: 10 | break # forbidden python syntax 11 | 12 | squares = [i ** 2 for i in range(1, 10)] # forbidden python syntax 13 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9959_redundant_assignment.py: -------------------------------------------------------------------------------- 1 | x = 0 # redundant assignment 2 | y = 10 3 | if y > 10: 4 | print(y) 5 | x = 5 6 | else: 7 | x = 10 8 | print(x) 9 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9969_possibly_undefined.py: -------------------------------------------------------------------------------- 1 | x = 0 2 | if x > 10: 3 | x = 5 4 | else: 5 | y = 5 6 | print(x + y) # y might not be defined 7 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9970_missing_param_type.py: -------------------------------------------------------------------------------- 1 | """Example for E9970 missing-param-type""" 2 | def add_one(n) -> int: 3 | """Return n + 1.""" 4 | return n + 1 5 | 6 | 7 | class ExampleClass: 8 | """Class docstring.""" 9 | inst_attr: int 10 | 11 | def __init__(self) -> None: 12 | """Initialize an instance of this class.""" 13 | self.inst_attr = 0 14 | 15 | def inst_method(self, x) -> int: # Missing function parameter type annotation 16 | """Function docstring.""" 17 | return self.inst_attr + x 18 | 19 | @staticmethod 20 | def static_function(x) -> int: # Missing function parameter type annotation 21 | """Static function docstring.""" 22 | return x 23 | 24 | @classmethod 25 | def class_method(cls, x) -> int: # Missing function parameter type annotation 26 | """Class function docstring.""" 27 | return x 28 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9971_missing_return_type.py: -------------------------------------------------------------------------------- 1 | """Example for E9971 missing-return-type""" 2 | def add_one(n: int): 3 | """Return n + 1.""" 4 | return n + 1 5 | 6 | 7 | class ExampleClass: 8 | """Class docstring.""" 9 | inst_attr: int 10 | 11 | def __init__(self): 12 | """Initialize an instance of this class.""" 13 | self.inst_attr = 0 14 | 15 | def inst_method(self, x: int): # Missing return type annotation 16 | """Function docstring.""" 17 | return self.inst_attr + x 18 | 19 | @staticmethod 20 | def static_function(x: int): # Missing return type annotation 21 | """Static function docstring.""" 22 | return x 23 | 24 | @classmethod 25 | def class_method(cls, x: str): # Missing return type annotation 26 | """Class function docstring.""" 27 | return x 28 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9972_missing_attribute_type.py: -------------------------------------------------------------------------------- 1 | """Example for E9972 missing-attribute-type""" 2 | 3 | 4 | class ExampleClass: 5 | """Class docstring.""" 6 | def __init__(self) -> None: 7 | """Initialize a new instance of this class.""" 8 | self.inst_attr: str = 'hi' # Instance variable should be annotated in class body 9 | self.inst_attr2 = True # Instance variable should be annotated in class body 10 | 11 | 12 | class A: 13 | """Class docstring.""" 14 | x: int 15 | 16 | 17 | class B(A): 18 | """Class B is a subclass of A.""" 19 | 20 | def method(self) -> None: 21 | """Function docstring""" 22 | self.x = 15 # No error because attribute has type annotation in the parent class 23 | 24 | 25 | class ExampleClass2: 26 | """Class docstring.""" 27 | inst_attr = 1 28 | 29 | def __init__(self) -> None: 30 | """Initialize a new instance of this class.""" 31 | self.inst_attr: str # Instance variable should be annotated in class body 32 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9973_missing_space_in_doctest.py: -------------------------------------------------------------------------------- 1 | """Examples for E9973 missing-space-in-doctest""" 2 | 3 | 4 | def f(x: int) -> int: 5 | """Return one plus x. 6 | 7 | >>>f(10) # Error on this line: Won't actually be parsed as a doctest! 8 | 11 9 | """ 10 | 11 | 12 | def f2(x: int) -> int: 13 | """Return one plus x. 14 | 15 | >>>f(10) # Error on this line: Won't actually be parsed as a doctest! 16 | 11 17 | >>>f(11) # Error on this line: Won't actually be parsed as a doctest! 18 | 12 19 | """ 20 | 21 | 22 | def f3(x: int) -> int: 23 | """Return one plus x. 24 | 25 | >>> f(10) 26 | 11 27 | >>>f(11) # Error on this line: Won't actually be parsed as a doctest! 28 | 12 29 | """ 30 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9988_shadowing_in_comprehension.py: -------------------------------------------------------------------------------- 1 | """Example for E9988: shadowing-in-comprehension.""" 2 | from __future__ import annotations 3 | 4 | 5 | # There are four different types of comprehensions: 6 | # list comprehension, dict comprehension, set comprehension, and generator comprehension 7 | # below are examples with each type of comprehensions in respective order 8 | 9 | 10 | def num_lst(n: int) -> list[int]: 11 | """Return a list of integers from 0 to , in that order.""" 12 | return [n for n in range(n)] 13 | 14 | 15 | def switch_dict(x: dict) -> dict: 16 | """Return a dictionary with keys and values switched.""" 17 | return {y: x for x, y in x.items()} 18 | 19 | 20 | def common_items(lst1: list, lst2: list) -> int: 21 | """Return the number of unique common items in and .""" 22 | s = 0 23 | set1 = {s for s in lst1} 24 | for item in set1: 25 | if item in lst2: 26 | s += 1 27 | 28 | return s 29 | 30 | 31 | def print_pos(lst: list[int]) -> None: 32 | """Print items in lst one by one if they are greater than 0.""" 33 | for k in (k for k in lst if k > 0): 34 | print(k) 35 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9989_pep8_errors.py: -------------------------------------------------------------------------------- 1 | def add(n:int,m:int)->int : 2 | """Return the sum of n and m.""" 3 | return n+m 4 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9989_pycodestyle/e115_error.py: -------------------------------------------------------------------------------- 1 | if True: 2 | # No indented block follows the colon 3 | pass 4 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9989_pycodestyle/e115_no_error.py: -------------------------------------------------------------------------------- 1 | if True: 2 | # Correctly indented block follows the colon 3 | pass 4 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9989_pycodestyle/e122_error.py: -------------------------------------------------------------------------------- 1 | print("Python", ( 2 | "Rules")) 3 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9989_pycodestyle/e122_no_error.py: -------------------------------------------------------------------------------- 1 | print("Python", ( 2 | "Rules")) 3 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9989_pycodestyle/e123_error.py: -------------------------------------------------------------------------------- 1 | x = [ 2 | 1 3 | ] 4 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9989_pycodestyle/e123_no_error.py: -------------------------------------------------------------------------------- 1 | x = [ 2 | 1 3 | ] 4 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9989_pycodestyle/e125_error.py: -------------------------------------------------------------------------------- 1 | if 2 > 1 and 3 > 3 or \ 2 | 4 < 5: 3 | print("Hello") 4 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9989_pycodestyle/e125_no_error.py: -------------------------------------------------------------------------------- 1 | if 2 > 1 and 3 > 3 or \ 2 | 4 < 5: 3 | print("Hello") 4 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9989_pycodestyle/e127_error.py: -------------------------------------------------------------------------------- 1 | print("Python", ("Hello", 2 | "World")) 3 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9989_pycodestyle/e127_no_error.py: -------------------------------------------------------------------------------- 1 | print("Python", ("Hello", 2 | "World")) 3 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9989_pycodestyle/e129_error.py: -------------------------------------------------------------------------------- 1 | if (2 > 1, 2 | 2 > 0, 3 | 3 > 3, 4 | 4 > 4): 5 | print("Hello") 6 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9989_pycodestyle/e129_no_error.py: -------------------------------------------------------------------------------- 1 | if (2 > 1, 2 | 2 > 0, 3 | 3 > 3, 4 | 4 > 4): 5 | print("Hello") 6 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9989_pycodestyle/e131_error.py: -------------------------------------------------------------------------------- 1 | my_dict = { 2 | "key": "value", 3 | "long": "the quick brown fox jumps over the " 4 | "lazy dog", 5 | } 6 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9989_pycodestyle/e131_no_error.py: -------------------------------------------------------------------------------- 1 | my_dict = { 2 | "key": "value", 3 | "long": "the quick brown fox jumps over the " 4 | "lazy dog", 5 | } 6 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9989_pycodestyle/e203_error.py: -------------------------------------------------------------------------------- 1 | def add(n: int, m: int) -> int : 2 | return n + m 3 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9989_pycodestyle/e203_no_error.py: -------------------------------------------------------------------------------- 1 | def add(n: int, m: int) -> int: 2 | return n + m 3 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9989_pycodestyle/e222_error.py: -------------------------------------------------------------------------------- 1 | a = 1 2 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9989_pycodestyle/e222_no_error.py: -------------------------------------------------------------------------------- 1 | a = 1 2 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9989_pycodestyle/e223_error.py: -------------------------------------------------------------------------------- 1 | a = 1 2 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9989_pycodestyle/e223_no_error.py: -------------------------------------------------------------------------------- 1 | a = 1 2 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9989_pycodestyle/e224_error.py: -------------------------------------------------------------------------------- 1 | a = 1 2 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9989_pycodestyle/e224_no_error.py: -------------------------------------------------------------------------------- 1 | a = 1 2 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9989_pycodestyle/e226_error.py: -------------------------------------------------------------------------------- 1 | a = 1+2 2 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9989_pycodestyle/e226_no_error.py: -------------------------------------------------------------------------------- 1 | a = 1 + 2 2 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9989_pycodestyle/e227_error.py: -------------------------------------------------------------------------------- 1 | a = 1|2 2 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9989_pycodestyle/e227_no_error.py: -------------------------------------------------------------------------------- 1 | a = 1 | 2 2 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9989_pycodestyle/e228_error.py: -------------------------------------------------------------------------------- 1 | a = 7%2 2 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9989_pycodestyle/e228_no_error.py: -------------------------------------------------------------------------------- 1 | a = 7 % 2 2 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9989_pycodestyle/e262_error.py: -------------------------------------------------------------------------------- 1 | a = 1 # this is a comment 2 | b = 1 #this is a comment with no leading space 3 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9989_pycodestyle/e262_no_error.py: -------------------------------------------------------------------------------- 1 | a = 1 # this is a comment 2 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9989_pycodestyle/e265_error.py: -------------------------------------------------------------------------------- 1 | #This comment is NOT appropriately formatted according to PEP8. 2 | if __name__ == "__main__": 3 | a = 1 4 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9989_pycodestyle/e265_no_error.py: -------------------------------------------------------------------------------- 1 | # This comment is appropriately formatted according to PEP8. 2 | if __name__ == "__main__": 3 | a = 1 4 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9989_pycodestyle/e266_error.py: -------------------------------------------------------------------------------- 1 | ## This is a comment with too many leading '#' 2 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9989_pycodestyle/e266_no_error.py: -------------------------------------------------------------------------------- 1 | # This is a comment without too many leading '#' 2 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9989_pycodestyle/e275_error.py: -------------------------------------------------------------------------------- 1 | from math import(lcm) 2 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9989_pycodestyle/e275_no_error.py: -------------------------------------------------------------------------------- 1 | from math import lcm 2 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9989_pycodestyle/e301_error.py: -------------------------------------------------------------------------------- 1 | class Example: 2 | 3 | def getTrue(self): 4 | return True 5 | def getFalse(self): 6 | return False 7 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9989_pycodestyle/e301_no_error.py: -------------------------------------------------------------------------------- 1 | class Example: 2 | 3 | def getTrue(self): 4 | return True 5 | 6 | def getFalse(self): 7 | return False 8 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9989_pycodestyle/e303_error.py: -------------------------------------------------------------------------------- 1 | def func1(): 2 | return True 3 | 4 | 5 | 6 | def func2(): 7 | return False 8 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9989_pycodestyle/e303_no_error.py: -------------------------------------------------------------------------------- 1 | def func1(): 2 | return True 3 | 4 | 5 | def func2(): 6 | return False 7 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9989_pycodestyle/e304_error.py: -------------------------------------------------------------------------------- 1 | 2 | def decor(func): 3 | def inner(): 4 | x = func() 5 | return 2 * x 6 | 7 | return inner 8 | 9 | 10 | @decor 11 | 12 | def num(): 13 | return 10 14 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9989_pycodestyle/e304_no_error.py: -------------------------------------------------------------------------------- 1 | 2 | def decor(func): 3 | def inner(): 4 | x = func() 5 | return 2 * x 6 | 7 | return inner 8 | 9 | 10 | @decor 11 | def num(): 12 | return 10 13 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9992_forbidden_top_level_code.py: -------------------------------------------------------------------------------- 1 | def example_function(name: str) -> str: 2 | return f'Hello {name}!' 3 | 4 | 5 | print(example_function('Fred')) # error on this line 6 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9993_invalid_range_index.py: -------------------------------------------------------------------------------- 1 | for i in range(0): 2 | print(i) 3 | 4 | for i in range(10, 0): 5 | print(i) 6 | 7 | for j in range(0, 1, 3): 8 | print(j) 9 | 10 | for m in range(4, 5): 11 | print(m) 12 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9995_type_is_assigned.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | import datetime 3 | 4 | 5 | class Person: 6 | name = "Bob" 7 | 8 | 9 | def add_two_numbers( 10 | x=int, # Error on this line 11 | y=list[float], # Error on this line 12 | z: type = complex # No error on this line 13 | ) -> int: 14 | return (x + y) * z 15 | 16 | 17 | class MyDataType: 18 | x = datetime.time # Error on this line 19 | y = Person # Error on this line 20 | z: complex = complex # No error on this line 21 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9996_one_iteration.py: -------------------------------------------------------------------------------- 1 | """Examples for E9996 one-iteration.""" 2 | 3 | 4 | def buggy_search(numbers: list[int], x: int) -> bool: 5 | """Return whether numbers contains x (buggy version).""" 6 | for number in numbers: 7 | if number == x: 8 | return True 9 | else: 10 | return False 11 | 12 | 13 | def loop() -> int: 14 | """A more complex example.""" 15 | for j in range(0, 10): # loop 1 iterates only once 16 | if j < 2: 17 | j += 1 18 | for k in range(0, 2): # loop could iterate more than once 19 | if k > 2: 20 | for i in range(0, 5): 21 | break # loop exits in the first iteration 22 | return 1 23 | else: 24 | k += 1 25 | elif j > 1: 26 | return 1 27 | else: 28 | j += 1 29 | break 30 | i = 0 31 | while i < 10: # loop iterates only once 32 | if i > 2: 33 | break 34 | else: 35 | i += 1 36 | return 4 37 | return 0 # loop 1 will always end up returning 38 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9997_forbidden_global_variables.py: -------------------------------------------------------------------------------- 1 | """Examples for E9997 forbidden-global-variables.""" 2 | 3 | 4 | def function() -> None: 5 | """A test for the global variables checker.""" 6 | # Change "value" to mean the global variable. 7 | # (the assignment would be local without "global") 8 | global VALUE 9 | VALUE = 100 10 | 11 | 12 | VALUE = 0 13 | function() 14 | print(VALUE) 15 | 16 | ex = 1 17 | 18 | def add_ex(n: int) -> int: 19 | """Add ex to n.""" 20 | return ex + n 21 | 22 | 23 | # The local variable in a comprehension is okay 24 | print({x + 1 for x in [1, 2, 3]}) 25 | print({x: x * 3 for x in [1, 2, 3]}) 26 | print(list(x + 1 for x in [1, 2, 3])) 27 | 28 | 29 | def function1() -> int: 30 | """A test for the global variables checker.""" 31 | 32 | def function2() -> None: 33 | """A test for the global variables checker.""" 34 | # In nested method, reference nonlocal variable 35 | nonlocal value 36 | value = 100 37 | 38 | # Set local 39 | value = 10 40 | function2() 41 | 42 | # Local variable reflects nonlocal change 43 | return value + 3 # 103 44 | 45 | 46 | if __name__ == '__main__': 47 | var1 = 10 # This assignment is okay: statements inside main block are not checked 48 | 49 | if var1 > 5: 50 | var2 = 13 # This assignment is also okay 51 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9998_forbidden_IO_function.py: -------------------------------------------------------------------------------- 1 | def hello() -> None: 2 | """Print a message to the user.""" 3 | # You should not use input action in some assignments 4 | name = input("What is your name?") # Error on this line 5 | 6 | # You should not use print action in some assignments 7 | print('hello, ' + name) # Error on this line 8 | 9 | 10 | if __name__ == '__main__': 11 | hello() 12 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9999_forbidden_import.py: -------------------------------------------------------------------------------- 1 | import copy # Error on this line 2 | from sys import path # Error on this line 3 | import python_ta # No error 4 | import e9999_forbidden_import_local # Error on this line 5 | 6 | __import__('math') # Error on this line 7 | -------------------------------------------------------------------------------- /examples/custom_checkers/e9999_forbidden_import_local.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyta-uoft/pyta/0539d23be047c12316158304e4837b80e1384d75/examples/custom_checkers/e9999_forbidden_import_local.py -------------------------------------------------------------------------------- /examples/custom_checkers/r9710_inconsistent_returns.py: -------------------------------------------------------------------------------- 1 | import math 2 | from typing import Optional 3 | 4 | 5 | def add_sqrts(x: float, y: float) -> Optional[float]: 6 | """Return the sum of the square roots of x and y, or None if 7 | either number is negative.""" 8 | if x >= 0 and y >= 0: 9 | return math.sqrt(x) + math.sqrt(y) 10 | else: 11 | return # Error: this should be `return None` instead. 12 | 13 | 14 | def str_to_int(s: str) -> Optional[int]: 15 | """Return the integer representation of the string s, or None if it cannot be converted.""" 16 | try: 17 | return int(s) 18 | except ValueError: 19 | return # Error: this should be `return None` instead. 20 | 21 | -------------------------------------------------------------------------------- /examples/custom_checkers/r9711_missing_return_statement.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | from typing import Optional 3 | 4 | 5 | def index_of(numbers: list[int], n: int) -> Optional[int]: 6 | """Return the index of the first occurrence of n in numbers, 7 | or None if n doesn't appear in the list. 8 | """ 9 | i = 0 10 | for number in numbers: 11 | if number == n: 12 | return i 13 | i += 1 14 | 15 | 16 | def day_name_to_number(day: str) -> int: 17 | """Return a number between 0-6 representing the given day of the week.""" 18 | if day == 'Monday': 19 | return 0 20 | elif day == 'Tuesday': 21 | return 1 22 | elif day == 'Wednesday': 23 | return 2 24 | elif day == 'Thursday': 25 | return 3 26 | elif day == 'Friday': 27 | return 4 28 | elif day == 'Saturday': 29 | return 5 30 | elif day == 'Sunday': 31 | return 6 32 | -------------------------------------------------------------------------------- /examples/custom_checkers/r9900_redundant_condition.py: -------------------------------------------------------------------------------- 1 | def return_large_number(x: int) -> int: 2 | """Return number x only if it's greater than 1000 3 | 4 | Preconditions: 5 | - x > 1000 6 | """ 7 | # the if condition is already checked by function precondition 8 | if x > 1000: # Error on this line 9 | return x 10 | 11 | 12 | def nested_condition(x: int) -> int: 13 | if x > 10: 14 | # the condition `x > 5` is already guaranteed by `x > 10` 15 | if x > 5: # Error on this line 16 | return x 17 | return 0 18 | 19 | 20 | def redundant_condition(x: bool) -> None: 21 | # the if condition is always true 22 | if x or not x: # Error on this line 23 | print("redundant") 24 | -------------------------------------------------------------------------------- /examples/custom_checkers/r9901_impossible_condition.py: -------------------------------------------------------------------------------- 1 | def print_none_negative_number(x: int) -> None: 2 | """Print number x only if it's greater or equal to 0 3 | 4 | Preconditions: 5 | - x >= 0 6 | """ 7 | # the if condition is impossible given the function precondition 8 | if x < 0: # Error on this line 9 | raise Exception("x is smaller than zero") 10 | print(x) 11 | 12 | 13 | def impossible_condition(x: bool) -> None: 14 | # the if condition is always false 15 | if x and not x: # Error on this line 16 | print("impossible") 17 | 18 | 19 | def display_number(x: int) -> str: 20 | """Display numbers 0 to 2 in word""" 21 | if x == 0: 22 | "zero" 23 | elif x == 1: 24 | return "one" 25 | elif x == 2: 26 | return "two" 27 | elif x == 2: # Error on this line 28 | return "two again" 29 | -------------------------------------------------------------------------------- /examples/custom_checkers/static_type_checker_examples/e9951_incompatible_argument_type.py: -------------------------------------------------------------------------------- 1 | def calculate_area(radius: float) -> float: 2 | """Calculate the area of a circle with the given radius""" 3 | return 3.14159 * radius * radius 4 | 5 | area = calculate_area("five") # Error: Function argument should be float, but got str 6 | 7 | def convert_to_upper(text: str) -> str: 8 | """Convert the given text to uppercase""" 9 | return text.upper() 10 | 11 | result = convert_to_upper(5) # Error: Function argument should be str, but got int 12 | -------------------------------------------------------------------------------- /examples/custom_checkers/static_type_checker_examples/e9952_incompatible_assignment.py: -------------------------------------------------------------------------------- 1 | age: int = 25 2 | age = "twenty-five" # Error: Incompatible types in assignment (expression has type "str", variable has type "int") 3 | 4 | count: int = "ten" # Error: Incompatible types in assignment (expression has type "str", variable has type "int") 5 | -------------------------------------------------------------------------------- /examples/custom_checkers/static_type_checker_examples/e9953_list_item_type_mismatch.py: -------------------------------------------------------------------------------- 1 | names: list[str] = ["Alice", "Bob", 3] # Error: List item 2 has incompatible type "int"; expected "str" 2 | 3 | numbers: list[int] = [1, 2, "three"] # Error: List item 2 has incompatible type "str"; expected "int" 4 | 5 | mixed: list[float] = [1.1, 2.2, "3.3"] # Error: List item 2 has incompatible type "str"; expected "float" 6 | -------------------------------------------------------------------------------- /examples/custom_checkers/static_type_checker_examples/e9954_unsupported_operand_types.py: -------------------------------------------------------------------------------- 1 | result = "hello" - 5 # Error: Unsupported operand types for - ("str" and "int") 2 | 3 | total = 10 + "20" # Error: Unsupported operand types for + ("int" and "str") 4 | 5 | value = 5.5 * "3" # Error: Unsupported operand types for * ("float" and "str") 6 | -------------------------------------------------------------------------------- /examples/custom_checkers/static_type_checker_examples/e9955_union_attr_error.py: -------------------------------------------------------------------------------- 1 | from typing import Union 2 | 3 | def get_status(status: Union[str, int, float]) -> str: 4 | return (status 5 | .upper()) # Error: Item "int" of "str | int | float" has no attribute "upper" 6 | # Error: Item "float" of "str | int | float" has no attribute "upper" 7 | 8 | def get_keys(data: Union[dict, list]) -> list: 9 | return data.keys() # Error: Item "list" of "dict | list" has no attribute "keys" 10 | -------------------------------------------------------------------------------- /examples/custom_checkers/static_type_checker_examples/e9956_dict_item_type_mismatch.py: -------------------------------------------------------------------------------- 1 | data: dict[int, str] = {1: "one", 2: "two", "three": 3} # Error: Dict entry 2 has incompatible type "str": "int"; expected "int": "str" 2 | 3 | info: dict[str, float] = {"pi": 3.14, "e": 2.71, 42: "1.618"} # Error: Dict entry 2 has incompatible type "int": "str"; expected "str": "float" 4 | -------------------------------------------------------------------------------- /examples/custom_checkers/static_type_checker_examples/imports_no_error.py: -------------------------------------------------------------------------------- 1 | # Imports a module with mypy errors, but mypy should not report any errors when checking this file 2 | import e9952_incompatible_assignment 3 | -------------------------------------------------------------------------------- /examples/custom_checkers/static_type_checker_examples/static_type_checker_no_error.py: -------------------------------------------------------------------------------- 1 | # Correct Function Usage 2 | def calculate_area(radius: float) -> float: 3 | """Calculate the area of a circle.""" 4 | return 3.14159 * radius * radius 5 | 6 | area = calculate_area(5.0) 7 | 8 | # Proper Variable Assignments 9 | name: str = "Alice" 10 | age: int = 30 11 | height: float = 5.9 12 | 13 | # Correct List Usage 14 | names: list[str] = ["Alice", "Bob", "Charlie"] 15 | numbers: list[int] = [1, 2, 3, 4] 16 | prices: list[float] = [9.99, 19.99, 29.99] 17 | 18 | # Correct Dict Usage 19 | data: dict[int, str] = {1: "one", 2: "two", 3: "three"} 20 | config: dict[str, float] = {"pi": 3.14, "e": 2.71} 21 | 22 | # Valid Operations 23 | result = 10 + 5 24 | value = 3.5 * 2 25 | combined_name = "Alice" + " Bob" 26 | 27 | # Union with Compatible Attribute Access 28 | from typing import Union 29 | 30 | def get_length(value: Union[str, list]) -> int: 31 | return len(value) 32 | 33 | length_of_name = get_length("Alice") 34 | length_of_list = get_length([1, 2, 3]) 35 | 36 | # Valid Empty Structures 37 | empty_list: list[int] = [] 38 | empty_dict: dict[str, int] = {} 39 | 40 | # Functions with Default Arguments 41 | def greet(name: str = "Guest") -> str: 42 | return f"Hello, {name}" 43 | 44 | greeting = greet() 45 | custom_greeting = greet("Alice") 46 | -------------------------------------------------------------------------------- /examples/ending_locations/arguments.py: -------------------------------------------------------------------------------- 1 | def fun(so, many, arguments, and_some_are_long, soooooooooooooooooooo, 2 | wrappppppppppppppppppp): 3 | pass 4 | 5 | def empty_fun(): 6 | pass 7 | 8 | fun = lambda: 3 9 | fun2 = lambda x, y: x + y 10 | 11 | def f(a: 'annotation', b=1, c=2, *d, e, f=3, **g): 12 | pass 13 | -------------------------------------------------------------------------------- /examples/ending_locations/assert.py: -------------------------------------------------------------------------------- 1 | assert True, 'Oops, something happened :-P' 2 | assert True 3 | -------------------------------------------------------------------------------- /examples/ending_locations/assign.py: -------------------------------------------------------------------------------- 1 | x = 3 2 | a = b = 1 3 | a = b = 1 4 | a, b = c 5 | *a = 1 6 | -------------------------------------------------------------------------------- /examples/ending_locations/assign_attr.py: -------------------------------------------------------------------------------- 1 | class ClassName(): 2 | def __init__(self, name2): 3 | self.name = name2 4 | self . name = name2 5 | -------------------------------------------------------------------------------- /examples/ending_locations/assign_name.py: -------------------------------------------------------------------------------- 1 | x = 3 2 | a = b = 1 3 | a, b = x 4 | -------------------------------------------------------------------------------- /examples/ending_locations/async_for.py: -------------------------------------------------------------------------------- 1 | async def fun(): 2 | """Note coroutine function must be declared with async def.""" 3 | async for a in b: 4 | if a > 5: 5 | break 6 | else: 7 | continue 8 | -------------------------------------------------------------------------------- /examples/ending_locations/async_function_def.py: -------------------------------------------------------------------------------- 1 | def async_coroutine(): 2 | pass 3 | 4 | async def fun(): 5 | await async_coroutine() 6 | -------------------------------------------------------------------------------- /examples/ending_locations/async_with.py: -------------------------------------------------------------------------------- 1 | async def fun(): 2 | async with open('/foo/bar', 'r') as f: 3 | pass -------------------------------------------------------------------------------- /examples/ending_locations/attribute.py: -------------------------------------------------------------------------------- 1 | snake.colour 2 | snake . colour 3 | snake.colour == snake.colour 4 | -------------------------------------------------------------------------------- /examples/ending_locations/aug_assign.py: -------------------------------------------------------------------------------- 1 | x += 1 2 | -------------------------------------------------------------------------------- /examples/ending_locations/await.py: -------------------------------------------------------------------------------- 1 | def async_coroutine(): 2 | pass 3 | 4 | async def fun(): 5 | await async_coroutine() 6 | -------------------------------------------------------------------------------- /examples/ending_locations/bin_op.py: -------------------------------------------------------------------------------- 1 | 1 + 2 + 3 2 | ( 100 * 42 ) 3 | ( (102) * (44) ) 4 | ((1 + 2) * (3 + 4)) -------------------------------------------------------------------------------- /examples/ending_locations/bool_op.py: -------------------------------------------------------------------------------- 1 | x = None or 1 2 | True and False and True or False -------------------------------------------------------------------------------- /examples/ending_locations/break.py: -------------------------------------------------------------------------------- 1 | while True: 2 | break -------------------------------------------------------------------------------- /examples/ending_locations/call.py: -------------------------------------------------------------------------------- 1 | print(1, 2, 3, 2 | 4 ) 3 | -------------------------------------------------------------------------------- /examples/ending_locations/class_def.py: -------------------------------------------------------------------------------- 1 | @wrapper 2 | class Foo(base1, base2): 3 | pass 4 | 5 | 6 | class Bar: 7 | def __init__(self): 8 | pass 9 | -------------------------------------------------------------------------------- /examples/ending_locations/compare.py: -------------------------------------------------------------------------------- 1 | 0 < 1 != 1 2 | 1 > 3 3 | b'5' <= b'6' 4 | 'bob' == 'bob' != 'george' 5 | -------------------------------------------------------------------------------- /examples/ending_locations/comprehension.py: -------------------------------------------------------------------------------- 1 | [x for x in range(3)] 2 | (g for ip in num for num in range(9)) 3 | ( g for ip in num for num in range(8) ) 4 | -------------------------------------------------------------------------------- /examples/ending_locations/const.py: -------------------------------------------------------------------------------- 1 | 3.1415 2 | x = 10 3 | (3) 4 | ((True)) 5 | ( 6 | 7 7 | ) 8 | print(False, ( ( True ) )) 9 | ... 10 | -------------------------------------------------------------------------------- /examples/ending_locations/continue.py: -------------------------------------------------------------------------------- 1 | for i in range(3): 2 | continue 3 | -------------------------------------------------------------------------------- /examples/ending_locations/decorators.py: -------------------------------------------------------------------------------- 1 | @wrapper 2 | @decor("hello", "world" ) 3 | def fun(): 4 | pass 5 | 6 | @ wrapper 7 | def fun(): 8 | pass 9 | -------------------------------------------------------------------------------- /examples/ending_locations/del_attr.py: -------------------------------------------------------------------------------- 1 | class Foo(): 2 | def __init__(self): 3 | self.attr = 1 4 | del self.attr 5 | del self . attr 6 | del self.attr; del self.attr 7 | -------------------------------------------------------------------------------- /examples/ending_locations/del_name.py: -------------------------------------------------------------------------------- 1 | del x 2 | -------------------------------------------------------------------------------- /examples/ending_locations/delete.py: -------------------------------------------------------------------------------- 1 | del x 2 | del x, self.attr, y[0] 3 | -------------------------------------------------------------------------------- /examples/ending_locations/dict.py: -------------------------------------------------------------------------------- 1 | a = { 'b': 1, 'c ' : 2 } 2 | b = { 3 | 'b': 1, 4 | 'c': 2 5 | } 6 | c = { 7 | 'b': 1, 8 | 'c': 2 9 | } 10 | -------------------------------------------------------------------------------- /examples/ending_locations/dict_comp.py: -------------------------------------------------------------------------------- 1 | {str(n): n for n in range(3)} 2 | { str(n): n for n in range( 4 ) } 3 | { str(n): n for n in range( 5 ) # comment here should be fine. 4 | # ..here too.. 5 | 6 | 7 | } 8 | -------------------------------------------------------------------------------- /examples/ending_locations/except_handler.py: -------------------------------------------------------------------------------- 1 | try: 2 | pass 3 | except ValueError as e: 4 | pass 5 | else: 6 | pass 7 | finally: 8 | pass -------------------------------------------------------------------------------- /examples/ending_locations/expr.py: -------------------------------------------------------------------------------- 1 | print ( 1 ) 2 | ( 100 * 42 ) 3 | 101 * 43 4 | ( (100) * (42) ) 5 | ( (111) * (22), (333) * (44) ) 6 | -------------------------------------------------------------------------------- /examples/ending_locations/for.py: -------------------------------------------------------------------------------- 1 | for i in [1, 2, 3]: 2 | break 3 | else: 4 | pass 5 | -------------------------------------------------------------------------------- /examples/ending_locations/function_def.py: -------------------------------------------------------------------------------- 1 | @wrapper 2 | def fun(arg) -> str: 3 | """ 4 | This is a function fun. 5 | """ 6 | return_annotation = "cool!" 7 | return return_annotation 8 | 9 | 10 | def fun2(arg) -> str: 11 | """ 12 | This is a function fun2. 13 | """ 14 | return_annotation = "cool!" 15 | return return_annotation 16 | -------------------------------------------------------------------------------- /examples/ending_locations/generator_exp.py: -------------------------------------------------------------------------------- 1 | (g for ip in num for num in range(9)) 2 | ( g for ip in num for num in range(9) ) 3 | -------------------------------------------------------------------------------- /examples/ending_locations/global.py: -------------------------------------------------------------------------------- 1 | def fun(): 2 | global x, y 3 | -------------------------------------------------------------------------------- /examples/ending_locations/if.py: -------------------------------------------------------------------------------- 1 | if n == 0: 2 | pass 3 | elif something: 4 | pass 5 | elif n > 0: 6 | pass 7 | else: 8 | n = 3 9 | -------------------------------------------------------------------------------- /examples/ending_locations/if_exp.py: -------------------------------------------------------------------------------- 1 | x = 1 if True else 0 2 | -------------------------------------------------------------------------------- /examples/ending_locations/import.py: -------------------------------------------------------------------------------- 1 | import astroid as ast 2 | import sample_usage.pyta_stats 3 | import astroid, sample_usage 4 | -------------------------------------------------------------------------------- /examples/ending_locations/import_from.py: -------------------------------------------------------------------------------- 1 | from transforms import TransformVisitor as tfv 2 | from sample_usage.pyta_stats import pyta_statistics, _print_stats 3 | from .. import level_is_2 as l2 4 | from ... import level_is_3 as l3 5 | -------------------------------------------------------------------------------- /examples/ending_locations/keyword.py: -------------------------------------------------------------------------------- 1 | str(object=2) 2 | str( object = 2 ) 3 | -------------------------------------------------------------------------------- /examples/ending_locations/lambda.py: -------------------------------------------------------------------------------- 1 | fun = lambda: 3 2 | fun2 = lambda x, y: x + y 3 | -------------------------------------------------------------------------------- /examples/ending_locations/list.py: -------------------------------------------------------------------------------- 1 | [] 2 | [1, 2, 3] 3 | [x, y] = 7, 8 4 | [ 5 | 1, 6 | 2, 7 | 3, 8 | 4 9 | ] 10 | 11 | -------------------------------------------------------------------------------- /examples/ending_locations/list_comp.py: -------------------------------------------------------------------------------- 1 | [ l+l for l in "str" ] 2 | [ x*y for x in [ 1, 2, 3] for y in [4, 5, 6 ] ] 3 | -------------------------------------------------------------------------------- /examples/ending_locations/module.py: -------------------------------------------------------------------------------- 1 | """This is some module documentation.""" 2 | assert True, 'Oops, something happened :-P' 3 | assert True 4 | -------------------------------------------------------------------------------- /examples/ending_locations/name.py: -------------------------------------------------------------------------------- 1 | my_var -------------------------------------------------------------------------------- /examples/ending_locations/nonlocal.py: -------------------------------------------------------------------------------- 1 | def outer(): 2 | x = y = 1 3 | def inner(): 4 | nonlocal x, y 5 | x += y 6 | inner() 7 | -------------------------------------------------------------------------------- /examples/ending_locations/pass.py: -------------------------------------------------------------------------------- 1 | def f(b): 2 | if b: 3 | pass 4 | else: 5 | return [x ** 2 for x in range(10)] 6 | -------------------------------------------------------------------------------- /examples/ending_locations/raise.py: -------------------------------------------------------------------------------- 1 | def f(b): 2 | if b: 3 | raise ValueError 4 | else: 5 | raise BaseException('error') 6 | -------------------------------------------------------------------------------- /examples/ending_locations/return.py: -------------------------------------------------------------------------------- 1 | def f(b): 2 | if b: 3 | return 4 | else: 5 | return [x ** 2 for x in range(10)] 6 | -------------------------------------------------------------------------------- /examples/ending_locations/set.py: -------------------------------------------------------------------------------- 1 | {0} 2 | { 0 } 3 | {1, 2, "hi"} 4 | -------------------------------------------------------------------------------- /examples/ending_locations/set_comp.py: -------------------------------------------------------------------------------- 1 | { x * 2 for x in [1] } 2 | { x * y for x in [0, 1, 2] for y in [4, 3, 2] if x < y } 3 | -------------------------------------------------------------------------------- /examples/ending_locations/slice.py: -------------------------------------------------------------------------------- 1 | a[:] 2 | b [ : ] 3 | c[1:] 4 | d [ 2 : ] 5 | e[1:-1:3] 6 | x = f [ 1 : - 1 : 3 ] 7 | g[2:3: 8 | 4] 9 | h[1:][:] 10 | i[:][2:] 11 | j[:][:] 12 | k[::] 13 | l[:] [:] 14 | x = m[ : ] 15 | n[:][:] [:] 16 | -------------------------------------------------------------------------------- /examples/ending_locations/starred.py: -------------------------------------------------------------------------------- 1 | *a, b = range(5) 2 | 3 | # Example 2 4 | print(*a) 5 | -------------------------------------------------------------------------------- /examples/ending_locations/subscript.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | y[0] 4 | z [ 0 ] 5 | a[:] 6 | b [ : ] 7 | c[1:] 8 | d [ 2 : ] 9 | e[1:-1:3] 10 | x = f [ 1 : - 1 : 3 ] 11 | g[2:3: 12 | 4] 13 | h[1:][:] 14 | i[:][2:] 15 | j[:][:] 16 | k[::] 17 | l[:] [:] 18 | x = m[ : ] 19 | 20 | 21 | def add(numbers: list[int]) -> list[int]: 22 | return numbers + [1] 23 | -------------------------------------------------------------------------------- /examples/ending_locations/try.py: -------------------------------------------------------------------------------- 1 | try: 2 | pass 3 | except: 4 | pass 5 | finally: 6 | pass 7 | -------------------------------------------------------------------------------- /examples/ending_locations/tuple.py: -------------------------------------------------------------------------------- 1 | (1, 2) 2 | ( 1, 2 ) 3 | (1, ) 4 | (1, ) 5 | ( 1, 2, ) 6 | ( 3, 7 | 4, 8 | 5 ) 9 | 1 , 10 | 1, 2, 11 | ( (1) * (2), 12 | (3) * (4), 13 | (5) * (6) ) 14 | ((1),) 15 | fun(2, ((1),)) 16 | fun(((1),)) 17 | (1,), (2,) 18 | (a, b) = [ 19 | 5, 6] 20 | (x, y) = [7, 8] # prevent this last comma being used 21 | () 22 | -------------------------------------------------------------------------------- /examples/ending_locations/unary_op.py: -------------------------------------------------------------------------------- 1 | not None 2 | +5 3 | -x 4 | ~72 5 | -------------------------------------------------------------------------------- /examples/ending_locations/while.py: -------------------------------------------------------------------------------- 1 | while True: 2 | print('hi') 3 | cmd = input() 4 | if cmd == 'quit': 5 | break 6 | -------------------------------------------------------------------------------- /examples/ending_locations/with.py: -------------------------------------------------------------------------------- 1 | with open('myfile.pdf') as f1, open('input.txt'): 2 | contents = f1.read() 3 | print(contents) 4 | -------------------------------------------------------------------------------- /examples/ending_locations/yield.py: -------------------------------------------------------------------------------- 1 | def yield_item(x): 2 | yield x 3 | -------------------------------------------------------------------------------- /examples/ending_locations/yield_from.py: -------------------------------------------------------------------------------- 1 | def fun(g): 2 | yield from range(g) 3 | -------------------------------------------------------------------------------- /examples/nodes/ann_assign.py: -------------------------------------------------------------------------------- 1 | """ 2 | AnnAssign astroid node 3 | 4 | A node representing an annotated assignment statement. 5 | 6 | Attributes: 7 | - annotation (NodeNG) 8 | - A Name node representing the type of the variable. 9 | - simple (int) 10 | - Whether target is a pure name or complex statement. 11 | - target (Optional[NodeNG]) 12 | - An AssignName node representing the name of the variable being 13 | assigned to. 14 | - value (Optional[Expr]) 15 | - An node that is being assigned to the variables. 16 | 17 | Example: 18 | AnnAssign( 19 | simple=1, 20 | target=AssignName(name='x'), 21 | annotation=Name(name='int'), 22 | value=Const(value=3)) 23 | """ 24 | 25 | 26 | class Student: 27 | x: int = 3 # This is the example 28 | -------------------------------------------------------------------------------- /examples/nodes/assert.py: -------------------------------------------------------------------------------- 1 | """ 2 | Assert astroid node 3 | 4 | An assertion. 5 | 6 | Attributes: 7 | - fail (Optional[NodeNG]) 8 | - A message that is shown when the assertion fails. 9 | - test (Optional[Expr]) 10 | - This holds the condition, such as a Compare node, to be evaluated 11 | True or False 12 | 13 | Example: 14 | Assert( 15 | test=Compare( 16 | left=Name(name='x'), 17 | ops=[['==', Const(value=0)]]), 18 | fail=Const(value='error')) 19 | """ 20 | 21 | assert x == 0, "error" 22 | -------------------------------------------------------------------------------- /examples/nodes/assign.py: -------------------------------------------------------------------------------- 1 | """ 2 | Assign astroid node 3 | 4 | An assignment. 5 | 6 | Attributes: 7 | - targets (Optional[list[NodeNG]]) 8 | - A list of nodes being assigned to. 9 | - type_annotation (Optional[NodeNG]) 10 | - If present, this will contain the type annotation passed by a type comment. 11 | - value (Optional[Expr]) 12 | - The value being assigned to the variables. 13 | 14 | Example 1: 15 | Assign( 16 | targets=[AssignName(name='x')], 17 | value=Const(value=3)) 18 | 19 | Example 2: 20 | Assign( 21 | targets=[ 22 | AssignName(name='a'), 23 | AssignName(name='b')], 24 | value=Const(value=1)) 25 | 26 | Example 3: 27 | Assign( 28 | targets=[ 29 | Tuple( 30 | ctx=, 31 | elts=[AssignName(name='a'), AssignName(name='b')])], 32 | value=Name(name='c')) 33 | 34 | Example 4: 35 | Assign( 36 | targets=[List( 37 | ctx=, 38 | elts=[AssignName(name='a'), Starred( 39 | ctx=, 40 | value=AssignName(name='b'))])], 41 | value=Name(name='d')) 42 | """ 43 | 44 | # Example 1 45 | x = 3 46 | 47 | # Example 2 48 | a = b = 1 49 | 50 | # Example 3 51 | a, b = c 52 | 53 | # Example 4 54 | [a, *b] = d 55 | -------------------------------------------------------------------------------- /examples/nodes/assign_attr.py: -------------------------------------------------------------------------------- 1 | """ 2 | AssignAttr astroid node 3 | 4 | To assign a value to the relationship attribute. (This is the astroid 5 | Attribute node in the specific Load context.) 6 | 7 | Attributes: 8 | - attrname (Optional[str]) 9 | - The name of the attribute that is assigned. 10 | - expr (Optional[NodeNG]) 11 | - The node object whose attribute is assigned. 12 | 13 | Example: 14 | AssignAttr( 15 | attrname='name', 16 | expr=Name(name='self')) 17 | """ 18 | 19 | 20 | class ClassName: 21 | def __init__(self, name): 22 | self.name = name 23 | -------------------------------------------------------------------------------- /examples/nodes/assign_name.py: -------------------------------------------------------------------------------- 1 | """ 2 | AssignName astroid node 3 | 4 | An assignment for a name node that appears in a Store (assignment) context. 5 | 6 | Attributes: 7 | - name (Optional[str]) 8 | - The name which is assigned to. 9 | 10 | Example: 11 | AssignName(name='x') 12 | """ 13 | 14 | x = 3 15 | -------------------------------------------------------------------------------- /examples/nodes/async_for.py: -------------------------------------------------------------------------------- 1 | """ 2 | AsyncFor astroid node 3 | 4 | Subclass of For astroid node. This node iterates over async code with a for-loop 5 | like syntax. Asynchronous code doesn't wait for an operation to complete, 6 | rather the code executes all operations in one go. Only valid in body of an 7 | AsyncFunctionDef astroid node. 8 | 9 | Attributes: 10 | # Derives directly from "For" node; see "For" node for attributes. 11 | 12 | Example: 13 | AsyncFor( 14 | target=AssignName(name='a'), 15 | iter=Name(name='b'), 16 | body=[ 17 | If( 18 | test=Compare( 19 | left=Name(name='a'), 20 | ops=[['>', Const(value=5)]]), 21 | body=[Break()], 22 | orelse=[])], 23 | orelse=[Continue()]) 24 | 25 | """ 26 | 27 | 28 | async def fun(): 29 | """Note coroutine function must be declared with async def.""" 30 | async for a in b: 31 | if a > 5: 32 | break 33 | else: 34 | continue 35 | -------------------------------------------------------------------------------- /examples/nodes/async_function_def.py: -------------------------------------------------------------------------------- 1 | """ 2 | AsyncFunctionDef astroid node 3 | 4 | Subclass of FunctionDef astroid node. An async def function definition and used 5 | for async astroid nodes like AsyncFor and AsyncWith. 6 | 7 | Attributes: 8 | # Derives directly from "FunctionDef" node; see "FunctionDef" node for attributes. 9 | 10 | Example: 11 | AsyncFunctionDef( 12 | name='animal', 13 | doc_node=Const(value='\n This is function animal.\n '), 14 | decorators=None, 15 | args=Arguments( 16 | vararg=None, 17 | kwarg=None, 18 | args=[AssignName(name='arg')], 19 | defaults=[], 20 | kwonlyargs=[], 21 | posonlyargs=[], 22 | posonlyargs_annotations=[], 23 | kw_defaults=[], 24 | annotations=[None], 25 | varargannotation=None, 26 | kwargannotation=None, 27 | kwonlyargs_annotations=[], 28 | type_comment_args=[None], 29 | type_comment_kwonlyargs=[], 30 | type_comment_posonlyargs=[]), 31 | returns=None, 32 | body=[ 33 | Assign( 34 | targets=[AssignName(name='dog')], 35 | value=Const(value='an animal')), 36 | Return(value=Name(name='dog'))]) 37 | 38 | """ 39 | 40 | 41 | @wrapper 42 | async def animal(arg): 43 | """ 44 | This is function animal. 45 | """ 46 | dog = "an animal" 47 | return dog 48 | -------------------------------------------------------------------------------- /examples/nodes/async_with.py: -------------------------------------------------------------------------------- 1 | """ 2 | AsyncWith astroid node 3 | 4 | Subclass of With astroid node, which is used to simplify set up/tear down 5 | actions for a block of code. Asynchronous code doesn't wait for an operation 6 | to complete, rather the code executes all operations in one go. Only valid in 7 | body of an AsyncFunctionDef astroid node. 8 | 9 | Attributes: 10 | - # Derives directly from "With" node; see "with" node for attributes. 11 | 12 | Example: 13 | AsyncWith( 14 | items=[ 15 | [ 16 | Call( 17 | func=Name(name='open'), 18 | args=[Const(value='/foo/bar'), Const(value='r')], 19 | keywords=None), 20 | AssignName(name='f')]], 21 | body=[Pass()]) 22 | """ 23 | 24 | 25 | async def fun(): 26 | async with open("/foo/bar", "r") as f: 27 | pass 28 | -------------------------------------------------------------------------------- /examples/nodes/attribute.py: -------------------------------------------------------------------------------- 1 | """ 2 | Attribute astroid node 3 | 4 | An expression accessing an object's attribute (This is only for Attribute nodes appearing 5 | in a Load context. For more information, see the README.) 6 | 7 | Attributes: 8 | - attrname (Optional[str]) 9 | - The name of the accessed attribute. 10 | - expr (Optional[Name]) 11 | - The Name object whose attribute is given access to. 12 | 13 | Example: 14 | Attribute( 15 | attrname='colour', 16 | expr=Name(name='snake')) 17 | """ 18 | 19 | snake.colour 20 | -------------------------------------------------------------------------------- /examples/nodes/aug_assign.py: -------------------------------------------------------------------------------- 1 | """ 2 | AugAssign astroid node 3 | 4 | An augmented assignment, which is the combination, in a single statement, of a 5 | binary operation and an assignment statement. 6 | 7 | Attributes: 8 | - op (Optional[str]) 9 | - The operator to be performed on target. 10 | - target (Optional[Name | Subscript | Attribute]) 11 | - What is being assigned to. 12 | - value (Optional[NodeNG]) 13 | - A single node to be assigned to target. 14 | 15 | Example: 16 | AugAssign( 17 | op='+=', 18 | target=AssignName(name='x'), 19 | value=Const(value=1)) 20 | """ 21 | 22 | # Example: 23 | x += 1 24 | -------------------------------------------------------------------------------- /examples/nodes/await.py: -------------------------------------------------------------------------------- 1 | """ 2 | Await astroid node 3 | 4 | An await expression. Only valid in the body of an AsyncFunctionDef. 5 | 6 | Attributes: 7 | - value (Optional[Expr]) 8 | - What the expression waits for. 9 | 10 | Example: 11 | Await( 12 | value=Call( 13 | func=Name(name='async_coroutine'), 14 | args=[], 15 | keywords=None)) 16 | """ 17 | 18 | 19 | def async_coroutine(): 20 | pass 21 | 22 | 23 | async def fun(): 24 | await async_coroutine() 25 | -------------------------------------------------------------------------------- /examples/nodes/bin_op.py: -------------------------------------------------------------------------------- 1 | """ 2 | BinOp astroid node 3 | 4 | A binary operation (like addition or division). 5 | 6 | Attributes: 7 | - left (Optional[Expr]) 8 | - What is being applied to the operator on the left side. 9 | - op (Optional[str]) 10 | - The operator to be performed on left and right. 11 | - right (Optional[Expr]) 12 | - What is being applied to the operator on the right side. 13 | 14 | Example 1: 15 | BinOp( 16 | op='+', 17 | left=Const(value=1), 18 | right=Const(value=2)) 19 | 20 | Examples of operators on primitive types; dunder function -> call and symbol: 21 | - __add__ -> + 22 | - __sub__ -> - 23 | - __mult__ -> * 24 | - __floordiv__ -> // 25 | - __mod__ -> % 26 | - __truediv__ -> / 27 | - __pow__ -> ** 28 | 29 | Refer to URL below for more information: 30 | https://docs.python.org/3/library/operator.html?highlight=operator#module-operator 31 | """ 32 | 33 | 1 + 2 34 | a * b 35 | 4 - 8 36 | 8**3 37 | -------------------------------------------------------------------------------- /examples/nodes/bool_op.py: -------------------------------------------------------------------------------- 1 | """ 2 | BoolOp astroid node 3 | 4 | A boolean operation, 'or' or 'and'. 5 | 6 | Attributes: 7 | - op (Optional[str]) 8 | - The operator, 'or' or 'and'. 9 | - values (Optional[list[Expr]]) 10 | - A list of the argument expressions 11 | 12 | Example 1: 13 | BoolOp( 14 | op='or', 15 | values=[Const(value=None), Const(value=1)]) 16 | 17 | Example 2: 18 | BoolOp( 19 | op='or', 20 | values=[Const(value=None), Const(value=1), Const(value=2)]) 21 | 22 | Example 3: 23 | BoolOp( 24 | op='or', 25 | values=[ 26 | Const(value=None), 27 | BoolOp( 28 | op='and', 29 | values=[Const(value=1), Const(value=2)])]) 30 | """ 31 | 32 | # Example 1 33 | None or 1 34 | 35 | # Example 2 36 | None or 1 or 2 37 | 38 | # Example 3 39 | None or 1 and 2 40 | -------------------------------------------------------------------------------- /examples/nodes/break.py: -------------------------------------------------------------------------------- 1 | """ 2 | Break astroid node 3 | 4 | Represents a Break Node. The break statement breaks out of the smallest 5 | enclosing for or while loop. Break has no attributes. 6 | 7 | Attributes: 8 | # No attributes. 9 | 10 | Example: 11 | Break() 12 | """ 13 | 14 | for i in range(3): 15 | break 16 | -------------------------------------------------------------------------------- /examples/nodes/compare.py: -------------------------------------------------------------------------------- 1 | """ 2 | Compare astroid node 3 | 4 | Compare node represents a value comparison between two objects, which do not need to have the same type. 5 | Value comparison operators are: '<', '>', '==', '<=', '>=', '!=" 6 | Expressions are always evaluated at most once (PRIOR to comparison) and the values are stored as attributes in the node. 7 | Multi-comparison expressions are logically equivalent to the conjunction of the individual value comparisons. 8 | 9 | Attributes: 10 | - left (Optional[Expr]) 11 | - The first value in the comparison. 12 | - ops (Optional[list[tuple(str, NodeNG)]]) 13 | - The list of operators to be performed on left. 14 | 15 | Example: 16 | Compare( 17 | left=Const(value=0), 18 | ops=[ 19 | ['<', Const(value=1)], 20 | ['!=', Const(value=1)]]) 21 | """ 22 | 23 | 0 < 1 != 1 24 | 25 | 1 > 3 26 | 27 | b"5" <= b"6" 28 | 29 | "bob" == "bob" != "george" 30 | -------------------------------------------------------------------------------- /examples/nodes/const.py: -------------------------------------------------------------------------------- 1 | """ 2 | Const astroid node 3 | 4 | Represents a literal constant node like num, str, bool, None, bytes, not 5 | computed values. 6 | 7 | Attributes: 8 | - value (object) 9 | - The value that the constant represents. These are Python literals. 10 | 11 | Example 1: 12 | Const(value=1) 13 | 14 | Example 2: 15 | Const(value=b'6') 16 | """ 17 | 18 | 1 19 | b"6" 20 | -------------------------------------------------------------------------------- /examples/nodes/continue.py: -------------------------------------------------------------------------------- 1 | """ 2 | Continue astroid node 3 | 4 | Represents a Continue node. The continue statement continues with the next 5 | iteration of the loop. Continue has no attributes. 6 | 7 | Attributes: 8 | # No attributes. 9 | 10 | Example: 11 | Continue() 12 | """ 13 | 14 | for i in range(3): 15 | continue 16 | -------------------------------------------------------------------------------- /examples/nodes/decorators.py: -------------------------------------------------------------------------------- 1 | """ 2 | Decorators astroid node 3 | 4 | A decorator is a function that alters the functionality of a function, method, 5 | or class without having to directly use subclasses or change the source code of 6 | the function being decorated. A Decorators node is a child node of FunctionDef 7 | node. 8 | 9 | Attributes: 10 | - nodes (Optional[list[Name | Call]]) 11 | - A list of decorators this node contains. 12 | 13 | Example: 14 | Decorators( 15 | nodes=[ 16 | Name(name='wrapper'), 17 | Name(name='decor')]) 18 | """ 19 | 20 | 21 | @wrapper 22 | @decor 23 | def fun(): 24 | pass 25 | -------------------------------------------------------------------------------- /examples/nodes/del_attr.py: -------------------------------------------------------------------------------- 1 | """ 2 | DelAttr astroid node 3 | 4 | This node represents an attribute of an object being deleted. 5 | This is an astroid Attribute node specifically in the Del (being deleted) context. 6 | 7 | Attributes: 8 | - attrname (Optional[str]) 9 | - The name of the attribute being deleted. 10 | - expr (Optional[Name]) 11 | - The node object whose attribute is being deleted. 12 | 13 | Example: 14 | DelAttr( 15 | attrname='attr', 16 | expr=Name(name='self')) 17 | """ 18 | 19 | 20 | class Foo: 21 | def __init__(self): 22 | self.attr = 1 23 | del self.attr 24 | -------------------------------------------------------------------------------- /examples/nodes/del_name.py: -------------------------------------------------------------------------------- 1 | """ 2 | DelName astroid node 3 | 4 | The name of an object being deleted. 5 | This is a Name astroid node that specifically appears in the Del 6 | (being deleted) context. 7 | 8 | Attributes: 9 | - name (str) 10 | - The node being deleted. 11 | 12 | Example 1: 13 | Delete(targets=[DelName(name='x')]) 14 | 15 | * DelName is in the targets list of the Delete node 16 | 17 | """ 18 | 19 | # Example 1 20 | del x 21 | -------------------------------------------------------------------------------- /examples/nodes/delete.py: -------------------------------------------------------------------------------- 1 | """ 2 | Delete astroid node 3 | 4 | Delete node represents a del statement. 5 | 6 | Attributes: 7 | - targets (list[DelName | DelAttr | Subscript | assignable]) 8 | - The targets to be deleted. These must have a Del expression context, 9 | such as DelName and DelAttr themselves, or any assignable node 10 | except AssignName and AssignAttr. (See the README for more details.) 11 | 12 | Example 1: 13 | Delete(targets=[DelName(name='x')]) 14 | 15 | Example 2: 16 | Delete(targets=[ 17 | DelName(name='x'), 18 | DelAttr( 19 | attrname='attr', 20 | expr=Name(name='self')), 21 | Subscript( 22 | ctx=, 23 | value=Name(name='y'), 24 | slice=Const(value=0))]) 25 | """ 26 | 27 | # Example 1 28 | del x 29 | 30 | # Example 2 31 | del x, self.attr, y[0] 32 | -------------------------------------------------------------------------------- /examples/nodes/dict.py: -------------------------------------------------------------------------------- 1 | """ 2 | Dict astroid node 3 | 4 | This node represents the Python dictionary objects. 5 | 6 | Attributes: 7 | - items (list[tuple[NodeNG, NodeNG]]) 8 | - Contains a list of key-value-pair tuples, where key and value are 9 | nodes. 10 | 11 | Example 1: 12 | Dict(items=[[Const(value='b'), Const(value=1)]]) 13 | 14 | Example 2: 15 | Dict(items=[[Name(name='my_key'), Name(name='my_value')], 16 | [BinOp( 17 | op='+', 18 | left=Const(value=3), 19 | right=Const(value=2)), 20 | Subscript( 21 | ctx=, 22 | value=Name(name='x'), 23 | slice=Const(value=0))]]) 24 | 25 | Representation tree of Dict nodes show each KVP as a list; 26 | however, the actual .items attribute stores each KVP as a tuple. 27 | """ 28 | 29 | # Example 1 30 | {"b": 1} 31 | 32 | # Example 2 33 | {my_key: my_value, 3 + 2: x[0]} 34 | -------------------------------------------------------------------------------- /examples/nodes/dict_unpack.py: -------------------------------------------------------------------------------- 1 | """ 2 | DictUnpack astroid node 3 | 4 | Represents the unpacking of dicts into dicts using PEP 448. 5 | 6 | Attributes: 7 | *This node does not have any explicit attributes* 8 | 9 | Example: 10 | - The double star (**) preceding the dictionary represents dictionary 11 | unpacking for the nested dictionary. Here is the astroid AST representation 12 | of them example: 13 | - Dict(items=[[Const(value=1), Const(value=1)], 14 | [DictUnpack(), Dict(items=[[Const(value=2), Const(value=2)]]]] 15 | - Note that 'DictUnpack()' node is the 'key' and the nested dictionary is 16 | 'value' in the [key, value] pair of the outermost Dict node. 17 | 18 | This is node is NOT created when passing a dictionary into a function using ** (e.g. f(**x)) 19 | """ 20 | 21 | # Example 1 22 | {1: 1, **{2: 2}} 23 | -------------------------------------------------------------------------------- /examples/nodes/expr.py: -------------------------------------------------------------------------------- 1 | """ 2 | Expr astroid node 3 | 4 | When an expression, such as a function call, appears as a statement by itself 5 | with its return value not used or stored, it is wrapped in Expr node. 6 | 7 | Attributes: 8 | - value (NodeNG) 9 | - Value holds nodes like Name, Lambda, Yield or YieldFrom. 10 | 11 | Examples: 12 | 13 | Expr(value=Call( 14 | func=Name(name='print'), 15 | args=[Const(value=1)], 16 | keywords=None)) 17 | 18 | Expr(value=BinOp( 19 | op='*', 20 | left=Const(value=100), 21 | right=Const(value=42))) 22 | 23 | Expr(value=Const(value=0)) 24 | 25 | Expr(value=Tuple( 26 | ctx=, 27 | elts=[Const(value=1), Const(value=2)])) 28 | 29 | Expr(value=Subscript( 30 | ctx=, 31 | value=Const(value='a'), 32 | slice=Const(value=0))) 33 | 34 | Expr(value=Subscript( 35 | ctx=, 36 | value=Dict(items=[[Const(value='a'), Const(value=0)], [Const(value='b'), Const(value=1)]]), 37 | slice=Const(value=0))) 38 | """ 39 | 40 | # Examples 41 | print(1) 42 | 100 * 42 43 | 0 44 | (1, 2) 45 | "a"[0] 46 | (1, 2)[0] 47 | [1, 2, 3][0] 48 | {"a": 0, "b": 1}[0] 49 | -------------------------------------------------------------------------------- /examples/nodes/formatted_value.py: -------------------------------------------------------------------------------- 1 | """ 2 | FormattedValue astroid node 3 | 4 | Represents a single formatting field in an f-string (formatted string literal). 5 | 6 | Attributes: 7 | - value (Expr) 8 | - The value to be formatted into the string. 9 | - format_spec (Optional[JoinedStr]) 10 | - The formatting to be applied to the value. 11 | 12 | Example 1: 13 | JoinedStr(values=[Const(value='My name is '), FormattedValue( 14 | value=Name(name='name'), 15 | format_spec=None)]) 16 | 17 | * NOTE : The example above is of a FormattedValue Node "{name}" within 18 | a JoinedStr Node "f'My name is {name}'". 19 | 20 | Example 2: 21 | JoinedStr(values=[FormattedValue( 22 | value=Const(value=3.14159), 23 | format_spec=JoinedStr(values=[Const(value='.3')]))]) 24 | 25 | * NOTE : The example above is of a FormattedValue Node "{3.14159:.3}'" within 26 | a JoinedStr Node "f'{3.14159:.3}'". 27 | """ 28 | 29 | # Example 1 30 | f"My name is {name}" 31 | 32 | # Example 2 33 | f"{3.14159:.3}" 34 | -------------------------------------------------------------------------------- /examples/nodes/generator_exp.py: -------------------------------------------------------------------------------- 1 | """ 2 | GeneratorExp astroid node 3 | 4 | A generator expressions is a generator object that is used when iterating over 5 | the elements one at a time. 6 | 7 | Attributes: 8 | - elt (NodeNG) 9 | - Represents the node that will be evaluated for each item. 10 | - generators (list[Comprehension]) 11 | - Nodes are comprehension nodes. See Comprehension.py for more details. 12 | 13 | Example: 14 | GeneratorExp( 15 | elt=Tuple( 16 | ctx=, 17 | elts=[Name(name='i'), Name(name='j')]), 18 | generators=[Comprehension( 19 | is_async=0, 20 | target=AssignName(name='i'), 21 | iter=Call( 22 | func=Name(name='range'), 23 | args=[Const(value=4)], 24 | keywords=None), 25 | ifs=[]), 26 | Comprehension( 27 | is_async=0, 28 | target=AssignName(name='j'), 29 | iter=Call( 30 | func=Name(name='range'), 31 | args=[Name(name='i')], 32 | keywords=None), 33 | ifs=[])]) 34 | """ 35 | 36 | # Example 37 | ((i, j) for i in range(4) for j in range(i)) 38 | -------------------------------------------------------------------------------- /examples/nodes/global.py: -------------------------------------------------------------------------------- 1 | """ 2 | Global astroid node 3 | 4 | Global sets a variable to be a global variable which can be called outside of 5 | the scope of a function. 6 | 7 | Attributes: 8 | - names (list[str]) 9 | - Names of variables whose values are to be assigned to the 10 | corresponding global variable. 11 | 12 | Example 1: 13 | Global(names=['x']) 14 | 15 | Example 2: 16 | Global(names=['x', 'y']) 17 | """ 18 | 19 | # Example 1 20 | global x 21 | 22 | # Example 2 23 | global x, y 24 | -------------------------------------------------------------------------------- /examples/nodes/if_exp.py: -------------------------------------------------------------------------------- 1 | """ 2 | IfExp astroid node 3 | 4 | An if statement written in an expression form. 5 | (IfExp node represents an expression, not a statement.) 6 | 7 | Attributes: 8 | - test (NodeNG) 9 | - Holds a single node such as Compare to evaluate the truth condition of. 10 | - body (NodeNG) 11 | - A Node representing the suite to be executed when the if expression 12 | evalutes to True. 13 | - orelse (NodeNG) 14 | - The Node representing the suite to be executed when the if expression 15 | evaluates to False. 16 | 17 | Example 1: 18 | IfExp( 19 | test=Const(value=True), 20 | body=Const(value=1), 21 | orelse=Const(value=0)) 22 | 23 | Example 2: 24 | IfExp( 25 | test=Compare( 26 | left=Name(name='eval_expr'), 27 | ops=[['==', Name(name='expected')]]), 28 | body=BinOp( 29 | op='+', 30 | left=Name(name='x'), 31 | right=Name(name='y')), 32 | orelse=Name(name='something')) 33 | """ 34 | 35 | # Example 1 36 | 1 if True else 0 37 | 38 | # Example 2 39 | x + y if eval_expr == expected else something 40 | -------------------------------------------------------------------------------- /examples/nodes/import.py: -------------------------------------------------------------------------------- 1 | """ 2 | Import astroid node 3 | 4 | Represents an import statement. Unlike ImportFrom, Import node doesn't have 5 | the attribute "level". 6 | 7 | Attributes: 8 | - names (list[tuple[str, Optional[str]]]) 9 | - List of tuples containing the name of the module and its assigned alias (if applicable) 10 | 11 | Example 1: 12 | Import(names=[['astroid', 'ast']]) 13 | 14 | Example 2: 15 | Import(names=[['sample_usage.pyta_stats', None]]) 16 | 17 | Example 3: 18 | Import(names=[['astroid', None], ['sample_usage', None]]) 19 | 20 | The representation trees display the pair of module name and its alias as a list, when the actual 21 | data type is a tuple. 22 | """ 23 | 24 | # Example 3: 25 | # Example 1: 26 | import astroid 27 | import astroid as ast 28 | 29 | import sample_usage 30 | 31 | # Example 2: 32 | import sample_usage.pyta_stats 33 | -------------------------------------------------------------------------------- /examples/nodes/import_from.py: -------------------------------------------------------------------------------- 1 | """ 2 | ImportFrom astroid node 3 | 4 | This node represents statement from x import y. 5 | 6 | Attributes: 7 | - modname (str) 8 | - The name of the module that is being imported from 9 | (can be an empty string for relative imports). 10 | - names (list[tuple[str, Optional[str]]]) 11 | - List of tuples representing the imported objects and the aliases (if applicable) 12 | - level (Optional[int]) 13 | - An integer that holds the level of the relative import. 0 means 14 | absolute import. 15 | 16 | Example 1: 17 | ImportFrom( 18 | modname='transforms', 19 | names=[['TransformVisitor', 'tfv']], 20 | level=None) 21 | 22 | Example 2: 23 | ImportFrom( 24 | modname='sample_usage.pyta_stats', 25 | names=[['pyta_statistics', None], ['_print_stats', None]], 26 | level=None) 27 | 28 | Example 3: 29 | ImportFrom( 30 | modname='', 31 | names=[['level_is_2', 'l2']], 32 | level=2) 33 | 34 | Example 4: 35 | ImportFrom( 36 | modname='pack3', 37 | names=[['level_is_3', 'l3']], 38 | level=3) 39 | """ 40 | 41 | # Example 1: 42 | from transforms import TransformVisitor as tfv 43 | 44 | # Example 2: 45 | from sample_usage.pyta_stats import _print_stats, pyta_statistics 46 | 47 | # Example 4: 48 | from ...pack3 import level_is_3 as l3 49 | 50 | # Example 3: 51 | from .. import level_is_2 as l2 52 | -------------------------------------------------------------------------------- /examples/nodes/joined_str.py: -------------------------------------------------------------------------------- 1 | """ 2 | JoinedStr astroid node 3 | 4 | Represents a list of string expressions to be joined in 5 | f-strings (formatted string literals). 6 | 7 | Attributes: 8 | - values (Optional[list[FormattedValue | Const]]) 9 | - The string expressions to be joined. 10 | 11 | Example 1: 12 | JoinedStr(values=[Const(value='hello world')]) 13 | 14 | Example 2: 15 | JoinedStr(values=[ 16 | Const(value='name: '), 17 | FormattedValue( 18 | value=Name(name='name'), 19 | format_spec=None), 20 | Const(value=', age: '), 21 | FormattedValue( 22 | value=Name(name='age'), 23 | format_spec=JoinedStr(values=[Const(value='.0f')]))]) 24 | 25 | * Note that there is another JoinedStr in the format_spec of the FormattedValue. 26 | This JoinedStr contains a str Const representing how to format a FormattedValue value 27 | """ 28 | 29 | # Example 1 30 | f"hello world" 31 | 32 | # Example 2 33 | f"name: {name}, age: {age:.0f}" 34 | -------------------------------------------------------------------------------- /examples/nodes/keyword.py: -------------------------------------------------------------------------------- 1 | """ 2 | Keyword astroid node 3 | 4 | A keyword argument, kwargs, to a function call or class definition. 5 | 6 | Attributes: 7 | - arg (str) 8 | - A string of the parameter name. 9 | - value (NodeNG) 10 | - A node to pass into the arg. 11 | 12 | Example 1: 13 | Call( 14 | func=Name(name='str'), 15 | args=[], 16 | keywords=[Keyword( 17 | arg='object', 18 | value=Const(value=2))]) 19 | 20 | * Note that the Keyword is inside of the keywords list in the Call node. 21 | """ 22 | 23 | str(object=2) 24 | -------------------------------------------------------------------------------- /examples/nodes/list.py: -------------------------------------------------------------------------------- 1 | """ 2 | List astroid node 3 | 4 | This node represents the Python list objects. 5 | 6 | Attributes: 7 | - elts (list[Expr]) 8 | - The elements in this list, which can be any expression. 9 | - ctx (Context) 10 | - The context in which this list is to be used, either Load or Store. 11 | 12 | Example 1: 13 | List( 14 | ctx=, 15 | elts=[]) 16 | 17 | Example 2: 18 | List( 19 | ctx=, 20 | elts=[ 21 | Const(value=1), 22 | Const(value=2), 23 | Const(value=3)]) 24 | 25 | Example 3: 26 | Assign( 27 | targets=[List( 28 | ctx=, 29 | elts=[AssignName(name='x'), AssignName(name='y')])], 30 | value=Tuple( 31 | ctx=, 32 | elts=[Const(value=7), Const(value=8)])) 33 | 34 | Example 3 demonstrates a Store context instead of Load 35 | """ 36 | 37 | # Example 1 38 | [] 39 | 40 | # Example 2 41 | [1, 2, 3] 42 | 43 | # Example 3 44 | [x, y] = 7, 8 45 | -------------------------------------------------------------------------------- /examples/nodes/module.py: -------------------------------------------------------------------------------- 1 | """ 2 | Module astroid Node 3 | 4 | Anything in this file is wrapped in a module node. 5 | 6 | Attributes: 7 | - body (Optional[list[Expr]]) 8 | - The contents of the module 9 | 10 | Example: 11 | Module( 12 | name='', 13 | doc_node=None, 14 | file='', 15 | path=[''], 16 | package=False, 17 | pure_python=True, 18 | future_imports=set(), 19 | body=[Expr(value=Name(name='x'))]) 20 | """ 21 | 22 | x 23 | -------------------------------------------------------------------------------- /examples/nodes/name.py: -------------------------------------------------------------------------------- 1 | """ 2 | Name astroid node 3 | 4 | This node is used to represent variables in Python, in the context of Loading 5 | the variable's contents. For Storing and Deleting, see AssignName and DelName. 6 | 7 | Attributes: 8 | - name (str) 9 | - The name of the variable. 10 | 11 | Example: 12 | Name(name='my_var') 13 | """ 14 | 15 | my_var 16 | -------------------------------------------------------------------------------- /examples/nodes/nonlocal.py: -------------------------------------------------------------------------------- 1 | """ 2 | Nonlocal astroid node 3 | 4 | This node represents statements formed with the Python "nonlocal" identifier, 5 | which causes the identified variable names to be interpreted as referring to 6 | the variables with those names previously bound in the nearest enclosing 7 | (non-global) scope. Note that several variables can be rebound in the same 8 | Nonlocal statement. Also, variables already defined in the current scope trying 9 | be rebound as nonlocals will raise a SyntaxWarning. 10 | 11 | Attributes: 12 | - names (list[str]) 13 | - The raw names of variables to be rebound as nonlocal. 14 | 15 | Example: 16 | Nonlocal(names=['x', 'y']) 17 | """ 18 | 19 | 20 | def outer(): 21 | x = y = 1 22 | 23 | def inner(): 24 | nonlocal x, y 25 | x += y 26 | 27 | inner() 28 | -------------------------------------------------------------------------------- /examples/nodes/pass.py: -------------------------------------------------------------------------------- 1 | """ 2 | Pass astroid node 3 | 4 | Pass represents the pass null operation, which has no attributes. 5 | 6 | Example: 7 | Pass() 8 | """ 9 | 10 | pass 11 | -------------------------------------------------------------------------------- /examples/nodes/return.py: -------------------------------------------------------------------------------- 1 | """ 2 | Return astroid node 3 | 4 | This node represents the Python return statement, which can return any 5 | expression from None to a function Call, or even cause the function to exit 6 | without returning anything. 7 | 8 | Attributes: 9 | - value (Optional[Expr]) 10 | - Optionally, the value to be returned, which can be any possible 11 | expression. 12 | 13 | Example 1: 14 | Return(value=None) 15 | 16 | Example 2: 17 | Return(value=Const(value=None)) 18 | 19 | Example 3: 20 | Return(value=ListComp( 21 | elt=BinOp( 22 | op='**', 23 | left=Name(name='x'), 24 | right=Const(value=2)), 25 | generators=[Comprehension( 26 | is_async=0, 27 | target=AssignName(name='x'), 28 | iter=Call( 29 | func=Name(name='range'), 30 | args=[Const(value=10)], 31 | keywords=None), 32 | ifs=[])])) 33 | """ 34 | 35 | # Example 1 36 | return 37 | 38 | # Example 2 39 | return None 40 | 41 | # Example 3 42 | return [x**2 for x in range(10)] 43 | -------------------------------------------------------------------------------- /examples/nodes/set.py: -------------------------------------------------------------------------------- 1 | """ 2 | Set astroid node 3 | 4 | This node represents the Python set object. 5 | 6 | Attributes: 7 | - elts (list[Expr]) 8 | - The elements in this set, which can be any immutable/hashable 9 | type expression. 10 | 11 | Example 1: 12 | Set(elts=[Const(value=0)]) 13 | 14 | Example 2: 15 | Set(elts=[ 16 | Const(value=1), 17 | Const(value=2), 18 | Const(value='hi')] 19 | """ 20 | 21 | # Example 1 22 | {0} 23 | 24 | # Example 2 25 | {1, 2, "hi"} 26 | -------------------------------------------------------------------------------- /examples/nodes/starred.py: -------------------------------------------------------------------------------- 1 | """ 2 | Starred astroid node 3 | 4 | This node represents a starred variable reference, used for unpacking iterables 5 | into lists. This type of node usually appears under a List, Tuple, or Call node. 6 | 7 | Attributes: 8 | - value (Name) 9 | - The variable to be unpacked into as a list. 10 | - ctx (class[expr_context]) 11 | - The context in which this starred variable is used, one of 12 | Load or Store. 13 | 14 | Example 1: (nested in Tuple) 15 | Assign( 16 | targets=[Tuple( 17 | ctx=, 18 | elts=[Starred( 19 | ctx=, 20 | value=AssignName(name='a')), 21 | AssignName(name='b')])], 22 | value=Call( 23 | func=Name(name='range'), 24 | args=[Const(value=5)], 25 | keywords=None)) 26 | 27 | Example 2: (nested in Call) 28 | Call( 29 | func=Name(name='print'), 30 | args=[Starred( 31 | ctx=, 32 | value=Name(name='x'))], 33 | keywords=None) 34 | """ 35 | 36 | # Example 1 37 | *a, b = range(5) 38 | 39 | # Example 2 40 | print(*x) 41 | -------------------------------------------------------------------------------- /examples/nodes/subscript.py: -------------------------------------------------------------------------------- 1 | """ 2 | Subscript astroid node 3 | 4 | This node represents iterable subscripting using '[' and ']' in Python. 5 | 6 | Attributes: 7 | - value (Expr) 8 | - The iterable whose elements are to be accessed by the subscript. 9 | - slice (Expr) 10 | - The index or slice of the iterable being subscripted. 11 | - ctx (class[expr_context]) 12 | - The context in which this subscripted iterable is used, one of 13 | Load, Store, or Del. 14 | 15 | Example: 16 | Subscript( 17 | ctx=, 18 | value=Name(name='x'), 19 | slice=Const(value=0)) 20 | """ 21 | 22 | x[0] 23 | -------------------------------------------------------------------------------- /examples/nodes/tuple.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tuple astroid node 3 | 4 | This node represents the Python tuple objects. 5 | 6 | Attributes: 7 | - elts (list[Expr]) 8 | - The elements in this tuple, which can be any expression. 9 | - ctx (class[expr_context]) 10 | - The context in which this list is to be used, either Load or Store. 11 | 12 | Example 1: 13 | Tuple( 14 | ctx=, 15 | elts=[]) 16 | 17 | Example 2: 18 | Tuple( 19 | ctx=, 20 | elts=[Const(value=1), Const(value=2)]) 21 | 22 | Example 3: (nested in Assign) 23 | Assign( 24 | targets=[Tuple( 25 | ctx=, 26 | elts=[AssignName(name='x'), AssignName(name='y')])], 27 | value=List( 28 | ctx=, 29 | elts=[Const(value=7), Const(value=8)])) 30 | """ 31 | 32 | # Example 1: 33 | () 34 | 35 | # Example 2: 36 | (1, 2) 37 | 38 | # Example 3: 39 | (x, y) = [7, 8] 40 | -------------------------------------------------------------------------------- /examples/nodes/unary_op.py: -------------------------------------------------------------------------------- 1 | """ 2 | UnaryOp astroid node 3 | 4 | This node represents unary operators such as positive, negation, and 5 | inversion (complementing). 6 | 7 | See https://docs.python.org/3/reference/expressions.html#unary-arithmetic-and-bitwise-operations. 8 | 9 | Attributes: 10 | - op (class[UAdd | USub | Not | Invert]) 11 | - The unary operation to be performed on the operand. 12 | - operand (Optional[Expr]) 13 | - The single expression to be operated on. 14 | 15 | Example 1: 16 | UnaryOp( 17 | op='not', 18 | operand=Const(value=None)) 19 | 20 | Example 2: 21 | UnaryOp( 22 | op='+', 23 | operand=Const(value=5)) 24 | 25 | Example 3: 26 | UnaryOp( 27 | op='-', 28 | operand=Name(name='x')) 29 | 30 | Example 4: 31 | UnaryOp( 32 | op='~', 33 | operand=Const(value=72)) 34 | """ 35 | 36 | # Example 1: 37 | not None 38 | 39 | # Example 2: 40 | +5 41 | 42 | # Example 3: 43 | -x 44 | 45 | # Example 4: 46 | ~72 47 | -------------------------------------------------------------------------------- /examples/nodes/while.py: -------------------------------------------------------------------------------- 1 | """ 2 | While astroid node 3 | 4 | This node represents the Python while loop structure. 5 | 6 | Attributes: 7 | - test (Expr) 8 | - The boolean-valued expression to determine whether the loop continues. 9 | - body (list[Statement]) 10 | - The code to be performed while the loop condition is true. 11 | - orelse (list[Statement]) 12 | - The code in the else statement (to be performed once the loop exits). 13 | 14 | Example: 15 | While( 16 | test=Const(value=True), 17 | body=[Break()], 18 | orelse=[Pass()]) 19 | """ 20 | 21 | while True: 22 | break 23 | else: 24 | pass 25 | -------------------------------------------------------------------------------- /examples/nodes/with.py: -------------------------------------------------------------------------------- 1 | """ 2 | With astroid node 3 | 4 | This node represents the Python "with" statement, which is used to simplify 5 | set up/tear down actions for a block of code. 6 | 7 | Attributes: 8 | - items (list[tuple[Expr]]) 9 | - The expressions or expression-reassigned Name pairs that are to be 10 | set up by this "with" and torn down after the completion of body. 11 | Expressions are usually Call or Name nodes. 12 | - body (list[Statement]) 13 | - The code to be performed until the with statement closes. 14 | 15 | Example 1: 16 | With( 17 | items=[[Call( 18 | func=Name(name='open'), 19 | args=[Subscript( 20 | ctx=, 21 | value=Attribute( 22 | attrname='argv', 23 | expr=Name(name='sys')), 24 | slice=Const(value=1))], 25 | keywords=None), 26 | AssignName(name='f')], 27 | [Call( 28 | func=Name(name='open'), 29 | args=[Const(value='input.txt')], 30 | keywords=None), 31 | AssignName(name='i')]], 32 | body=[Pass()]) 33 | """ 34 | 35 | with open(sys.argv[1]) as f, open("input.txt") as i: 36 | pass 37 | -------------------------------------------------------------------------------- /examples/nodes/yield.py: -------------------------------------------------------------------------------- 1 | """ 2 | Yield astroid node 3 | 4 | This node represents the Python "yield" statement, which turns a function 5 | into a generator object that returns the "yielded" results iteratively as 6 | needed by the calling program. 7 | 8 | Attributes: 9 | - value (Optional[Expr]) 10 | - Optionally, the value to be yielded. 11 | 12 | Example 1: 13 | Yield(value=None) 14 | 15 | Example 2: 16 | Yield(value=Const(value=None)) 17 | 18 | Example 3: 19 | Yield(value=Name(name='x')) 20 | """ 21 | 22 | # Example 1 23 | yield 24 | 25 | # Example 2 26 | yield None 27 | 28 | # Example 3 29 | yield x 30 | -------------------------------------------------------------------------------- /examples/nodes/yield_from.py: -------------------------------------------------------------------------------- 1 | """ 2 | YieldFrom astroid node 3 | 4 | This node represents the Python "yield from" statement, which functions 5 | similarly to the "yield" statement except that the generator can delegate 6 | some generating work to another generator. 7 | 8 | Attributes: 9 | - value (Expr) 10 | - The generator that this YieldFrom is delegating work to, 11 | which must be a generator expression (either a GeneratorExp node 12 | or an Expr node containing a generator expression). 13 | 14 | Example (nested in Expr): 15 | FunctionDef( 16 | name='fun', 17 | doc_node=None, 18 | decorators=None, 19 | args=Arguments( 20 | vararg=None, 21 | kwarg=None, 22 | args=[AssignName(name='g')], 23 | defaults=[], 24 | kwonlyargs=[], 25 | posonlyargs=[], 26 | posonlyargs_annotations=[], 27 | kw_defaults=[], 28 | annotations=[None], 29 | varargannotation=None, 30 | kwargannotation=None, 31 | kwonlyargs_annotations=[], 32 | type_comment_args=[None], 33 | type_comment_kwonlyargs=[], 34 | type_comment_posonlyargs=[]), 35 | returns=None, 36 | body=[Expr( 37 | value=YieldFrom( 38 | value=Call( 39 | func=Name(name='range'), 40 | args=[Name(name='g')], 41 | keywords=None)))]) 42 | """ 43 | 44 | 45 | def fun(g): 46 | yield from range(g) 47 | -------------------------------------------------------------------------------- /examples/pylint/c0103_naming_convention_violation.py: -------------------------------------------------------------------------------- 1 | def is_positive(number: int) -> bool: 2 | """Check if number is positive.""" 3 | Result = number > 0 # Error on this line: Invalid name 'Result' 4 | return Result 5 | -------------------------------------------------------------------------------- /examples/pylint/c0104_disallowed_name.py: -------------------------------------------------------------------------------- 1 | def is_positive(number: int) -> bool: 2 | """Check if number is positive.""" 3 | foo = number > 0 # Error on this line: Blacklisted name 'foo' 4 | return foo 5 | -------------------------------------------------------------------------------- /examples/pylint/c0112_empty_docstring.py: -------------------------------------------------------------------------------- 1 | def is_false(obj: bool) -> bool: 2 | """ 3 | """ 4 | return obj is False 5 | -------------------------------------------------------------------------------- /examples/pylint/c0114_missing_module_docstring.py: -------------------------------------------------------------------------------- 1 | # Error on this line (no docstring) 2 | ... 3 | -------------------------------------------------------------------------------- /examples/pylint/c0115_missing_class_docstring.py: -------------------------------------------------------------------------------- 1 | """C0115: Missing class docstring.""" 2 | class A: 3 | # Error on this line (no docstring) 4 | pass 5 | -------------------------------------------------------------------------------- /examples/pylint/c0116_missing_function_docstring.py: -------------------------------------------------------------------------------- 1 | """C0116: Missing function docstring.""" 2 | def f() -> None: 3 | pass 4 | 5 | 6 | async def g(): 7 | pass 8 | -------------------------------------------------------------------------------- /examples/pylint/c0117_unnecessary_negation.py: -------------------------------------------------------------------------------- 1 | number = 5 2 | if not number >= 0: # Error on this line 3 | number_category = 'negative' 4 | else: 5 | number_category = 'non-negative' 6 | -------------------------------------------------------------------------------- /examples/pylint/c0121_singleton_comparison.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | def square(number: Optional[float]) -> Optional[float]: 4 | """Return the square of the number.""" 5 | if number == None: # Error on this line 6 | return None 7 | else: 8 | return number**2 9 | -------------------------------------------------------------------------------- /examples/pylint/c0123_unidiomatic_typecheck.py: -------------------------------------------------------------------------------- 1 | from typing import Union 2 | 3 | def is_int(obj: Union[int, float, str]) -> bool: 4 | """Check if the given object is of type 'int'.""" 5 | return type(obj) == int # Error on this line 6 | -------------------------------------------------------------------------------- /examples/pylint/c0201_consider_iterating_dictionary.py: -------------------------------------------------------------------------------- 1 | menu = {'pizza': 12.50, 'fries': 5.99, 'fizzy drink': 2.00} 2 | 3 | for item in menu.keys(): # Error on this line 4 | print("My store sells {}.".format(item)) 5 | -------------------------------------------------------------------------------- /examples/pylint/c0209_consider_using_f_string.py: -------------------------------------------------------------------------------- 1 | name = "Bob" 2 | print("Hi! My name is %s!" % name) # Error on this line 3 | print("{0} is my name!".format(name)) # Error on this line 4 | -------------------------------------------------------------------------------- /examples/pylint/c0301_line_too_long.py: -------------------------------------------------------------------------------- 1 | TEMP = 'This constant is in the file c0301_line_too_long.py. This is a very long line.... in fact it is too long!' 2 | -------------------------------------------------------------------------------- /examples/pylint/c0303_trailing_whitespace.py: -------------------------------------------------------------------------------- 1 | # Error on line below, there are spaces after the print statement. 2 | print('Hello') 3 | -------------------------------------------------------------------------------- /examples/pylint/c0304_missing_final_newline.py: -------------------------------------------------------------------------------- 1 | print("Hello World!") # Trailing newline is absent: -------------------------------------------------------------------------------- /examples/pylint/c0305_trailing_newlines.py: -------------------------------------------------------------------------------- 1 | print("Hello World!") # Too many newline characters after this line 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /examples/pylint/c0321_multiple_statements.py: -------------------------------------------------------------------------------- 1 | def is_positive(number: int) -> str: 2 | """Return whether the number is 'positive' or 'negative'.""" 3 | if number > 0: return 'positive' # Error on this line 4 | else: 5 | return 'negative' 6 | 7 | 8 | def is_negative(number: int) -> bool: 9 | """Return whether the number is negative.""" 10 | b = number < 0; return b # Error on this line 11 | -------------------------------------------------------------------------------- /examples/pylint/c0325_superfluous_parens.py: -------------------------------------------------------------------------------- 1 | pizza_toppings = ['extra cheese', 'pineapple', 'anchovies'] 2 | 3 | if ('anchovies' in pizza_toppings): # Error on this line 4 | print("Awesome!") 5 | -------------------------------------------------------------------------------- /examples/pylint/c0410_multiple_imports.py: -------------------------------------------------------------------------------- 1 | import sys, math 2 | -------------------------------------------------------------------------------- /examples/pylint/c0411_wrong_import_order.py: -------------------------------------------------------------------------------- 1 | from assignment_1 import solution # Your own modules should be imported last 2 | import sys # "standard modules" should be imported first 3 | -------------------------------------------------------------------------------- /examples/pylint/c0412_ungrouped_imports.py: -------------------------------------------------------------------------------- 1 | from sys import byteorder # Same packages should be grouped 2 | from math import floor 3 | from sys import stdin # Same packages should be grouped 4 | -------------------------------------------------------------------------------- /examples/pylint/c0413_wrong_import_position.py: -------------------------------------------------------------------------------- 1 | my_list = ['a', 'b'] 2 | import math # Imports should be at the top (below the docstring) 3 | -------------------------------------------------------------------------------- /examples/pylint/c0414_useless_import_alias.py: -------------------------------------------------------------------------------- 1 | import os as os # Error on this line 2 | -------------------------------------------------------------------------------- /examples/pylint/c0415_import_outside_toplevel.py: -------------------------------------------------------------------------------- 1 | def import_module(): 2 | import something # Error on this line 3 | -------------------------------------------------------------------------------- /examples/pylint/c1802_use_implicit_booleaness_not_len.py: -------------------------------------------------------------------------------- 1 | ARRAY = [1, 2, 3] 2 | 3 | if len(ARRAY): # Error on this line 4 | pass 5 | -------------------------------------------------------------------------------- /examples/pylint/c2503_non_ascii_name.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- # Error on this line 2 | z̯̯͡a̧͎̺l̡͓̫g̹̲o̡̼̘ = 2 # Error on this line 3 | my_int = 3 4 | -------------------------------------------------------------------------------- /examples/pylint/cyclic_import_helper.py: -------------------------------------------------------------------------------- 1 | from r0401_cyclic_import import Egg 2 | 3 | 4 | class Chicken: 5 | """ Which came first? """ 6 | eggs: list[Egg] 7 | -------------------------------------------------------------------------------- /examples/pylint/e0101_return_in_init.py: -------------------------------------------------------------------------------- 1 | class Animal: 2 | """A carbon-based life form that eats and moves around.""" 3 | _name: str 4 | 5 | def __init__(self, name: str) -> None: 6 | self._name = name 7 | return True # Error on this line 8 | -------------------------------------------------------------------------------- /examples/pylint/e0102_function_redefined.py: -------------------------------------------------------------------------------- 1 | def is_positive(number: int) -> bool: 2 | """Check if number is positive.""" 3 | return number > 0 4 | 5 | 6 | def is_positive(number: int) -> bool: # Error on this line: Function redefined 7 | """Check if number is positive.""" 8 | return number >= 0 9 | -------------------------------------------------------------------------------- /examples/pylint/e0103_not_in_loop.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | def add(lst: list[int]) -> int: 4 | """Calculate the sum of the elements in the given list.""" 5 | temp = 0 6 | for item in lst: 7 | temp += item 8 | break # Error on this line 9 | return temp 10 | -------------------------------------------------------------------------------- /examples/pylint/e0104_return_outside_function.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | def add(lst: list[int]) -> None: 4 | """Calculate the sum of the elements in the given list.""" 5 | temp = 0 6 | for item in lst: 7 | temp += item 8 | 9 | return False # Error on this line 10 | -------------------------------------------------------------------------------- /examples/pylint/e0107_nonexistent_operator.py: -------------------------------------------------------------------------------- 1 | spam = 0 2 | ++spam # Error on this line 3 | --spam # Error on this line 4 | -------------------------------------------------------------------------------- /examples/pylint/e0108_duplicate_argument_name.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | def add(lst: list[int], lst: list[int]) -> int: # Error on this line 4 | """Calculate the sum of the elements in the given list.""" 5 | temp = 0 6 | for item in lst: 7 | temp += item 8 | return temp 9 | -------------------------------------------------------------------------------- /examples/pylint/e0111_bad_reversed_sequence.py: -------------------------------------------------------------------------------- 1 | reversed(12345) # Error on this line 2 | -------------------------------------------------------------------------------- /examples/pylint/e0118_used_prior_global_declaration.py: -------------------------------------------------------------------------------- 1 | TIME = 0 2 | 3 | def timestep() -> None: 4 | """Increment global time by 1.""" 5 | print(TIME) # Error on this line 6 | global TIME 7 | TIME += 1 8 | -------------------------------------------------------------------------------- /examples/pylint/e0119_misplaced_format_function.py: -------------------------------------------------------------------------------- 1 | print('My name is {}').format('Adam') # Error on this line 2 | -------------------------------------------------------------------------------- /examples/pylint/e0202_method_hidden.py: -------------------------------------------------------------------------------- 1 | class Person: 2 | """Generic person with a name and a hobby.""" 3 | name: str 4 | hobby: str 5 | 6 | def __init__(self, name: str, hobby: str) -> None: 7 | self.name = name 8 | self.hobby = hobby 9 | 10 | def hobby(self) -> str: # Error on this line 11 | return "No hobbies; I just work and study!" 12 | -------------------------------------------------------------------------------- /examples/pylint/e0203_access_member_before_definition.py: -------------------------------------------------------------------------------- 1 | class Animal: 2 | """A carbon-based life form that eats and moves around.""" 3 | 4 | def __init__(self, name: str) -> None: 5 | print(self._name) # Haven't defined `self._name` yet, can't use 6 | self._name = name 7 | -------------------------------------------------------------------------------- /examples/pylint/e0211_no_method_argument.py: -------------------------------------------------------------------------------- 1 | class Saxophone: 2 | """A jazzy musical instrument.""" 3 | _sound: str 4 | 5 | def __init__(self) -> None: 6 | self._sound = "Saxamaphone...." 7 | 8 | def make_sound() -> None: # Error on this line 9 | print("Don't know what sound I can make!") 10 | -------------------------------------------------------------------------------- /examples/pylint/e0213_no_self_argument.py: -------------------------------------------------------------------------------- 1 | class SecretKeeper: 2 | """A class which stores a secret as a private attribute.""" 3 | _secret: str 4 | 5 | def __init__(self, secret: str) -> None: 6 | self._secret = secret 7 | 8 | def guess_secret(obj, secret) -> bool: # Error: 'obj' should be 'self' 9 | """Guess the private secret.""" 10 | return obj._secret == secret 11 | -------------------------------------------------------------------------------- /examples/pylint/e0239_inherit_non_class.py: -------------------------------------------------------------------------------- 1 | class FancyFloat('float'): # Error on this line 2 | """A fancy floating point number.""" 3 | pass 4 | -------------------------------------------------------------------------------- /examples/pylint/e0241_duplicate_bases.py: -------------------------------------------------------------------------------- 1 | class Animal: 2 | """A carbon-based life form that eats and moves around.""" 3 | pass 4 | 5 | class Dog(Animal, Animal): # Only include Animal once to inherit properly 6 | """A man's best friend.""" 7 | pass 8 | -------------------------------------------------------------------------------- /examples/pylint/e0301_non_iterator_returned.py: -------------------------------------------------------------------------------- 1 | class Iterator: 2 | def __init__(self, end, start=0): 3 | self.n = start 4 | self.end = end 5 | 6 | def __iter__(self): # Error on this line 7 | return self 8 | -------------------------------------------------------------------------------- /examples/pylint/e0302_unexpected_special_method_signature.py: -------------------------------------------------------------------------------- 1 | class Animal: 2 | """A carbon-based life form that eats and moves around.""" 3 | _name: str 4 | 5 | def __init__(self, name: str) -> None: 6 | self._name = name 7 | 8 | def __str__(self, unexpected_argument: str) -> str: # Error on this line 9 | return unexpected_argument 10 | -------------------------------------------------------------------------------- /examples/pylint/e0303_invalid_length_returned.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | class Company: 4 | """A company with some employees.""" 5 | 6 | def __init__(self, employees: list[str]) -> None: 7 | self._employees = employees 8 | 9 | def __len__(self) -> int: 10 | return -1 # Error on this line 11 | -------------------------------------------------------------------------------- /examples/pylint/e0304_invalid_bool_returned.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | class Company: 4 | """A company with some employees.""" 5 | 6 | def __init__(self, employees: list[str]) -> None: 7 | self._employees = employees 8 | 9 | def __bool__(self) -> bool: 10 | return {'employees': self._employees} # Error on this line 11 | -------------------------------------------------------------------------------- /examples/pylint/e0306_invalid_repr_returned.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | class Company: 4 | """A company with some employees.""" 5 | 6 | def __init__(self, employees: list[str]) -> None: 7 | self._employees = employees 8 | 9 | def __repr__(self) -> str: 10 | return {'employees': self._employees} # Error on this line 11 | -------------------------------------------------------------------------------- /examples/pylint/e0307_invalid_str_returned.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | class Company: 4 | """A company with some employees.""" 5 | 6 | def __init__(self, employees: list[str]) -> None: 7 | self._employees = employees 8 | 9 | def __str__(self) -> str: 10 | return {'employees': self._employees} # Error on this line 11 | -------------------------------------------------------------------------------- /examples/pylint/e0401_import_error.py: -------------------------------------------------------------------------------- 1 | import missing_module # This module does not exist 2 | -------------------------------------------------------------------------------- /examples/pylint/e0601_used_before_assignment.py: -------------------------------------------------------------------------------- 1 | print(a) # Error on this line 2 | a = 1 3 | -------------------------------------------------------------------------------- /examples/pylint/e0602_undefined_variable.py: -------------------------------------------------------------------------------- 1 | var1 = 1 2 | 3 | print(var1) 4 | print(var2) # Error on this line 5 | -------------------------------------------------------------------------------- /examples/pylint/e0611_no_name_in_module.py: -------------------------------------------------------------------------------- 1 | from math import does_not_exist 2 | -------------------------------------------------------------------------------- /examples/pylint/e0632_unbalanced_tuple_unpacking.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | def set_values() -> tuple[int, int]: 4 | """Return a tuple of two integers.""" 5 | var1 = 1 6 | var2 = 2 7 | return var1, var2 8 | 9 | # Error on the following line. Cannot unpack 2 items into 3 variables. 10 | one, two, three = set_values() 11 | -------------------------------------------------------------------------------- /examples/pylint/e0633_unpacking_non_sequence.py: -------------------------------------------------------------------------------- 1 | one, two = 15 # Cannot unpack one thing into two things 2 | -------------------------------------------------------------------------------- /examples/pylint/e0643_potential_index_error.py: -------------------------------------------------------------------------------- 1 | coffees = ['americano', 'latte', 'macchiato', 'mocha'] 2 | print(coffees[4]) # Error on this line, invalid index 3 | -------------------------------------------------------------------------------- /examples/pylint/e0701_bad_except_order.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | def divide(numerator: float, denominator: float) -> Optional[float]: 4 | """Divide the numerator by the denominator.""" 5 | try: 6 | return numerator / denominator 7 | except Exception: 8 | print("Some exception occurd! But I don't know which one?!") 9 | except ZeroDivisionError: 10 | print("This exception block will never be reached!") 11 | -------------------------------------------------------------------------------- /examples/pylint/e0702_raising_bad_type.py: -------------------------------------------------------------------------------- 1 | raise 1 # Error on this line 2 | -------------------------------------------------------------------------------- /examples/pylint/e0704_misplaced_bare_raise.py: -------------------------------------------------------------------------------- 1 | def divide(numerator: float, denominator: float) -> float: 2 | """Divide the numerator by the denominator.""" 3 | try: 4 | return numerator / denominator 5 | except ZeroDivisionError: 6 | print("Can't divide by 0!") 7 | raise # Error on this line 8 | -------------------------------------------------------------------------------- /examples/pylint/e0710_raising_non_exception.py: -------------------------------------------------------------------------------- 1 | class NotAnException: 2 | """This class does not inherit from BaseException.""" 3 | pass 4 | 5 | raise NotAnException() 6 | -------------------------------------------------------------------------------- /examples/pylint/e0711_notimplemented_raised.py: -------------------------------------------------------------------------------- 1 | class Account: 2 | """Abstract base class describing the API for an account.""" 3 | _balance: float 4 | 5 | def __init__(self, balance: float) -> None: 6 | self._balance = balance 7 | 8 | def withdraw(self, amount: float) -> float: 9 | """Withdraw some money from this account.""" 10 | # Error on the following line: Use `NotImplementedError` instead 11 | raise NotImplemented 12 | -------------------------------------------------------------------------------- /examples/pylint/e0712_catching_non_exception.py: -------------------------------------------------------------------------------- 1 | class NotAnException: 2 | """This class does not inherit from BaseException.""" 3 | pass 4 | 5 | try: 6 | n = 5 / 0 7 | except NotAnException: # Error on this line: NotAnException does not inherit 8 | pass # from BaseException 9 | -------------------------------------------------------------------------------- /examples/pylint/e1003_bad_super_call.py: -------------------------------------------------------------------------------- 1 | class Foo: 2 | pass 3 | 4 | 5 | class Bar(Foo): 6 | def __init__(self): 7 | super(Foo, self).__init__() # Error on this line 8 | -------------------------------------------------------------------------------- /examples/pylint/e1101_no_member.py: -------------------------------------------------------------------------------- 1 | x = 'hello world' 2 | print(x.prop) # Error: strings don't have a 'prop' attribute 3 | print(x.meth()) # Error: strings don't have a 'meth' method 4 | -------------------------------------------------------------------------------- /examples/pylint/e1102_not_callable.py: -------------------------------------------------------------------------------- 1 | x = 10 2 | print(x()) # Error on this line 3 | -------------------------------------------------------------------------------- /examples/pylint/e1111_assignment_from_no_return.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | def add_fruit(fruit_basket: list[str], fruit: str) -> None: 4 | """Add fruit to fruit_basket.""" 5 | fruit_basket.append(fruit) 6 | 7 | basket = ['apple', 'apple', 'orange'] 8 | new_basket = add_fruit(basket, 'banana') # Error on this line 9 | print(new_basket) # Prints `None` 10 | -------------------------------------------------------------------------------- /examples/pylint/e1120_no_value_for_parameter.py: -------------------------------------------------------------------------------- 1 | def get_sum(x: int, y: int, z: int) -> int: 2 | """Return the sum of x, y and z.""" 3 | return x + y + z 4 | 5 | get_sum(1, 2) # Error on this line 6 | -------------------------------------------------------------------------------- /examples/pylint/e1121_too_many_function_args.py: -------------------------------------------------------------------------------- 1 | def get_sum(x: int, y: int) -> int: 2 | """Return the sum of x and y.""" 3 | return x + y 4 | 5 | get_sum(1, 2, 3) # Error on this line 6 | -------------------------------------------------------------------------------- /examples/pylint/e1123_unexpected_keyword_arg.py: -------------------------------------------------------------------------------- 1 | def print_greeting(name: str) -> None: 2 | """Print a greeting to the person with the given name.""" 3 | print("Hello {}!".format(name)) 4 | 5 | print_greeting(first_name="Arthur") # Error on this line 6 | -------------------------------------------------------------------------------- /examples/pylint/e1126_invalid_sequence_index.py: -------------------------------------------------------------------------------- 1 | a = ['p', 'y', 'T', 'A'] 2 | print(a['p']) # Error on this line 3 | -------------------------------------------------------------------------------- /examples/pylint/e1127_invalid_slice_index.py: -------------------------------------------------------------------------------- 1 | a = ['p', 'y', 'T', 'A'] 2 | print(a['p': 'A']) # Error on this line 3 | -------------------------------------------------------------------------------- /examples/pylint/e1128_assignment_from_none.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | def add_fruit(fruit_basket: list[str], fruit: str) -> None: 4 | """Add fruit to fruit_basket.""" 5 | fruit_basket.append(fruit) 6 | return None 7 | 8 | basket = ['apple', 'apple', 'orange'] 9 | new_basket = add_fruit(basket, 'banana') # Error on this line 10 | print(new_basket) # Prints `None` 11 | -------------------------------------------------------------------------------- /examples/pylint/e1129_not_context_manager.py: -------------------------------------------------------------------------------- 1 | with 'ctxmanager' as ctx: # Error on this line 2 | pass 3 | -------------------------------------------------------------------------------- /examples/pylint/e1130_invalid_unary_operand_type.py: -------------------------------------------------------------------------------- 1 | print(-[1, 2, 3]) # Error on this line 2 | -------------------------------------------------------------------------------- /examples/pylint/e1131_unsupported_binary_operation.py: -------------------------------------------------------------------------------- 1 | a = [1, 2] 2 | b = {'p': 1} 3 | c = a + b # Error on this line 4 | -------------------------------------------------------------------------------- /examples/pylint/e1133_not_an_iterable.py: -------------------------------------------------------------------------------- 1 | for number in 123: # Error on this line 2 | print(number) 3 | -------------------------------------------------------------------------------- /examples/pylint/e1134_not_a_mapping.py: -------------------------------------------------------------------------------- 1 | def func(a: int, b: float) -> None: 2 | pass 3 | 4 | 5 | def call_func() -> None: 6 | a = 1 7 | func(**{'a': 10, 'b': 15.2}) # This works 8 | func(**a) # Error on this line: non-mapping value 'a' used in a mapping context 9 | -------------------------------------------------------------------------------- /examples/pylint/e1135_unsupported_membership_test.py: -------------------------------------------------------------------------------- 1 | lst = 1132424 2 | if 'a' in lst: # Error on this line 3 | print('unsupported membership test') 4 | -------------------------------------------------------------------------------- /examples/pylint/e1136_unsubscriptable_object.py: -------------------------------------------------------------------------------- 1 | a = [[1, 2], 5] 2 | print(a[1][0]) # Error on this line 3 | -------------------------------------------------------------------------------- /examples/pylint/e1137_unsupported_assignment_operation.py: -------------------------------------------------------------------------------- 1 | my_number = 1.345 2 | my_number[0] = 2 # Error on this line 3 | 4 | my_string = "Hello World!" 5 | my_string[6:] = "Universe!" # Error on this line 6 | -------------------------------------------------------------------------------- /examples/pylint/e1138_unsupported_delete_operation.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | class NamedList: 4 | """A contaner class for storing a list of named integers.""" 5 | 6 | def __init__(self, names: list[str], values: list[int]) -> None: 7 | self._names = names 8 | self._values = values 9 | 10 | def __getitem__(self, name: str) -> int: 11 | idx = self._names.index(name) 12 | return self._values[idx] 13 | 14 | def __contains__(self, name: str) -> bool: 15 | return name in self._names 16 | 17 | 18 | named_list = NamedList(['a', 'b', 'c'], [1, 2, 3]) 19 | print('c' in named_list) # Prints True 20 | del named_list['c'] # Error on this line 21 | print('c' in named_list) 22 | -------------------------------------------------------------------------------- /examples/pylint/e1141_dict_iter_missing_items.py: -------------------------------------------------------------------------------- 1 | data = {'x': 1, 'y': 2, 'z': 3} 2 | for key, value in data: # Error on this line 3 | pass 4 | 5 | -------------------------------------------------------------------------------- /examples/pylint/e1143_unhashable_member.py: -------------------------------------------------------------------------------- 1 | data = {} 2 | numbers = [1, 2, 3] 3 | data[numbers] = True # Error on this line 4 | -------------------------------------------------------------------------------- /examples/pylint/e1144_invalid_slice_step.py: -------------------------------------------------------------------------------- 1 | greeting = 'HELLO!' 2 | print(greeting[::0]) # Error on this line 3 | -------------------------------------------------------------------------------- /examples/pylint/e1305_too_many_format_args.py: -------------------------------------------------------------------------------- 1 | name = 'Amy' 2 | age = '17' 3 | country = 'England' 4 | city = 'London' 5 | 6 | # Error on the following line 7 | s = '{} who is {} lives in {}'.format(name, age, country, city) 8 | -------------------------------------------------------------------------------- /examples/pylint/e1306_too_few_format_args.py: -------------------------------------------------------------------------------- 1 | s = '{} and {}'.format('first') # Error on this line 2 | -------------------------------------------------------------------------------- /examples/pylint/e1307_bad_string_format_type.py: -------------------------------------------------------------------------------- 1 | print("%d" % ('10')) # Error on this line 2 | -------------------------------------------------------------------------------- /examples/pylint/e1310_bad_str_strip_call.py: -------------------------------------------------------------------------------- 1 | filename = 'attachment.data' 2 | basename = filename.strip('data') # Error on this line 3 | print(basename) # Prints 'chment.' 4 | -------------------------------------------------------------------------------- /examples/pylint/e3701_invalid_field_call.py: -------------------------------------------------------------------------------- 1 | from dataclasses import field 2 | 3 | money = field(default=5) # Error on this line 4 | -------------------------------------------------------------------------------- /examples/pylint/e4702_modified_iterating_dict.py: -------------------------------------------------------------------------------- 1 | data = {'x': 1, 'y': 2, 'z': 3} 2 | 3 | for key, value in data: 4 | data['w'] = 0 # Error on this line 5 | -------------------------------------------------------------------------------- /examples/pylint/e4703_modified_iterating_set.py: -------------------------------------------------------------------------------- 1 | data = {1, 2, 3} 2 | 3 | for x in data: 4 | data.remove(3) # Error on this line 5 | -------------------------------------------------------------------------------- /examples/pylint/r0123_literal_comparison.py: -------------------------------------------------------------------------------- 1 | num = 256 2 | assert num is 256 3 | 4 | num = 257 5 | assert num is 257 # Assertion fails if typed into a Python interpreter 6 | 7 | chars = 'this_string_passes' 8 | assert chars is 'this_string_passes' 9 | 10 | chars = 'this string fails' 11 | assert chars is 'this string fails' # Assertion fails if typed into a Python interpreter 12 | -------------------------------------------------------------------------------- /examples/pylint/r0124_comparison_with_itself.py: -------------------------------------------------------------------------------- 1 | 5 == 5 # Error on this line 2 | -------------------------------------------------------------------------------- /examples/pylint/r0133_comparison_of_constants.py: -------------------------------------------------------------------------------- 1 | def is_equal_to_one() -> bool: 2 | return 1 == 1 # Error on this line 3 | -------------------------------------------------------------------------------- /examples/pylint/r0201_no_self_use.py: -------------------------------------------------------------------------------- 1 | class CashRegister: 2 | """A cash register for storing money and making change.""" 3 | _current_balance: float 4 | 5 | def __init__(self, balance: float) -> None: 6 | self._current_balance = balance 7 | 8 | def add_small_coins(self, nickels: int = 0, dimes: int = 0, quarters: int = 0) -> float: 9 | """Return the dollar value of the small coins.""" 10 | return 0.05 * nickels + 0.10 * dimes + 0.25 * quarters 11 | -------------------------------------------------------------------------------- /examples/pylint/r0205_useless_object_inheritance.py: -------------------------------------------------------------------------------- 1 | class A(object): 2 | pass 3 | -------------------------------------------------------------------------------- /examples/pylint/r0401_cyclic_import.py: -------------------------------------------------------------------------------- 1 | from cyclic_import_helper import Chicken 2 | 3 | 4 | class Egg: 5 | """ Which came first? """ 6 | offspring: Chicken 7 | -------------------------------------------------------------------------------- /examples/pylint/r0402_consider_using_from_import.py: -------------------------------------------------------------------------------- 1 | import python_ta.contracts as contracts # Error on this line 2 | -------------------------------------------------------------------------------- /examples/pylint/r0902_too_many_instance_attributes.py: -------------------------------------------------------------------------------- 1 | class MyClass(object): 2 | """Class with too many instance attributes.""" 3 | 4 | def __init__(self) -> None: 5 | self.animal = 'Dog' 6 | self.bread = 'Sourdough' 7 | self.liquid = 'Water' 8 | self.colour = 'Black' 9 | self.shape = 'Circle' 10 | self.direction = 'Up' 11 | self.clothing = 'Shirt' 12 | self.number = 3 13 | -------------------------------------------------------------------------------- /examples/pylint/r0912_too_many_branches.py: -------------------------------------------------------------------------------- 1 | def lots_of_branches(arg: bool) -> None: 2 | """Example to demonstrate max branching.""" 3 | if arg == 1: 4 | pass 5 | elif arg == 2: 6 | pass 7 | elif arg == 3: 8 | pass 9 | elif arg == 4: 10 | pass 11 | elif arg == 5: 12 | pass 13 | elif arg == 6: 14 | pass 15 | elif arg == 7: 16 | pass 17 | elif arg == 8: 18 | pass 19 | elif arg == 9: 20 | pass 21 | elif arg == 10: 22 | pass 23 | elif arg == 11: 24 | pass 25 | elif arg == 12: 26 | pass 27 | elif arg == 13: 28 | pass 29 | -------------------------------------------------------------------------------- /examples/pylint/r0913_too_many_arguments.py: -------------------------------------------------------------------------------- 1 | def foo_bar(arg1: int, arg2: int, arg3: int, arg4: int, arg5: int, 2 | arg6: int) -> None: 3 | """I have too many arguments.""" 4 | pass 5 | -------------------------------------------------------------------------------- /examples/pylint/r0914_too_many_locals.py: -------------------------------------------------------------------------------- 1 | def too_many_locals() -> None: 2 | """Example function that has to many local variables.""" 3 | local_variable_1 = 1 4 | local_variable_2 = 2 5 | local_variable_3 = 3 6 | local_variable_4 = 4 7 | local_variable_5 = 5 8 | local_variable_6 = 6 9 | local_variable_7 = 7 10 | local_variable_8 = 8 11 | local_variable_9 = 9 12 | local_variable_10 = 10 13 | local_variable_11 = 11 14 | local_variable_12 = 12 15 | local_variable_13 = 13 16 | local_variable_14 = 14 17 | local_variable_15 = 15 18 | local_variable_16 = 16 19 | -------------------------------------------------------------------------------- /examples/pylint/r0916_too_many_boolean_expressions.py: -------------------------------------------------------------------------------- 1 | def number_choice(x: int, y: int, z: int) -> None: 2 | # Error on line below 3 | if (x or (y and z)) or (x % 53 == 7 or (z % x == y and z % 2 == 1) or ((x == y) and not (z == y))): 4 | print('nice choice of numbers') 5 | else: 6 | print('pick better numbers') 7 | -------------------------------------------------------------------------------- /examples/pylint/r1701_consider_merging_isinstance.py: -------------------------------------------------------------------------------- 1 | from typing import Any 2 | 3 | 4 | def is_int_or_str(mystery: Any) -> bool: 5 | """Return whether mystery is an int or str, or some other type.""" 6 | return isinstance(mystery, int) or isinstance(mystery, str) # Error on this line 7 | -------------------------------------------------------------------------------- /examples/pylint/r1702_too_many_nested_blocks.py: -------------------------------------------------------------------------------- 1 | """Example for too many nested blocks""" 2 | from __future__ import annotations 3 | from typing import Optional 4 | 5 | def cross_join(x_list: list[Optional[int]], y_list: list[Optional[int]], 6 | z_list: list[Optional[int]]) -> list[tuple[int, int, int]]: 7 | """Perform an all-by-all join of all elements in the input lists. 8 | 9 | Note: This function skips elements which are None. 10 | """ 11 | cross_join_list = [] 12 | for x in x_list: # Error on this line: "Too many nested blocks" 13 | if x is not None: 14 | for y in y_list: 15 | if y is not None: 16 | for z in z_list: 17 | if z is not None: 18 | cross_join_list.append((x, y, z)) 19 | return cross_join_list 20 | -------------------------------------------------------------------------------- /examples/pylint/r1704_redefined_argument_from_local.py: -------------------------------------------------------------------------------- 1 | def greet_person(name, friends) -> None: 2 | """Print the name of a person and all their friends.""" 3 | print("My name is {}".format(name)) 4 | for name in friends: # Error on this line 5 | print("I am friends with {}".format(name)) 6 | -------------------------------------------------------------------------------- /examples/pylint/r1707_trailing_comma_tuple.py: -------------------------------------------------------------------------------- 1 | my_lucky_number = 7, # Error on this line 2 | print(my_lucky_number) # Prints (7,) 3 | -------------------------------------------------------------------------------- /examples/pylint/r1712_consider_swap_variables.py: -------------------------------------------------------------------------------- 1 | original = 1 2 | new = 2 3 | temp = original # Error on this line 4 | 5 | original = new 6 | new = temp 7 | -------------------------------------------------------------------------------- /examples/pylint/r1713_consider_using_join.py: -------------------------------------------------------------------------------- 1 | letters = ['H', 'e', 'l', 'l', 'o'] 2 | word = '' 3 | for letter in letters: 4 | word += letter # Error on this line 5 | -------------------------------------------------------------------------------- /examples/pylint/r1714_consider_using_in.py: -------------------------------------------------------------------------------- 1 | from typing import Any 2 | 3 | 4 | def f(x: Any) -> bool: 5 | """Return whether x is one of a few different values.""" 6 | return x == 1 or x == "hello" or x == 2.5 # Error on this line 7 | -------------------------------------------------------------------------------- /examples/pylint/r1715_consider_using_get.py: -------------------------------------------------------------------------------- 1 | dictionary = dict() 2 | 3 | if 'key' in dictionary: # Error on this line 4 | variable = dictionary['key'] 5 | else: 6 | variable = 'default' 7 | -------------------------------------------------------------------------------- /examples/pylint/r1716_chained_comparison.py: -------------------------------------------------------------------------------- 1 | if a < b and b < c: # Error on this line 2 | pass 3 | -------------------------------------------------------------------------------- /examples/pylint/r1721_unnecessary_comprehension.py: -------------------------------------------------------------------------------- 1 | tuple_x = (1, 2, 3) 2 | 3 | listed_x = [x for x in tuple_x] # Error on this line 4 | -------------------------------------------------------------------------------- /examples/pylint/r1725_super_with_arguments.py: -------------------------------------------------------------------------------- 1 | class DummyClass: 2 | def __init__(self): 3 | super(DummyClass, self).__init__() # Error on this line 4 | -------------------------------------------------------------------------------- /examples/pylint/r1726_simplifiable_condition.py: -------------------------------------------------------------------------------- 1 | if True and a: # Error on this line 2 | pass 3 | -------------------------------------------------------------------------------- /examples/pylint/r1727_condition_evals_to_constant.py: -------------------------------------------------------------------------------- 1 | if a or True: # Error on this line 2 | pass 3 | -------------------------------------------------------------------------------- /examples/pylint/r1732_consider_using_with.py: -------------------------------------------------------------------------------- 1 | file = open('my_file.txt', 'r') # Error on this line: need to manually close file 2 | file.close() 3 | -------------------------------------------------------------------------------- /examples/pylint/r1733_unnecessary_dict_index_lookup.py: -------------------------------------------------------------------------------- 1 | sample_dict = {"key_one": "value_one", "key_two": "value_two"} 2 | 3 | for key, value in sample_dict.items(): 4 | print(key, sample_dict[key]) # Error on this line 5 | -------------------------------------------------------------------------------- /examples/pylint/r1734_use_list_literal.py: -------------------------------------------------------------------------------- 1 | lst = [1, 2, 3, 4] 2 | even_lst = list() # Error on this line. 3 | 4 | for x in lst: 5 | if x % 2 == 0: 6 | even_lst.append(x) 7 | -------------------------------------------------------------------------------- /examples/pylint/r1735_use_dict_literal.py: -------------------------------------------------------------------------------- 1 | students_info = [[1002123, "Alex H", "CS"], [1001115, "Jack K", "PSY"]] 2 | 3 | cs_student_dict = dict() # Error on this line. 4 | 5 | for student in students_info: 6 | if student[2] == "CS": 7 | cs_student_dict[student[0]] = student[1] 8 | -------------------------------------------------------------------------------- /examples/pylint/r1736_unnecessary_list_index_lookup.py: -------------------------------------------------------------------------------- 1 | colours = ['red', 'blue', 'yellow', 'green'] 2 | 3 | for index, colour in enumerate(colours): 4 | print(index) 5 | print(colours[index]) # Error on this line 6 | -------------------------------------------------------------------------------- /examples/pylint/w0101_unreachable.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | 4 | def add(lst: list[int]) -> int: 5 | """Return the sum of the elements in the given list.""" 6 | temp = 0 7 | for item in lst: 8 | temp += item 9 | return temp 10 | temp += 1 # Error on this line 11 | -------------------------------------------------------------------------------- /examples/pylint/w0102_dangerous_default_value.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | def make_list(n: int, lst: list[int]=[]) -> list[int]: 4 | for i in range(n): 5 | lst.append(i) 6 | return lst 7 | 8 | 9 | print(make_list(5)) 10 | print(make_list(5)) 11 | -------------------------------------------------------------------------------- /examples/pylint/w0104_pointless_statement.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | def add(lst: list[int]) -> int: 4 | """Calculate the sum of the elements in the given list.""" 5 | temp = 0 6 | for item in lst: 7 | temp += item 8 | temp # Error on this line 9 | -------------------------------------------------------------------------------- /examples/pylint/w0105_pointless_string_statement.py: -------------------------------------------------------------------------------- 1 | def say_hi() -> None: 2 | """Prints 'hi' to the console.""" 3 | message = "hi" 4 | "say hi" # Error on this line 5 | print(message) 6 | -------------------------------------------------------------------------------- /examples/pylint/w0106_expression_not_assigned.py: -------------------------------------------------------------------------------- 1 | lst = [1, 2, 3] 2 | lst.append(4), "Appended 4 to my list!" # Eror on this line 3 | -------------------------------------------------------------------------------- /examples/pylint/w0107_unnecessary_pass.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | def add(lst: list[int]) -> int: 4 | """Calculate the sum of the elements in the given list.""" 5 | temp = 0 6 | for item in lst: 7 | temp += item 8 | pass # Error on this line 9 | return temp 10 | -------------------------------------------------------------------------------- /examples/pylint/w0108_unnecessary_lambda.py: -------------------------------------------------------------------------------- 1 | def add_one(num: int) -> int: 2 | """Calculate the sum of the elements in the given list.""" 3 | return num + 1 4 | 5 | 6 | (lambda x: add_one(x))(1) # Error on this line 7 | -------------------------------------------------------------------------------- /examples/pylint/w0109_duplicate_key.py: -------------------------------------------------------------------------------- 1 | ex = { 2 | 'runner1': '5km', 3 | 'runner1': '7km' 4 | } 5 | print(ex) # Prints {'runner1': '7km'} 6 | -------------------------------------------------------------------------------- /examples/pylint/w0122_exec_used.py: -------------------------------------------------------------------------------- 1 | def dynamic_execution(code_block: str) -> None: 2 | exec(code_block) # Error on this line 3 | -------------------------------------------------------------------------------- /examples/pylint/w0123_eval_used.py: -------------------------------------------------------------------------------- 1 | from typing import Any 2 | 3 | 4 | def dynamic_evaluation(expression: str) -> Any: 5 | eval(expression) # Error on this line 6 | -------------------------------------------------------------------------------- /examples/pylint/w0124_confusing_with_statement.py: -------------------------------------------------------------------------------- 1 | with open('file.txt') as fh1, fh2: # Error on this line 2 | pass 3 | -------------------------------------------------------------------------------- /examples/pylint/w0125_using_constant_test.py: -------------------------------------------------------------------------------- 1 | def square(number: float) -> float: 2 | """Return the square of the number.""" 3 | if True: 4 | return number**2 5 | return number**3 # This line will never be executed 6 | -------------------------------------------------------------------------------- /examples/pylint/w0126_missing_parentheses_for_call_in_test.py: -------------------------------------------------------------------------------- 1 | def condition() -> bool: 2 | return True 3 | 4 | if condition: # Error on this line 5 | pass 6 | -------------------------------------------------------------------------------- /examples/pylint/w0127_self_assigning_variable.py: -------------------------------------------------------------------------------- 1 | x = 1 2 | 3 | x = x 4 | -------------------------------------------------------------------------------- /examples/pylint/w0128_redeclared_assigned_name.py: -------------------------------------------------------------------------------- 1 | x, x = 1, 2 # Error on this line 2 | -------------------------------------------------------------------------------- /examples/pylint/w0130_duplicate_value.py: -------------------------------------------------------------------------------- 1 | incorrect_set = {'value 1', 2, 3, 'value 1'} # Error on this line 2 | print(incorrect_set) # Prints {2, 3, 'value 1'} 3 | -------------------------------------------------------------------------------- /examples/pylint/w0133_pointless_exception_statement.py: -------------------------------------------------------------------------------- 1 | """Pointless Exception Statement Example""" 2 | # The exception below is not raised, assigned, nor returned for use anywhere in this file. 3 | # Note: ValueError is a subclass of Exception (it is a more specific type of exception in Python). 4 | 5 | 6 | def reciprocal(num: float) -> float: 7 | """Return 1 / num.""" 8 | if num == 0: 9 | ValueError('num cannot be 0!') # Error on this line 10 | else: 11 | return 1 / num 12 | -------------------------------------------------------------------------------- /examples/pylint/w0134_return_in_finally.py: -------------------------------------------------------------------------------- 1 | def error_code(error_codes): 2 | 3 | try: 4 | print(error_codes[0]) 5 | except IndexError: 6 | return error_codes[1] 7 | finally: 8 | return error_codes[2] # Error on this line 9 | -------------------------------------------------------------------------------- /examples/pylint/w0143_comparison_with_callable.py: -------------------------------------------------------------------------------- 1 | def getCourseCode(): 2 | return "CSC148" 3 | 4 | if "CSC148" == getCourseCode: # Error on this line 5 | print("Nice") 6 | -------------------------------------------------------------------------------- /examples/pylint/w0183_broad_exception_caught.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | def divide(numerator: float, denominator: float) -> Optional[float]: 4 | """Divide the numerator by the denominator.""" 5 | try: 6 | return numerator / denominator 7 | except Exception: 8 | print("Some exception occurd! But we don't know which one?!") 9 | -------------------------------------------------------------------------------- /examples/pylint/w0199_assert_on_tuple.py: -------------------------------------------------------------------------------- 1 | def check(condition1: bool, condition2: bool) -> None: 2 | assert (condition1, condition2) # Error on this line 3 | -------------------------------------------------------------------------------- /examples/pylint/w0201_attribute_defined_outside_init.py: -------------------------------------------------------------------------------- 1 | class SomeNumbers: 2 | """A class to store some numbers.""" 3 | num: int 4 | 5 | def __init__(self) -> None: 6 | self.num = 1 7 | 8 | def set_other_num(self, other_num: int) -> None: 9 | self.other_num = other_num 10 | -------------------------------------------------------------------------------- /examples/pylint/w0211_bad_staticmethod_argument.py: -------------------------------------------------------------------------------- 1 | class CashRegister: 2 | """A cash register for storing money and making change.""" 3 | 4 | def __init__(self, balance: float) -> None: 5 | self._current_balance = balance 6 | 7 | @staticmethod 8 | # Error on the following line: Static method with 'self' as first argument 9 | def add_small_coins(self, nickels: int = 0, dimes: int = 0, quarters: int = 0): 10 | """Return the dollar value of the small coins.""" 11 | return 0.05 * nickels + 0.10 * dimes + 0.25 * quarters 12 | -------------------------------------------------------------------------------- /examples/pylint/w0212_protected_access.py: -------------------------------------------------------------------------------- 1 | class Animal: 2 | """A carbon-based life form that eats and moves around.""" 3 | _name: str 4 | 5 | def __init__(self, name: str) -> None: 6 | self._name = name 7 | 8 | 9 | dog = Animal('Charly') 10 | print(dog._name) # Error on this line: Access of protected member `dog._name` 11 | -------------------------------------------------------------------------------- /examples/pylint/w0221_arguments_differ.py: -------------------------------------------------------------------------------- 1 | class Animal: 2 | """Abstract class to be implemented by all animals.""" 3 | _name: str 4 | 5 | def __init__(self, name: str) -> None: 6 | self._name = name 7 | 8 | def make_sound(self, mood: str) -> None: 9 | """Print a sound that the animal would make in a given mood.""" 10 | raise NotImplementedError 11 | 12 | 13 | class Dog(Animal): 14 | """A man's best friend.""" 15 | 16 | def make_sound(self, mood: str, state: str) -> None: # Error: Parameter differs 17 | if mood == 'happy': 18 | print("Woof Woof!") 19 | elif state == 'angry': 20 | print("Grrrrrrr!!") 21 | -------------------------------------------------------------------------------- /examples/pylint/w0222_signature_differs.py: -------------------------------------------------------------------------------- 1 | class StandardBankAccount: 2 | """A standard bank account.""" 3 | 4 | def __init__(self, balance: float) -> None: 5 | self._balance = balance 6 | 7 | def withdraw(self, amount: float = 20) -> float: 8 | """Withdraw money from the bank account.""" 9 | if amount <= self._balance: 10 | self._balance -= amount 11 | return amount 12 | else: 13 | return 0 14 | 15 | 16 | class PremiumBankAccount(StandardBankAccount): 17 | """A premium bank account. 18 | 19 | This bank account has more features than the standard bank account, 20 | but it also costs more. 21 | """ 22 | 23 | def withdraw(self, amount: float) -> float: # Error on this line 24 | """Withdraw money from the bank account.""" 25 | if amount <= self._balance - 2: 26 | # Charge a $2 transaction fee 27 | self._balance -= 2 28 | self._balance -= amount 29 | return amount 30 | else: 31 | return 0 32 | -------------------------------------------------------------------------------- /examples/pylint/w0223_abstract_method.py: -------------------------------------------------------------------------------- 1 | class Animal: 2 | """Abstract class to be implemented by all animals.""" 3 | name: str 4 | 5 | def __init__(self, name: str) -> None: 6 | self.name = name 7 | 8 | def make_sound(self) -> str: 9 | raise NotImplementedError 10 | 11 | 12 | class Cat(Animal): # Error: Method 'make_sound' is not overridden 13 | """A worthy companion.""" 14 | pass 15 | -------------------------------------------------------------------------------- /examples/pylint/w0231_super_init_not_called.py: -------------------------------------------------------------------------------- 1 | class Base: 2 | def __init__(self): 3 | print('Base init') 4 | 5 | class Derived(Base): 6 | def __init__(self): 7 | print('Derived init') # Error on this line [no call to Base.__init__()] 8 | -------------------------------------------------------------------------------- /examples/pylint/w0233_non_parent_init_called.py: -------------------------------------------------------------------------------- 1 | class ClassA: 2 | """An unrelated class.""" 3 | 4 | def __init__(self) -> None: 5 | pass 6 | 7 | class Parent: 8 | """A parent class.""" 9 | 10 | def __init__(self) -> None: 11 | pass 12 | 13 | class Child(Parent): 14 | """A child class.""" 15 | 16 | def __init__(self) -> None: 17 | ClassA.__init__(self) # `ClassA` is not a parent of `Child` 18 | -------------------------------------------------------------------------------- /examples/pylint/w0245_super_without_brackets.py: -------------------------------------------------------------------------------- 1 | class Animal: 2 | """A class that represents an animal""" 3 | def __init__(self) -> None: 4 | print('This is an animal') 5 | 6 | 7 | class Cat(Animal): 8 | """A class that represents a cat""" 9 | def __init__(self) -> None: 10 | super.__init__() # Error on this line, no brackets following super call 11 | print('This is a cat') 12 | -------------------------------------------------------------------------------- /examples/pylint/w0301_unnecessary_semicolon.py: -------------------------------------------------------------------------------- 1 | print("Hello World!"); # Error on this line 2 | -------------------------------------------------------------------------------- /examples/pylint/w0311_bad_indentation.py: -------------------------------------------------------------------------------- 1 | def print_greeting(name: str) -> None: 2 | """Print a greeting to the person with the given name.""" 3 | print('Hello {}!'.format(name)) # Bad indentation. Found 6 spaces, expected 4 4 | -------------------------------------------------------------------------------- /examples/pylint/w0401_wildcard_import.py: -------------------------------------------------------------------------------- 1 | from valid_module import * 2 | -------------------------------------------------------------------------------- /examples/pylint/w0404_reimported.py: -------------------------------------------------------------------------------- 1 | import math 2 | import math # Importing a module twice 3 | -------------------------------------------------------------------------------- /examples/pylint/w0406_import_self.py: -------------------------------------------------------------------------------- 1 | import w0406_import_self # Importing a module from within a module with 2 | # the same name 3 | -------------------------------------------------------------------------------- /examples/pylint/w0410_misplaced_future.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | from __future__ import print_function # Error on this line 4 | -------------------------------------------------------------------------------- /examples/pylint/w0416_shadowed_import.py: -------------------------------------------------------------------------------- 1 | import math 2 | import tkinter as math # Error on this line 3 | -------------------------------------------------------------------------------- /examples/pylint/w0511_fixme.py: -------------------------------------------------------------------------------- 1 | def fishy_function() -> None: 2 | # FIXME 3 | # Implement this function 4 | ... 5 | -------------------------------------------------------------------------------- /examples/pylint/w0604_global_at_module_level.py: -------------------------------------------------------------------------------- 1 | my_list = [1, 2, 3] 2 | 3 | global my_list # Error on this line 4 | -------------------------------------------------------------------------------- /examples/pylint/w0611_unused_import.py: -------------------------------------------------------------------------------- 1 | import re # Module imported, but not used 2 | -------------------------------------------------------------------------------- /examples/pylint/w0612_unused_variable.py: -------------------------------------------------------------------------------- 1 | def square(number: float) -> float: 2 | """Return the square of the number.""" 3 | exponent = 2 # Unused variable 'exponent' 4 | return number ** 2 5 | -------------------------------------------------------------------------------- /examples/pylint/w0613_unused_argument.py: -------------------------------------------------------------------------------- 1 | def add(x: float, y: float, z: float) -> float: # Unused argument 'z' 2 | """Return the sum of and .""" 3 | return x + y 4 | -------------------------------------------------------------------------------- /examples/pylint/w0621_redefined_outer_name.py: -------------------------------------------------------------------------------- 1 | file_data = None # 'file_data' defined here in the outer scope 2 | 3 | def read_file(filename) -> str: 4 | """Read the contents of a file.""" 5 | with open(filename) as fh: 6 | file_data = fh.read() # Redefining name 'file_data' that has already been 7 | return file_data # defined in the outer scope. 8 | -------------------------------------------------------------------------------- /examples/pylint/w0622_redefined_builtin.py: -------------------------------------------------------------------------------- 1 | id = 100 # Error on this line: Redefining built-in 'id' 2 | 3 | def sum(a: float, b: float) -> float: # Error on this line: Redefining built-in 'sum' 4 | return a - b # D'oh 5 | -------------------------------------------------------------------------------- /examples/pylint/w0631_undefined_loop_variable.py: -------------------------------------------------------------------------------- 1 | for i in range(0, 2): 2 | print(i) 3 | 4 | print(i) # i is undefined outside the loop 5 | -------------------------------------------------------------------------------- /examples/pylint/w0632_unbalanced_tuple_unpacking.py: -------------------------------------------------------------------------------- 1 | t = (1, 2, 3, 4) 2 | 3 | a, b, c = t # Error on this line 4 | -------------------------------------------------------------------------------- /examples/pylint/w0642_self_cls_assignment.py: -------------------------------------------------------------------------------- 1 | class Assigning: 2 | def __init__(self, value: int, name: str) -> None: 3 | self.value = value 4 | self.name = name 5 | 6 | def new_attr(self, newvalue: int, newname: str) -> None: 7 | # Wrong approach 8 | self = newvalue # Error on this line 9 | # Correct approach 10 | self.name = newname 11 | 12 | @classmethod 13 | def new_cls(cls, newtype: type) -> type: 14 | cls = newtype 15 | return cls 16 | -------------------------------------------------------------------------------- /examples/pylint/w0644_unbalanced_dict_unpacking.py: -------------------------------------------------------------------------------- 1 | """Examples for W0644 unbalanced-dict-unpacking""" 2 | 3 | SCORES = { 4 | "bob": (1, 1, 3, 2), 5 | "joe": (4, 3, 1, 2), 6 | "billy": (2, 2, 2, 2), 7 | } 8 | 9 | a, b = SCORES # Error on this line 10 | 11 | for d, e in SCORES.values(): # Error on this line 12 | print(d) 13 | -------------------------------------------------------------------------------- /examples/pylint/w0702_bare_except.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | def divide(numerator: float, denominator: float) -> Optional[float]: 4 | """Divide the numerator by the denominator.""" 5 | try: 6 | return numerator / denominator 7 | except: 8 | print("Some exception occurd! Could have been a KeyboardInterrupt!") 9 | -------------------------------------------------------------------------------- /examples/pylint/w0705_duplicate_except.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | def divide(numerator: float, denominator: float) -> Optional[float]: 4 | """Divide the numerator by the denominator.""" 5 | try: 6 | return numerator / denominator 7 | except ZeroDivisionError: 8 | print("Can't divide by 0!") 9 | except ZeroDivisionError: 10 | print("This duplicate exception block will never be reached!") 11 | -------------------------------------------------------------------------------- /examples/pylint/w0706_try_except_raise.py: -------------------------------------------------------------------------------- 1 | try: 2 | 1 / 0 3 | except ZeroDivisionError: 4 | raise 5 | -------------------------------------------------------------------------------- /examples/pylint/w0711_binary_op_exception.py: -------------------------------------------------------------------------------- 1 | def divide_and_square(numerator: float, denominator: float) -> float: 2 | """Divide the numerator by the denominator and square the result.""" 3 | try: 4 | return (numerator / denominator) ** 2 5 | except ZeroDivisionError or OverflowError: # Error on this line 6 | return float('nan') 7 | -------------------------------------------------------------------------------- /examples/pylint/w0715_raising_format_tuple.py: -------------------------------------------------------------------------------- 1 | class DivisionException(Exception): 2 | def __init__(self, message: str, numerator: int, denominator : int): 3 | self.message = message 4 | self.numerator = numerator 5 | self.wasZeroDivide = (denominator == 0) 6 | super().__init__() 7 | 8 | 9 | def divide(numerator: int, denominator: int) -> float: 10 | """Divide the numerator by the denominator.""" 11 | if denominator == 0: 12 | raise DivisionException("You can't do {n} / % {d}", numerator, denominator) 13 | else: 14 | return numerator / denominator 15 | -------------------------------------------------------------------------------- /examples/pylint/w0716_wrong_exception_operation.py: -------------------------------------------------------------------------------- 1 | try: 2 | 1 / 0 3 | except ZeroDivisionError + Exception: # Error on this line 4 | pass 5 | -------------------------------------------------------------------------------- /examples/pylint/w0718_broad_exception_caught.py: -------------------------------------------------------------------------------- 1 | """Broad Exception Caught Example""" 2 | # The caught exception below is too broad and vague. 3 | try: 4 | 1 / 0 5 | except Exception: # Error on this line 6 | print('An error occurred') 7 | -------------------------------------------------------------------------------- /examples/pylint/w0719_broad_exception_raised.py: -------------------------------------------------------------------------------- 1 | """Broad Exception Raised Example""" 2 | # The raised exception below is too broad and vague. 3 | raise Exception("This is a broad exception.") # Error on this line 4 | -------------------------------------------------------------------------------- /examples/pylint/w1114_arguments_out_of_order.py: -------------------------------------------------------------------------------- 1 | def f(x: int, y: int, z: int) -> int: 2 | return x + y + z 3 | 4 | 5 | def g(n: int) -> int: 6 | x = n 7 | y = n * 2 8 | z = n * 3 9 | 10 | return f(y, z, x) # Error on this line 11 | -------------------------------------------------------------------------------- /examples/pylint/w1117_kwarg_superseded_by_positional_arg.py: -------------------------------------------------------------------------------- 1 | """Examples for W1117: kwarg-superseded-by-positional-arg""" 2 | 3 | 4 | def print_greeting(greeting="Hello", /, **kwds) -> None: 5 | """Prints out the greeting provided as a positional argument, 6 | or "Hello" otherwise. 7 | """ 8 | print(greeting) 9 | 10 | 11 | print_greeting(greeting="Hi") # Error on this line 12 | -------------------------------------------------------------------------------- /examples/pylint/w1303_missing_format_argument_key.py: -------------------------------------------------------------------------------- 1 | # Error on the following line: missing format argument for 'age' 2 | s = '{last_name}, {fist_name} - {age}'.format(last_name='bond', first_name='james') 3 | -------------------------------------------------------------------------------- /examples/pylint/w1304_unused_format_string_argument.py: -------------------------------------------------------------------------------- 1 | print('{one} {two}'.format(one='hello', two='world', three='again')) # Error on this line 2 | -------------------------------------------------------------------------------- /examples/pylint/w1305_format_combined_specification.py: -------------------------------------------------------------------------------- 1 | s = '{} and {0}'.format('a', 'b') # Error on this line 2 | -------------------------------------------------------------------------------- /examples/pylint/w1308_duplicate_string_formatting_argument.py: -------------------------------------------------------------------------------- 1 | t = 'hello' 2 | 3 | print('{} {}'.format(t, t)) # Error on this line 4 | -------------------------------------------------------------------------------- /examples/pylint/w1309_f_string_without_interpolation.py: -------------------------------------------------------------------------------- 1 | print(f'Hello World!') # Error on this line 2 | -------------------------------------------------------------------------------- /examples/pylint/w1310_format_string_without_interpolation.py: -------------------------------------------------------------------------------- 1 | greeting = 'Hello There, '.format(name='person') # Error on this line 2 | -------------------------------------------------------------------------------- /examples/pylint/w1401_anomalous_backslash_in_string.py: -------------------------------------------------------------------------------- 1 | print('This is a bad escape: \d') # Error in this line 2 | -------------------------------------------------------------------------------- /examples/pylint/w1402_anomalous_unicode_escape_in_string.py: -------------------------------------------------------------------------------- 1 | print(b'\u{0}'.format('0394')) # Error on this line 2 | -------------------------------------------------------------------------------- /examples/pylint/w1404_implicit_str_concat.py: -------------------------------------------------------------------------------- 1 | ["he" "llo"] # Error on this line 2 | -------------------------------------------------------------------------------- /examples/pylint/w1501_bad_open_mode.py: -------------------------------------------------------------------------------- 1 | with open('my_file.txt', 'z'): # Error on this line 2 | pass 3 | -------------------------------------------------------------------------------- /examples/pylint/w1503_redundant_unittest_assert.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | import unittest 3 | 4 | def is_sorted(lst: list[float]) -> bool: 5 | """Check if is sorted in ascending order.""" 6 | return lst == sorted(lst) 7 | 8 | 9 | class TestStringMethods(unittest.TestCase): 10 | """Simple tests for example purposes.""" 11 | 12 | def test_isupper(self) -> None: 13 | """Simple tests for example purposes.""" 14 | # Valid: 15 | self.assertTrue(is_sorted([1, 2, 3])) 16 | self.assertFalse(is_sorted([1, 3, 2])) 17 | 18 | # If a constant is passed as parameter, that condition is always true: 19 | self.assertTrue('YES') 20 | self.assertTrue(1) 21 | self.assertTrue(True) 22 | self.assertTrue(False) 23 | -------------------------------------------------------------------------------- /examples/pylint/w1515_forgotten_debug_statement.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import pdb 3 | breakpoint() # Error on this line 4 | sys.breakpointhook() # Error on this line 5 | pdb.set_trace() # Error on this line 6 | -------------------------------------------------------------------------------- /examples/pylint/w2301_unnecessary_ellipsis.py: -------------------------------------------------------------------------------- 1 | def my_func() -> None: 2 | """Test Doctest""" 3 | ... # Error on this line 4 | if True: 5 | ... # Error on this line 6 | return None 7 | -------------------------------------------------------------------------------- /examples/pylint/w3301_nested_min_max.py: -------------------------------------------------------------------------------- 1 | """Examples for W3301 nested-min-max""" 2 | 3 | smallest = min(12, min(1, 2)) 4 | 5 | largest = max(12, max(1, 2)) 6 | -------------------------------------------------------------------------------- /examples/pylint/w3601_bad_chained_comparison.py: -------------------------------------------------------------------------------- 1 | """Examples for W3601 bad-chained-comparison""" 2 | 3 | x = 5 4 | 5 | if 0 < x is 5: # Error on this line 6 | print("hi") 7 | 8 | a = 1 9 | my_list = [1, 2, 3, 4] 10 | 11 | if a > 0 not in my_list: # Error on this line 12 | print("whee") 13 | 14 | if a == x is 1 in my_list: # Error on this line 15 | print("yikes") 16 | -------------------------------------------------------------------------------- /examples/pylint/w4701_modified_iterating_list.py: -------------------------------------------------------------------------------- 1 | data = [1, 2, 3, 4] 2 | 3 | for x in data: 4 | data.remove(4) # Error on this line 5 | -------------------------------------------------------------------------------- /examples/sample_usage/TODO.md: -------------------------------------------------------------------------------- 1 | ## print_nodes.py 2 | 3 | ### print_nodes function 4 | 5 | # To fix: 6 | 7 | AnnAssign Node: 8 | An AttributeError is raised because the transformer did not add 9 | 'end_lineno' attribute to the AnnAssign node. In the current example 10 | found in `examples/nodes/ann_assign.py`, only the last statement has the 11 | 'end_lineno' attribute added to it. 12 | 13 | DictUnpack Node: 14 | An AttributeError is raised because the transformer did not augment this 15 | node with the ending columns/line attribute. I tried adding this node to 16 | the NODES_WITHOUT_CHILDREN variable in `setendings.py` but it only added 17 | the incorrect column offset. 18 | -------------------------------------------------------------------------------- /examples/sample_usage/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyta-uoft/pyta/0539d23be047c12316158304e4837b80e1384d75/examples/sample_usage/__init__.py -------------------------------------------------------------------------------- /examples/sample_usage/draw_cfg.py: -------------------------------------------------------------------------------- 1 | import python_ta.cfg.cfg_generator as cfg_generator 2 | from sys import executable 3 | from os import path 4 | 5 | USAGE = f"USAGE: {path.basename(executable)} -m examples.sample_usage.draw_cfg " 6 | 7 | 8 | def main(filepath: str) -> None: 9 | cfg_generator.generate_cfg(mod=filepath, auto_open=True) 10 | 11 | 12 | if __name__ == "__main__": 13 | import sys 14 | 15 | if len(sys.argv) < 2: 16 | print(USAGE) 17 | exit(1) 18 | 19 | filepath = sys.argv[1] 20 | main(filepath) 21 | -------------------------------------------------------------------------------- /examples/syntax_errors/assignment_inside_condition.py: -------------------------------------------------------------------------------- 1 | if spam = 42: # Error on this line: assignment (`=`) instead of equality (`==`) 2 | print('Hello!') 3 | -------------------------------------------------------------------------------- /examples/syntax_errors/assignment_to_keyword.py: -------------------------------------------------------------------------------- 1 | class = 'algebra' # Error on this line: assignment to keyword 'class' 2 | -------------------------------------------------------------------------------- /examples/syntax_errors/assignment_to_literal.py: -------------------------------------------------------------------------------- 1 | a = 12 2 | 12 = a # Error on this line: can't assign to literal 3 | 'hello' = a # Error on this line: can't assign to literal 4 | -------------------------------------------------------------------------------- /examples/syntax_errors/missing_colon.py: -------------------------------------------------------------------------------- 1 | if spam == 42 # Error on this line: missing colon 2 | print('Hello!') 3 | -------------------------------------------------------------------------------- /examples/syntax_errors/missing_parentheses_in_call_to_print.py: -------------------------------------------------------------------------------- 1 | print "Hello world!" # Error on this line 2 | print("Hello world!") # Correct version 3 | -------------------------------------------------------------------------------- /examples/syntax_errors/missing_quote.py: -------------------------------------------------------------------------------- 1 | print('Hello!) # Error on this line: missing closing quote (') 2 | -------------------------------------------------------------------------------- /examples/syntax_errors/undefined_operator.py: -------------------------------------------------------------------------------- 1 | spam = 0 2 | spam++ # Error on this line 3 | spam-- # Error on this line 4 | -------------------------------------------------------------------------------- /examples/syntax_errors/unexpected_indent.py: -------------------------------------------------------------------------------- 1 | for i, animal in enumerate(['Monkey', 'Donkey', 'Platypus']): 2 | print(i) 3 | print(animal) # IndentationError: unexpected indent 4 | -------------------------------------------------------------------------------- /examples/syntax_errors/unindent_does_not_match_indentation.py: -------------------------------------------------------------------------------- 1 | num_even = 0 2 | num_odd = 0 3 | for i in range(100): 4 | if i % 2 == 0: 5 | num_even += 1 6 | else: # Error on this line: six spaces before `else:` instead of four 7 | num_odd += 1 8 | -------------------------------------------------------------------------------- /python_ta/cfg/__init__.py: -------------------------------------------------------------------------------- 1 | try: 2 | from .cfg_generator import generate_cfg 3 | except ModuleNotFoundError: 4 | 5 | def generate_cfg(*_args, **_kwargs) -> None: 6 | """Dummy version of generate_cfg""" 7 | raise Exception( 8 | "This function requires additional dependencies to be installed: " "python_ta[cfg]" 9 | ) 10 | 11 | 12 | from .graph import * 13 | from .visitor import * 14 | -------------------------------------------------------------------------------- /python_ta/check/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyta-uoft/pyta/0539d23be047c12316158304e4837b80e1384d75/python_ta/check/__init__.py -------------------------------------------------------------------------------- /python_ta/checkers/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyta-uoft/pyta/0539d23be047c12316158304e4837b80e1384d75/python_ta/checkers/__init__.py -------------------------------------------------------------------------------- /python_ta/debug/__init__.py: -------------------------------------------------------------------------------- 1 | from .accumulation_table import AccumulationTable 2 | from .recursion_table import RecursionTable 3 | from .snapshot_tracer import SnapshotTracer 4 | -------------------------------------------------------------------------------- /python_ta/debug/webstepper/99ee5c67fd0c522b4b6a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyta-uoft/pyta/0539d23be047c12316158304e4837b80e1384d75/python_ta/debug/webstepper/99ee5c67fd0c522b4b6a.png -------------------------------------------------------------------------------- /python_ta/debug/webstepper/fd6133fe40f4f90440d6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyta-uoft/pyta/0539d23be047c12316158304e4837b80e1384d75/python_ta/debug/webstepper/fd6133fe40f4f90440d6.png -------------------------------------------------------------------------------- /python_ta/debug/webstepper/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | MemoryViz Webstepper 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | -------------------------------------------------------------------------------- /python_ta/patches/__init__.py: -------------------------------------------------------------------------------- 1 | """Monkeypatch pylint behaviour.""" 2 | 3 | from .checkers import patch_checkers 4 | from .messages import patch_messages 5 | from .transforms import patch_ast_transforms 6 | 7 | 8 | def patch_all(z3: bool): 9 | """Execute all patches defined in this module.""" 10 | patch_checkers() 11 | patch_ast_transforms(z3) 12 | patch_messages() 13 | -------------------------------------------------------------------------------- /python_ta/patches/messages.py: -------------------------------------------------------------------------------- 1 | """Patch pylint message-handling behaviour.""" 2 | 3 | from pylint.interfaces import UNDEFINED 4 | from pylint.lint import PyLinter 5 | 6 | 7 | def patch_messages(): 8 | """Patch PyLinter to pass the node to reporter.""" 9 | old_add_message = PyLinter.add_message 10 | 11 | def new_add_message( 12 | self, 13 | msg_id, 14 | line=None, 15 | node=None, 16 | args=None, 17 | confidence=UNDEFINED, 18 | col_offset=None, 19 | end_lineno=None, 20 | end_col_offset=None, 21 | ): 22 | old_add_message( 23 | self, msg_id, line, node, args, confidence, col_offset, end_lineno, end_col_offset 24 | ) 25 | msg_info = self.msgs_store.get_message_definitions(msg_id)[0] 26 | # guard to allow for backward compatability with Pylint's reporters 27 | if hasattr(self.reporter, "handle_node"): 28 | self.reporter.handle_node(msg_info, node) 29 | 30 | PyLinter.add_message = new_add_message 31 | -------------------------------------------------------------------------------- /python_ta/patches/transforms.py: -------------------------------------------------------------------------------- 1 | """Patch to add transforms for setting type constraints and creating control flow graphs.""" 2 | 3 | import logging 4 | 5 | from pylint.lint import PyLinter 6 | 7 | from ..cfg.visitor import CFGVisitor 8 | 9 | 10 | def patch_ast_transforms(z3: bool): 11 | old_get_ast = PyLinter.get_ast 12 | 13 | def new_get_ast(self, filepath, modname, data): 14 | ast = old_get_ast(self, filepath, modname, data) 15 | if ast is None: 16 | return None 17 | 18 | # Run the Z3Visitor 19 | if z3: 20 | try: 21 | from ..transforms.z3_visitor import Z3Visitor 22 | 23 | ast = Z3Visitor().visitor.visit(ast) 24 | except Exception as e: 25 | logging.warning(f"Could not run Z3Visitor: {e}") 26 | 27 | # Run the CFGVisitor 28 | try: 29 | if z3: 30 | ast.accept(CFGVisitor(options={"separate-condition-blocks": True})) 31 | else: 32 | ast.accept(CFGVisitor()) 33 | except Exception as e: 34 | logging.warning(f"Could not run CFGVisitor: {e}") 35 | 36 | return ast 37 | 38 | PyLinter.get_ast = new_get_ast 39 | -------------------------------------------------------------------------------- /python_ta/reporters/__init__.py: -------------------------------------------------------------------------------- 1 | from .color_reporter import ColorReporter 2 | from .html_reporter import HTMLReporter 3 | from .json_reporter import JSONReporter 4 | from .plain_reporter import PlainReporter 5 | 6 | # Export tuple of reporter classes for python_ta init file. 7 | REPORTERS = (ColorReporter, PlainReporter, HTMLReporter, JSONReporter) 8 | -------------------------------------------------------------------------------- /python_ta/reporters/stat_reporter.py: -------------------------------------------------------------------------------- 1 | from .plain_reporter import PlainReporter 2 | 3 | 4 | class StatReporter(PlainReporter): 5 | error_messages = [] 6 | style_messages = [] 7 | 8 | def __init__(self, source_lines=None): 9 | """Initialize a StatReporter. 10 | 11 | Clear the two class-level message lists. 12 | 13 | @type source_lines: list[str] 14 | @rtype: None 15 | """ 16 | super().__init__(source_lines) 17 | StatReporter.error_messages = [] 18 | StatReporter.style_messages = [] 19 | 20 | def print_messages(self, level="all"): 21 | """Override the corresponding function in PlainReporter. 22 | 23 | @type level: str 24 | @rtype: None 25 | """ 26 | StatReporter.error_messages.extend(self._error_messages) 27 | StatReporter.style_messages.extend(self._style_messages) 28 | 29 | # to appease PyCharm's NotImplemented complaint 30 | _display = None 31 | -------------------------------------------------------------------------------- /python_ta/reporters/templates/pyta_logo_markdown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyta-uoft/pyta/0539d23be047c12316158304e4837b80e1384d75/python_ta/reporters/templates/pyta_logo_markdown.png -------------------------------------------------------------------------------- /python_ta/transforms/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyta-uoft/pyta/0539d23be047c12316158304e4837b80e1384d75/python_ta/transforms/__init__.py -------------------------------------------------------------------------------- /python_ta/util/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyta-uoft/pyta/0539d23be047c12316158304e4837b80e1384d75/python_ta/util/__init__.py -------------------------------------------------------------------------------- /python_ta/util/autoformat.py: -------------------------------------------------------------------------------- 1 | """ 2 | This file contains a function for running the Black formatting tool. 3 | """ 4 | 5 | import subprocess 6 | import sys 7 | 8 | 9 | def run_autoformat(file_path: str, autoformat_options: list[str], max_linelen: int) -> None: 10 | """Run the Black formatting tool on the Python file with the given autoformat options and maximum line length.""" 11 | subprocess_args = [sys.executable, "-m", "black"] 12 | if max_linelen: 13 | subprocess_args.append(f"--line-length={max_linelen}") 14 | for arg in autoformat_options: 15 | subprocess_args.append("--" + arg) 16 | 17 | subprocess.run( 18 | subprocess_args + [file_path], 19 | encoding="utf-8", 20 | capture_output=True, 21 | text=True, 22 | check=True, 23 | ) 24 | -------------------------------------------------------------------------------- /python_ta/util/tree.py: -------------------------------------------------------------------------------- 1 | """ 2 | Simple Tree class to be used for RecursionTable. 3 | """ 4 | 5 | from __future__ import annotations 6 | 7 | from typing import Any 8 | 9 | 10 | class Tree: 11 | """ 12 | This class is used by RecursionTable to represent a 13 | recursive call. 14 | 15 | Instance attributes: 16 | value: the value of the tree node 17 | children: the child nodes of the tree 18 | """ 19 | 20 | value: Any 21 | children: list[Tree] 22 | 23 | def __init__(self, value: Any) -> None: 24 | """Initialize a Tree with no children by default.""" 25 | self.value = value 26 | self.children = [] 27 | 28 | def add_child(self, child_node: Tree) -> None: 29 | """Add child_node as one of the tree's children.""" 30 | self.children.append(child_node) 31 | 32 | def __eq__(self, tree: Tree) -> bool: 33 | """Check if self and tree are equal by comparing their values and 34 | structure. 35 | """ 36 | if self.value != tree.value or len(self.children) != len(tree.children): 37 | return False 38 | for i in range(len(self.children)): 39 | if not self.children[i].__eq__(tree.children[i]): 40 | return False 41 | return True 42 | -------------------------------------------------------------------------------- /python_ta/utils.py: -------------------------------------------------------------------------------- 1 | from typing import ForwardRef, _GenericAlias 2 | 3 | from astroid import nodes 4 | 5 | 6 | def _get_name(t: type) -> str: 7 | """If t is associated with a class, return the name of the class; otherwise, return a string repr. of t""" 8 | if isinstance(t, ForwardRef): 9 | return t.__forward_arg__ 10 | elif isinstance(t, type): 11 | return t.__name__ 12 | elif isinstance(t, _GenericAlias): 13 | return "{} of {}".format( 14 | _get_name(t.__origin__), ", ".join(_get_name(arg) for arg in t.__args__) 15 | ) 16 | else: 17 | return str(t) 18 | 19 | 20 | def _is_in_main(node): 21 | if not hasattr(node, "parent"): 22 | return False 23 | 24 | parent = node.parent 25 | try: 26 | if ( 27 | isinstance(parent, nodes.If) 28 | and parent.test.left.name == "__name__" 29 | and parent.test.ops[0][1].value == "__main__" 30 | ): 31 | return True 32 | else: 33 | return _is_in_main(parent) 34 | except (AttributeError, IndexError) as e: 35 | return _is_in_main(parent) 36 | -------------------------------------------------------------------------------- /python_ta/z3/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyta-uoft/pyta/0539d23be047c12316158304e4837b80e1384d75/python_ta/z3/__init__.py -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | setup() 4 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyta-uoft/pyta/0539d23be047c12316158304e4837b80e1384d75/tests/__init__.py -------------------------------------------------------------------------------- /tests/fixtures/contracts/modules_not_in_arg.py: -------------------------------------------------------------------------------- 1 | """In reference to issue 799, test that check_all_contracts skips checks for modules not specified as an argument.""" 2 | 3 | blah = int 4 | 5 | 6 | def divide(x: blah, y: blah) -> int: 7 | """Return x // y.""" 8 | return x // y 9 | 10 | 11 | # Actual test run in test_contracts.py 12 | def run(): 13 | from python_ta.contracts import check_all_contracts 14 | 15 | check_all_contracts(__name__, decorate_main=False) 16 | 17 | divide(10, "x") 18 | -------------------------------------------------------------------------------- /tests/fixtures/no_errors.py: -------------------------------------------------------------------------------- 1 | """A module with no PythonTA errors.""" 2 | 3 | 4 | class MyClass: 5 | """This is a class.""" 6 | 7 | name: str 8 | value: int 9 | 10 | def __init__(self) -> None: 11 | self.name = "A" 12 | self.value = 10 13 | -------------------------------------------------------------------------------- /tests/fixtures/precondition_inline_comment.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | 4 | def move(direction: tuple[int, int]) -> bool: 5 | """ 6 | Preconditions: 7 | - direction in [(0, -1), (0, 1), (-1, 0), (1, 0)] # This limits movement to one tile 8 | """ 9 | return True 10 | -------------------------------------------------------------------------------- /tests/fixtures/pylint_comment.py: -------------------------------------------------------------------------------- 1 | # pylint: disable=unbalanced-tuple-unpacking 2 | -------------------------------------------------------------------------------- /tests/fixtures/reporters/no_watch_integration.py: -------------------------------------------------------------------------------- 1 | """This script serves as the entry point for an integration test of the PyTA HTML report server. 2 | It is invoked by the test `tests/test_reporters/test_html_server::test_open_html_in_browser_no_watch()` 3 | to verify that the HTML report server can handle multiple requests when `watch=True`.""" 4 | 5 | from unittest.mock import patch 6 | 7 | from python_ta import check_all 8 | 9 | 10 | @patch("webbrowser.open", return_value=None) 11 | def open_server(mock_webbrowser_open): 12 | check_all( 13 | config={ 14 | "watch": False, 15 | "server_port": 5008, 16 | } 17 | ) 18 | 19 | 20 | open_server() 21 | -------------------------------------------------------------------------------- /tests/fixtures/reporters/watch_integration.py: -------------------------------------------------------------------------------- 1 | """This script serves as the entry point for an integration test of the PyTA HTML report server. 2 | It is invoked by the test `tests/test_reporters/test_html_server::test_open_html_in_browser_watch()` 3 | to verify that the HTML report server can handle multiple requests when `watch=True`.""" 4 | 5 | from unittest.mock import patch 6 | 7 | from python_ta import check_all 8 | 9 | 10 | @patch("webbrowser.open", return_value=None) 11 | def open_server(mock_webbrowser_open): 12 | check_all( 13 | config={ 14 | "watch": True, 15 | "server_port": 5008, 16 | } 17 | ) 18 | 19 | 20 | open_server() 21 | -------------------------------------------------------------------------------- /tests/fixtures/sample_dir/assignment_inside_condition.py: -------------------------------------------------------------------------------- 1 | if spam = 42: # Error on this line: assignment (`=`) instead of equality (`==`) 2 | print('Hello!') 3 | -------------------------------------------------------------------------------- /tests/fixtures/sample_dir/c0114_missing_module_docstring.py: -------------------------------------------------------------------------------- 1 | # Error on this line (no docstring) 2 | ... 3 | -------------------------------------------------------------------------------- /tests/fixtures/sample_dir/custom_checkers/e9989_pycodestyle/e123_error.py: -------------------------------------------------------------------------------- 1 | x = [ 2 | 1 3 | ] 4 | -------------------------------------------------------------------------------- /tests/fixtures/sample_dir/custom_checkers/e9992_forbidden_top_level_code.py: -------------------------------------------------------------------------------- 1 | def example_function(name: str) -> str: 2 | return f"Hello {name}!" 3 | 4 | 5 | print(example_function("Fred")) # error on this line 6 | -------------------------------------------------------------------------------- /tests/fixtures/sample_dir/pylint/c0121_singleton_comparison.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | 4 | def square(number: Optional[float]) -> Optional[float]: 5 | """Return the square of the number.""" 6 | if number == None: # Error on this line 7 | return None 8 | else: 9 | return number**2 10 | -------------------------------------------------------------------------------- /tests/fixtures/sample_dir/watch/watch_enabled_configuration.py: -------------------------------------------------------------------------------- 1 | """This script serves as the entry point for an integration test of the _check watch mode.""" 2 | 3 | import python_ta 4 | 5 | def blank_function() -> int: 6 | count: int = "ten" 7 | return count 8 | 9 | if __name__ == "__main__": 10 | python_ta.check_all(config={ 11 | "output-format": "python_ta.reporters.PlainReporter", 12 | "watch": True 13 | }) 14 | -------------------------------------------------------------------------------- /tests/fixtures/unicode_decode_error.py: -------------------------------------------------------------------------------- 1 | "�" 2 | "�" 3 | "foo" 4 | "foo" 5 | "�" 6 | -------------------------------------------------------------------------------- /tests/fixtures/unused_imports.py: -------------------------------------------------------------------------------- 1 | """A module with three unused import errors.""" 2 | 3 | import os 4 | import sys 5 | import math 6 | -------------------------------------------------------------------------------- /tests/test_cfg/file_fixtures/funcs_only.py: -------------------------------------------------------------------------------- 1 | """Python script to use for testing that cfgs are only produced for functions when specified.""" 2 | 3 | a = 5 4 | 5 | 6 | class MyClass: 7 | def foo(self) -> None: 8 | print("method") 9 | 10 | 11 | def foo() -> None: 12 | a = 5 13 | 14 | 15 | def boo() -> None: 16 | print("boo") 17 | 18 | 19 | def hoo() -> None: 20 | if a > 0: 21 | owl = "hoo" 22 | -------------------------------------------------------------------------------- /tests/test_cfg/file_fixtures/my_file.py: -------------------------------------------------------------------------------- 1 | """Python script to use for testing whether cfgs were generated correctly""" 2 | 3 | 4 | def foo() -> None: 5 | for i in range(1, 10): 6 | if i < 5: 7 | print("hi") 8 | 9 | 10 | def func_with_while() -> None: 11 | """A function with a while loop""" 12 | a = 1 13 | while a < 100: 14 | print(a) 15 | a += 1 16 | 17 | 18 | def func_with_unreachable() -> int: 19 | """A function with unreachable code""" 20 | a = 1 21 | return a * 10 22 | a = 2 23 | -------------------------------------------------------------------------------- /tests/test_cfg/snapshots/funcs_only.gv: -------------------------------------------------------------------------------- 1 | digraph "funcs_only.gv" { 2 | node [fontname="Courier New" shape=box] 3 | subgraph cluster_0 { 4 | cluster_0_0 [label="self\l" fillcolor=palegreen style=filled] 5 | cluster_0_0 -> cluster_0_2 [color=black] 6 | cluster_0_2 [label="print('method')\l" fillcolor=white style=filled] 7 | cluster_0_2 -> cluster_0_1 [color=black] 8 | cluster_0_1 [label="\l" fillcolor=black style=filled] 9 | fontname="Courier New" label="MyClass.foo" 10 | } 11 | subgraph cluster_1 { 12 | cluster_1_0 [label="\l" fillcolor=palegreen style=filled] 13 | cluster_1_0 -> cluster_1_2 [color=black] 14 | cluster_1_2 [label="a = 5\l" fillcolor=white style=filled] 15 | cluster_1_2 -> cluster_1_1 [color=black] 16 | cluster_1_1 [label="\l" fillcolor=black style=filled] 17 | fontname="Courier New" label=foo 18 | } 19 | subgraph cluster_2 { 20 | cluster_2_0 [label="\l" fillcolor=palegreen style=filled] 21 | cluster_2_0 -> cluster_2_2 [color=black] 22 | cluster_2_2 [label=< ifa > 0
> fillcolor=white style=filled] 23 | cluster_2_2 -> cluster_2_3 [label=True color=black] 24 | cluster_2_3 [label="owl = 'hoo'\l" fillcolor=white style=filled] 25 | cluster_2_3 -> cluster_2_1 [color=black] 26 | cluster_2_1 [label="\l" fillcolor=black style=filled] 27 | cluster_2_2 -> cluster_2_1 [label=False color=black] 28 | fontname="Courier New" label=hoo 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tests/test_config/file_fixtures/funcs_with_errors.py: -------------------------------------------------------------------------------- 1 | """Python script used for testing that the correct number of error occurrences are being displayed.""" 2 | 3 | from __future__ import annotations 4 | 5 | # The following imports are used solely to trigger errors. 6 | import packaging 7 | import pip 8 | import pygments 9 | import pylint 10 | 11 | 12 | def sum_items(lst: list[int]) -> int: 13 | """...""" 14 | s = 0 15 | for i in range(len(lst)): 16 | s += lst[i] 17 | return s 18 | 19 | 20 | def sum_items2(lst: list[int]) -> int: 21 | """...""" 22 | s = 0 23 | for i in range(0, len(lst)): 24 | s += lst[i] 25 | return s 26 | 27 | 28 | def sum_items3(lst: list[int]) -> int: 29 | """...""" 30 | s = 0 31 | for i in range(0, len(lst), 1): 32 | s += lst[i] 33 | return s 34 | -------------------------------------------------------------------------------- /tests/test_config/file_fixtures/test.pylintrc: -------------------------------------------------------------------------------- 1 | [CUSTOM PYTA OPTIONS] 2 | 3 | # Default max amount of messages for reporter to display. 4 | pyta-number-of-messages = 10 5 | 6 | # Set whether the default error messages by pylint should be overwritten by python TA's custom messages 7 | overwrite-error-messages = yes 8 | 9 | [ELIF] 10 | 11 | # Set maximum allowed if nesting. 12 | max-nested-blocks = 5 13 | 14 | [FORMAT] 15 | 16 | # Set the maximum line length. 17 | max-line-length = 120 18 | -------------------------------------------------------------------------------- /tests/test_config/file_fixtures/test_f0011.pylintrc: -------------------------------------------------------------------------------- 1 | [REPORTS] 2 | 3 | output-format = pyta-html 4 | 5 | [FORMAT] 6 | 7 | max-line-length = 100 8 | 9 | ignore-long-lines = ^\s*((# )??)|(>>>.*)$ 10 | 11 | [FORBIDDEN IMPORT] 12 | extra-imports = math, tkinter 13 | 14 | # To trigger F0011 15 | bad 16 | -------------------------------------------------------------------------------- /tests/test_config/file_fixtures/test_json_with_errors.pylintrc: -------------------------------------------------------------------------------- 1 | [REPORTS] 2 | 3 | output-format = pyta-json 4 | 5 | [FORMAT] 6 | 7 | max-line-length = 100 8 | 9 | ignore-long-lines = ^\s*((# )??)|(>>>.*)$ 10 | 11 | [FORBIDDEN IMPORT] 12 | extra-imports = math, tkinter 13 | 14 | [MESSAGES CONTROL] 15 | disable = 16 | ooga 17 | -------------------------------------------------------------------------------- /tests/test_config/file_fixtures/test_plain_with_errors.pylintrc: -------------------------------------------------------------------------------- 1 | [REPORTS] 2 | 3 | output-format = pyta-plain 4 | 5 | [FORMAT] 6 | 7 | max-line-length = 100 8 | 9 | ignore-long-lines = ^\s*((# )??)|(>>>.*)$ 10 | 11 | [FORBIDDEN IMPORT] 12 | extra-imports = math, tkinter 13 | 14 | [MESSAGES CONTROL] 15 | disable = 16 | ooga 17 | -------------------------------------------------------------------------------- /tests/test_config/file_fixtures/test_with_errors.pylintrc: -------------------------------------------------------------------------------- 1 | [REPORTS] 2 | 3 | output-format = pyta-html 4 | 5 | [FORMAT] 6 | 7 | max-line-length = 100 8 | 9 | ignore-long-lines = ^\s*((# )??)|(>>>.*)$ 10 | 11 | [FORBIDDEN IMPORT] 12 | extra-imports = math, tkinter 13 | 14 | [MESSAGES CONTROL] 15 | # To trigger W0012, R0022 16 | disable = 17 | ooga, bad-continuation 18 | 19 | # To trigger E0015 20 | no-space-check = 21 | -------------------------------------------------------------------------------- /tests/test_config/test_file.py: -------------------------------------------------------------------------------- 1 | def some_function(): 2 | x = 5 # pylint: disable something 3 | y = 0 4 | result = x / y 5 | return result 6 | 7 | 8 | a = 10 9 | b = 20 10 | -------------------------------------------------------------------------------- /tests/test_contracts/test_contracts_attr_value_restoration.py: -------------------------------------------------------------------------------- 1 | from python_ta.contracts import check_contracts 2 | 3 | 4 | def test_class_attr_value_restores_to_original_if_violates_rep_inv() -> None: 5 | """Test to check whether the class attribute value is restored to the original value if a representation invariant 6 | is violated.""" 7 | 8 | @check_contracts 9 | class Person: 10 | """ 11 | Representation Invariants: 12 | - self.age >= 0 13 | """ 14 | 15 | age: int = 0 16 | 17 | my_person = Person() 18 | 19 | try: 20 | my_person.age = -1 21 | except AssertionError: 22 | assert my_person.age == 0 23 | 24 | 25 | def test_class_attr_value_does_not_exist_if_violates_rep_inv() -> None: 26 | """Test to check whether the class attribute value does not exist if a representation invariant 27 | is violated.""" 28 | 29 | @check_contracts 30 | class Person: 31 | """ 32 | Representation Invariants: 33 | - self.age >= 0 34 | """ 35 | 36 | age: int 37 | 38 | my_person = Person() 39 | 40 | try: 41 | my_person.age = -1 42 | except AssertionError: 43 | assert not hasattr(my_person, "age") 44 | -------------------------------------------------------------------------------- /tests/test_contracts/test_contracts_debug.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from python_ta import contracts 4 | 5 | contracts.DEBUG_CONTRACTS = True 6 | from python_ta.contracts import check_contracts 7 | 8 | 9 | def test_contracts_debug(caplog) -> None: 10 | """Test to see if _debug function is logging messages correctly""" 11 | caplog.set_level(logging.DEBUG) 12 | 13 | @check_contracts 14 | def divide(x: int, y: int) -> int: 15 | """Return x // y. 16 | 17 | Preconditions: 18 | - invalid precondition 19 | """ 20 | return x // y 21 | 22 | divide(6, 2) 23 | 24 | for record in caplog.records: 25 | assert record.levelname == "DEBUG" 26 | assert ( 27 | "Warning: precondition invalid precondition could not be parsed as a valid Python expression" 28 | in caplog.text 29 | ) 30 | -------------------------------------------------------------------------------- /tests/test_contracts/test_contracts_type_alias_abstract_network.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import Dict, Union 4 | 5 | # This creates a type alias, to save us typing "Union[int, tuple]" everywhere 6 | NodeAddress = Union[int, tuple] 7 | 8 | 9 | ############################################################################### 10 | # The Node class 11 | ############################################################################### 12 | class Node: 13 | address: NodeAddress 14 | 15 | def __init__(self, address: NodeAddress) -> None: 16 | self.address = address 17 | 18 | 19 | ############################################################################### 20 | # The AbstractNetwork class 21 | ############################################################################### 22 | class AbstractNetwork: 23 | _nodes: Dict[NodeAddress, Node] 24 | 25 | def __init__(self) -> None: 26 | self._nodes = {} 27 | -------------------------------------------------------------------------------- /tests/test_contracts/test_contracts_type_alias_abstract_ring.py: -------------------------------------------------------------------------------- 1 | from python_ta.contracts import check_contracts 2 | from tests.test_contracts.test_contracts_type_alias_abstract_network import ( 3 | AbstractNetwork, 4 | ) 5 | 6 | 7 | def test_type_alias_as_type_annotation_for_class_attribute_no_error() -> None: 8 | @check_contracts 9 | class AbstractRing(AbstractNetwork): 10 | def __init__(self) -> None: 11 | AbstractNetwork.__init__(self) 12 | 13 | AbstractRing() 14 | -------------------------------------------------------------------------------- /tests/test_custom_checkers/file_fixtures/badModuleName.py: -------------------------------------------------------------------------------- 1 | """Sample file for testing the InvalidNameChecker on bad module names.""" 2 | -------------------------------------------------------------------------------- /tests/test_custom_checkers/test_e9999_local_import/imported_module.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pyta-uoft/pyta/0539d23be047c12316158304e4837b80e1384d75/tests/test_custom_checkers/test_e9999_local_import/imported_module.py -------------------------------------------------------------------------------- /tests/test_debug/snapshot_main_frame.py: -------------------------------------------------------------------------------- 1 | """ 2 | This Python module is designed for testing the snapshot function's ability to return 3 | variables from the __main__ stack frame, particularly globally defined variables. 4 | 5 | This module is intended exclusively for testing purposes and should not be used for any other purpose. 6 | """ 7 | 8 | from __future__ import ( 9 | annotations, # "annotations" should not be included in the snapshot 10 | ) 11 | 12 | import json 13 | 14 | from python_ta.debug.snapshot import snapshot 15 | 16 | # globally defined variables 17 | team_lead = "David Liu" 18 | SDS_projects = ["PyTA", "MarkUs", "Memory Models"] 19 | team_num = 9 20 | 21 | print(json.dumps(snapshot()[0])) 22 | -------------------------------------------------------------------------------- /tests/test_debug/snapshot_save_file.py: -------------------------------------------------------------------------------- 1 | """ 2 | This Python module is designed for testing the snapshot function's ability to, when save is True, 3 | create a snapshot svg at the specified file path. 4 | 5 | This module is intended exclusively for testing purposes and should not be used for any other purpose. 6 | """ 7 | 8 | import os 9 | import sys 10 | 11 | from python_ta.debug.snapshot import snapshot 12 | 13 | test_var1a = "David is cool!" 14 | test_var2a = "Students Developing Software" 15 | snapshot( 16 | True, 17 | [ 18 | "--output=" + os.path.abspath(sys.argv[1]), 19 | "--roughjs-config", 20 | "seed=12345", 21 | ], 22 | "0.3.1", 23 | ) 24 | -------------------------------------------------------------------------------- /tests/test_debug/snapshot_save_stdout.py: -------------------------------------------------------------------------------- 1 | """ 2 | This Python module is designed for testing the snapshot function's ability to, when save is True, 3 | return the snapshot svg to stdout. 4 | 5 | This module is intended exclusively for testing purposes and should not be used for any other purpose. 6 | """ 7 | 8 | from python_ta.debug.snapshot import snapshot 9 | 10 | test_var1a = "David is cool!" 11 | test_var2a = "Students Developing Software" 12 | snapshot(True, ["--roughjs-config", "seed=12345"], "0.3.1") 13 | -------------------------------------------------------------------------------- /tests/test_messages_config/test.messages_config.toml: -------------------------------------------------------------------------------- 1 | ["pylint.checkers.base".BasicChecker] 2 | W0101 = "This custom error message is modified." 3 | -------------------------------------------------------------------------------- /tests/test_messages_config/test.messages_config_incorrect_section_header.toml: -------------------------------------------------------------------------------- 1 | ["This section header is incorrectly defined"] 2 | W0101 = "This custom error message is modified." 3 | -------------------------------------------------------------------------------- /tests/test_messages_config/test.messages_config_no_section_header.toml: -------------------------------------------------------------------------------- 1 | W0101 = "This custom error message is modified." 2 | -------------------------------------------------------------------------------- /tests/test_messages_config/test.messages_config_no_section_header_incorrect_error_message.toml: -------------------------------------------------------------------------------- 1 | W0101 = "This custom error message is modified." 2 | A1234 = "This error id does not exist." 3 | -------------------------------------------------------------------------------- /tests/test_messages_config/test_no_user_config_no_pyta_overwrite.pylintrc: -------------------------------------------------------------------------------- 1 | [CUSTOM PYTA OPTIONS] 2 | 3 | # Make sure to register custom options tuple first in `python_ta/__init__.py` 4 | # =========================================================== 5 | # Set whether the default error messages by pylint should be overwritten by python TA's custom messages 6 | use-pyta-error-messages = no 7 | 8 | [REPORTS] 9 | # The type of reporter to use to display results. Available PyTA options are 10 | # pyta-plain, pyta-color, pyta-html, pyta-json. 11 | # Replaces the pyta-reporter option. 12 | output-format = pyta-plain 13 | -------------------------------------------------------------------------------- /tests/test_messages_config/test_no_user_config_pyta_overwrite.pylintrc: -------------------------------------------------------------------------------- 1 | [CUSTOM PYTA OPTIONS] 2 | 3 | # Make sure to register custom options tuple first in `python_ta/__init__.py` 4 | # =========================================================== 5 | # Set whether the default error messages by pylint should be overwritten by python TA's custom messages 6 | use-pyta-error-messages = yes 7 | 8 | [REPORTS] 9 | # The type of reporter to use to display results. Available PyTA options are 10 | # pyta-plain, pyta-color, pyta-html, pyta-json. 11 | # Replaces the pyta-reporter option. 12 | output-format = pyta-plain 13 | -------------------------------------------------------------------------------- /tests/test_messages_config/test_user_config_incorrect_section_header.pylintrc: -------------------------------------------------------------------------------- 1 | [CUSTOM PYTA OPTIONS] 2 | 3 | # Make sure to register custom options tuple first in `python_ta/__init__.py` 4 | # =========================================================== 5 | # Path to messages_config toml file 6 | messages-config-path = tests/test_messages_config/test.messages_config_incorrect_section_header.toml 7 | 8 | # Set whether the default error messages by pylint should be overwritten by python TA's custom messages 9 | use-pyta-error-messages = yes 10 | 11 | [REPORTS] 12 | # The type of reporter to use to display results. Available PyTA options are 13 | # pyta-plain, pyta-color, pyta-html, pyta-json. 14 | # Replaces the pyta-reporter option. 15 | output-format = pyta-plain 16 | -------------------------------------------------------------------------------- /tests/test_messages_config/test_user_config_no_pyta_overwrite.pylintrc: -------------------------------------------------------------------------------- 1 | [CUSTOM PYTA OPTIONS] 2 | 3 | # Make sure to register custom options tuple first in `python_ta/__init__.py` 4 | # =========================================================== 5 | # Path to messages_config toml file 6 | messages-config-path = tests/test_messages_config/test.messages_config.toml 7 | 8 | # Set whether the default error messages by pylint should be overwritten by python TA's custom messages 9 | use-pyta-error-messages = no 10 | 11 | [REPORTS] 12 | # The type of reporter to use to display results. Available PyTA options are 13 | # pyta-plain, pyta-color, pyta-html, pyta-json. 14 | # Replaces the pyta-reporter option. 15 | output-format = pyta-plain 16 | -------------------------------------------------------------------------------- /tests/test_messages_config/test_user_config_no_section_header_incorrect_error_message.pylintrc: -------------------------------------------------------------------------------- 1 | [CUSTOM PYTA OPTIONS] 2 | 3 | # Make sure to register custom options tuple first in `python_ta/__init__.py` 4 | # =========================================================== 5 | # Path to messages_config toml file 6 | messages-config-path = tests/test_messages_config/test.messages_config_no_section_header_incorrect_error_message.toml 7 | 8 | # Set whether the default error messages by pylint should be overwritten by python TA's custom messages 9 | use-pyta-error-messages = yes 10 | 11 | [REPORTS] 12 | # The type of reporter to use to display results. Available PyTA options are 13 | # pyta-plain, pyta-color, pyta-html, pyta-json. 14 | # Replaces the pyta-reporter option. 15 | output-format = pyta-plain 16 | -------------------------------------------------------------------------------- /tests/test_messages_config/test_user_config_no_section_header_no_pyta_overwrite.pylintrc: -------------------------------------------------------------------------------- 1 | [CUSTOM PYTA OPTIONS] 2 | 3 | # Make sure to register custom options tuple first in `python_ta/__init__.py` 4 | # =========================================================== 5 | # Path to messages_config toml file 6 | messages-config-path = tests/test_messages_config/test.messages_config_no_section_header.toml 7 | 8 | # Set whether the default error messages by pylint should be overwritten by python TA's custom messages 9 | use-pyta-error-messages = no 10 | 11 | [REPORTS] 12 | # The type of reporter to use to display results. Available PyTA options are 13 | # pyta-plain, pyta-color, pyta-html, pyta-json. 14 | # Replaces the pyta-reporter option. 15 | output-format = pyta-plain 16 | -------------------------------------------------------------------------------- /tests/test_messages_config/test_user_config_no_section_header_pyta_overwrite.pylintrc: -------------------------------------------------------------------------------- 1 | [CUSTOM PYTA OPTIONS] 2 | 3 | # Make sure to register custom options tuple first in `python_ta/__init__.py` 4 | # =========================================================== 5 | # Path to messages_config toml file 6 | messages-config-path = tests/test_messages_config/test.messages_config_no_section_header.toml 7 | 8 | # Set whether the default error messages by pylint should be overwritten by python TA's custom messages 9 | use-pyta-error-messages = yes 10 | 11 | [REPORTS] 12 | # The type of reporter to use to display results. Available PyTA options are 13 | # pyta-plain, pyta-color, pyta-html, pyta-json. 14 | # Replaces the pyta-reporter option. 15 | output-format = pyta-plain 16 | -------------------------------------------------------------------------------- /tests/test_messages_config/test_user_config_pyta_overwrite.pylintrc: -------------------------------------------------------------------------------- 1 | [CUSTOM PYTA OPTIONS] 2 | 3 | # Make sure to register custom options tuple first in `python_ta/__init__.py` 4 | # =========================================================== 5 | # Path to messages_config toml file 6 | messages-config-path = tests/test_messages_config/test.messages_config.toml 7 | 8 | # Set whether the default error messages by pylint should be overwritten by python TA's custom messages 9 | use-pyta-error-messages = yes 10 | 11 | [REPORTS] 12 | # The type of reporter to use to display results. Available PyTA options are 13 | # pyta-plain, pyta-color, pyta-html, pyta-json. 14 | # Replaces the pyta-reporter option. 15 | output-format = pyta-plain 16 | -------------------------------------------------------------------------------- /tests/test_messages_config/testing_code.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | reversed(12345) # Error on this line 4 | 5 | 6 | def add(lst: list[int]) -> int: 7 | """Return the sum of the elements in the given list.""" 8 | temp = 0 9 | for item in lst: 10 | temp += item 11 | return temp 12 | temp += 1 # Error on this line 13 | -------------------------------------------------------------------------------- /tests/test_validate_invariants.py: -------------------------------------------------------------------------------- 1 | """ 2 | Test suite for checking the functionality of validate_invariants. 3 | """ 4 | 5 | from __future__ import annotations 6 | 7 | from typing import List 8 | 9 | import pytest 10 | 11 | from python_ta.contracts import check_contracts, validate_invariants 12 | 13 | 14 | @check_contracts 15 | class Person: 16 | """A custom data type that represents data for a person. 17 | 18 | Representation Invariants: 19 | - self.age >= 0 20 | - len(self.friends) > 1 21 | """ 22 | 23 | given_name: str 24 | age: int 25 | friends: List[str] 26 | 27 | def __init__(self, given_name: str, age: int, friends: List[str]) -> None: 28 | """Initialize a new Person object.""" 29 | self.given_name = given_name 30 | self.age = age 31 | self.friends = friends 32 | 33 | 34 | def test_no_errors() -> None: 35 | """Checks that validate_invariants does not raise an error when representation invariants are satisfied.""" 36 | person = Person("Jim", 50, ["Pam", "Dwight"]) 37 | 38 | try: 39 | validate_invariants(person) 40 | except AssertionError: 41 | pytest.fail("validate_invariants has incorrectly raised an AssertionError") 42 | 43 | 44 | def test_raise_error() -> None: 45 | """Checks that validate_invariants raises an error when representation invariants are violated.""" 46 | person = Person("Jim", 50, ["Pam", "Dwight"]) 47 | person.friends.pop() 48 | 49 | with pytest.raises(AssertionError): 50 | validate_invariants(person) 51 | -------------------------------------------------------------------------------- /tests/test_z3/test_z3_parser.py: -------------------------------------------------------------------------------- 1 | """Tests for Z3Parser in python_ta.z3.""" 2 | 3 | from astroid import extract_node 4 | 5 | from python_ta.z3.z3_parser import Z3Parser 6 | 7 | 8 | def test_z3_parser_assignment() -> None: 9 | assignment = "n = 2 + 3" 10 | 11 | node = extract_node(assignment) 12 | parser = Z3Parser() 13 | assert parser.parse(node) == 5 14 | --------------------------------------------------------------------------------