ripple-down-rules 0.6.49__tar.gz → 0.6.51__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (165) hide show
  1. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/PKG-INFO +1 -1
  2. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/doc/intro.md +1 -1
  3. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/doc/relational_example_tutorial.md +2 -2
  4. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/doc/relational_example_with_decorator_tutorial.md +5 -3
  5. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/src/ripple_down_rules/__init__.py +1 -1
  6. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/src/ripple_down_rules/datastructures/callable_expression.py +6 -3
  7. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/src/ripple_down_rules/rdr_decorators.py +97 -81
  8. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/src/ripple_down_rules.egg-info/PKG-INFO +1 -1
  9. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_rdr_decorators.py +0 -2
  10. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_rdr_helpers_rdrs.py +1 -2
  11. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/.github/workflows/build_and_deploy_doc.yml +0 -0
  12. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/.github/workflows/ci.yml +0 -0
  13. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/.github/workflows/publish-to-test-pypi.yml +0 -0
  14. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/.gitignore +0 -0
  15. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/.idea/shelf/Uncommitted_changes_before_Checkout_at_2_4_25,_6_32_PM_[Changes]/shelved.patch +0 -0
  16. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/.idea/shelf/Uncommitted_changes_before_Checkout_at_2_4_25,_6_32_PM_[Changes]1/shelved.patch +0 -0
  17. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/LICENSE +0 -0
  18. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/README.md +0 -0
  19. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/doc/_config.yml +0 -0
  20. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/doc/_toc.yml +0 -0
  21. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/doc/bibliography.md +0 -0
  22. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/doc/propositional_example_tutorial.md +0 -0
  23. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/doc/references.bib +0 -0
  24. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/doc/requirements.txt +0 -0
  25. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/doc/test_driven_rdr_fitting_tutorial.md +0 -0
  26. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/examples/__init__.py +0 -0
  27. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/examples/animal_species.py +0 -0
  28. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/examples/decorator_example.py +0 -0
  29. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/examples/decorator_model.py +0 -0
  30. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/examples/relational_example.py +0 -0
  31. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/examples/relational_model.py +0 -0
  32. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/examples/test_relational_example.py +0 -0
  33. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/images/scrdr.dot +0 -0
  34. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/images/scrdr.png +0 -0
  35. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/images/thinking_pr2.jpg +0 -0
  36. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/pyproject.toml +0 -0
  37. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/pytest.ini +0 -0
  38. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/requirements-dev-ci.txt +0 -0
  39. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/requirements-dev.txt +0 -0
  40. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/requirements-gui.txt +0 -0
  41. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/requirements-viz.txt +0 -0
  42. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/requirements.txt +0 -0
  43. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/results/complete_mcrdr_extra.dot +0 -0
  44. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/results/complete_mcrdr_extra.png +0 -0
  45. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/results/complete_mcrdr_stop_only.dot +0 -0
  46. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/results/complete_mcrdr_stop_only.png +0 -0
  47. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/results/complete_mcrdr_stop_plus_rule.dot +0 -0
  48. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/results/complete_mcrdr_stop_plus_rule.png +0 -0
  49. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/results/complete_scrdr.dot +0 -0
  50. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/results/complete_scrdr.png +0 -0
  51. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/results/complete_scrdr_2.dot +0 -0
  52. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/results/complete_scrdr_2.png +0 -0
  53. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/results/complete_scrdr_3.dot +0 -0
  54. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/results/complete_scrdr_3.png +0 -0
  55. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/results/grdr_Habitat.dot +0 -0
  56. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/results/grdr_Habitat.png +0 -0
  57. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/results/grdr_Species.dot +0 -0
  58. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/results/grdr_Species.png +0 -0
  59. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/results/mcrdr_extra.dot +0 -0
  60. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/results/mcrdr_extra.png +0 -0
  61. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/results/mcrdr_extra_classify.dot +0 -0
  62. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/results/mcrdr_extra_classify.png +0 -0
  63. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/results/mcrdr_stop_plus_rule_combined.dot +0 -0
  64. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/results/mcrdr_stop_plus_rule_combined.png +0 -0
  65. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/results/partial_mcrdr_extra.dot +0 -0
  66. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/results/partial_mcrdr_extra.png +0 -0
  67. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/results/relational_scrdr_classify.dot +0 -0
  68. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/results/relational_scrdr_classify.png +0 -0
  69. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/scripts/live_dot_server_client.py +0 -0
  70. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/setup.cfg +0 -0
  71. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/src/ripple_down_rules/datastructures/__init__.py +0 -0
  72. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/src/ripple_down_rules/datastructures/case.py +0 -0
  73. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/src/ripple_down_rules/datastructures/dataclasses.py +0 -0
  74. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/src/ripple_down_rules/datastructures/enums.py +0 -0
  75. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/src/ripple_down_rules/experts.py +0 -0
  76. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/src/ripple_down_rules/failures.py +0 -0
  77. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/src/ripple_down_rules/helpers.py +0 -0
  78. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/src/ripple_down_rules/rdr.py +0 -0
  79. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/src/ripple_down_rules/rules.py +0 -0
  80. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/src/ripple_down_rules/start-code-server.sh +0 -0
  81. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/src/ripple_down_rules/user_interface/__init__.py +0 -0
  82. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/src/ripple_down_rules/user_interface/gui.py +0 -0
  83. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/src/ripple_down_rules/user_interface/ipython_custom_shell.py +0 -0
  84. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/src/ripple_down_rules/user_interface/object_diagram.py +0 -0
  85. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/src/ripple_down_rules/user_interface/prompt.py +0 -0
  86. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/src/ripple_down_rules/user_interface/template_file_creator.py +0 -0
  87. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/src/ripple_down_rules/utils.py +0 -0
  88. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/src/ripple_down_rules.egg-info/SOURCES.txt +0 -0
  89. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/src/ripple_down_rules.egg-info/dependency_links.txt +0 -0
  90. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/src/ripple_down_rules.egg-info/requires.txt +0 -0
  91. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/src/ripple_down_rules.egg-info/top_level.txt +0 -0
  92. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/__init__.py +0 -0
  93. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/conf/__init__.py +0 -0
  94. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/conf/world/__init__.py +0 -0
  95. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/conf/world/base_config.py +0 -0
  96. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/conf/world/handles_and_containers.py +0 -0
  97. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/conftest.py +0 -0
  98. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/datasets.py +0 -0
  99. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/factories/__init__.py +0 -0
  100. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/factories/world/__init__.py +0 -0
  101. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/factories/world/handles_and_containers.py +0 -0
  102. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_expert_answers/__init__.py +0 -0
  103. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_expert_answers/correct_drawer_rdr_expert_answers_fit.json +0 -0
  104. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_expert_answers/drawer_cabinet_expert_answers_fit.json +0 -0
  105. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_expert_answers/grdr_expert_answers_classify.json +0 -0
  106. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_expert_answers/grdr_expert_answers_fit.json +0 -0
  107. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_expert_answers/grdr_expert_answers_fit.py +0 -0
  108. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_expert_answers/grdr_expert_answers_fit_extra.json +0 -0
  109. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_expert_answers/grdr_expert_answers_fit_no_targets.json +0 -0
  110. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_expert_answers/grdr_expert_answers_fit_no_targets.py +0 -0
  111. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_expert_answers/mcrdr_expert_answers_classify.json +0 -0
  112. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_expert_answers/mcrdr_expert_answers_fit_no_targets.json +0 -0
  113. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_expert_answers/mcrdr_expert_answers_fit_no_targets.py +0 -0
  114. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_expert_answers/mcrdr_expert_answers_stop_only_fit.json +0 -0
  115. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_expert_answers/mcrdr_expert_answers_stop_only_fit.py +0 -0
  116. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_expert_answers/mcrdr_extra_expert_answers_classify.json +0 -0
  117. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_expert_answers/mcrdr_extra_expert_answers_fit.json +0 -0
  118. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_expert_answers/mcrdr_multi_line_expert_answers_fit.json +0 -0
  119. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_expert_answers/mcrdr_multi_line_expert_answers_fit.py +0 -0
  120. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_expert_answers/mcrdr_stop_only_answers_fit.json +0 -0
  121. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_expert_answers/mcrdr_stop_plus_rule_answers_fit.json +0 -0
  122. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_expert_answers/mcrdr_stop_plus_rule_combined_expert_answers_fit.json +0 -0
  123. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_expert_answers/mcrdr_stop_plus_rule_expert_answers_fit.json +0 -0
  124. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_expert_answers/mutagenic_expert_answers.json +0 -0
  125. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_expert_answers/relational_scrdr_expert_answers_classify.json +0 -0
  126. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_expert_answers/scrdr_expert_answers_classify.json +0 -0
  127. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_expert_answers/scrdr_expert_answers_fit.json +0 -0
  128. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_expert_answers/scrdr_expert_answers_fit.py +0 -0
  129. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_expert_answers/scrdr_expert_answers_fit_no_targets.json +0 -0
  130. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_expert_answers/scrdr_expert_answers_fit_no_targets.py +0 -0
  131. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_expert_answers/scrdr_multi_line_expert_answers_fit.json +0 -0
  132. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_expert_answers/scrdr_multi_line_expert_answers_fit.py +0 -0
  133. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_expert_answers/scrdr_world_expert_answers_fit.json +0 -0
  134. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_generated_rdrs/__init__.py +0 -0
  135. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_helpers/__init__.py +0 -0
  136. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_helpers/helpers.py +0 -0
  137. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_helpers/object_diagram_case_query.png +0 -0
  138. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_helpers/object_diagram_person.png +0 -0
  139. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_json_serialization.py +0 -0
  140. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_object_diagram.py +0 -0
  141. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_on_mutagenic.py +0 -0
  142. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_rdr.py +0 -0
  143. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_rdr_alchemy.py +0 -0
  144. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_rdr_world/__init__.py +0 -0
  145. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_rdr_world/conftest.py +0 -0
  146. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_rdr_world/test_rdr_world.py +0 -0
  147. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_relational_rdr.py +0 -0
  148. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_relational_rdr_alchemy.py +0 -0
  149. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_results/__init__.py +0 -0
  150. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_results/datasets_physical_object_is_a_robot/__init__.py +0 -0
  151. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_results/datasets_physical_object_is_a_robot/physical_object_is_a_robot_output__scrdr.py +0 -0
  152. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_results/datasets_physical_object_is_a_robot/physical_object_is_a_robot_output__scrdr_defs.py +0 -0
  153. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_results/datasets_physical_object_is_a_robot/physical_object_is_a_robot_rdr.py +0 -0
  154. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_results/datasets_physical_object_select_objects_that_are_parts_of_robot/__init__.py +0 -0
  155. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_results/datasets_physical_object_select_objects_that_are_parts_of_robot/physical_object_select_objects_that_are_parts_of_robot_output__mcrdr.py +0 -0
  156. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_results/datasets_physical_object_select_objects_that_are_parts_of_robot/physical_object_select_objects_that_are_parts_of_robot_output__mcrdr_defs.py +0 -0
  157. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_results/datasets_physical_object_select_objects_that_are_parts_of_robot/physical_object_select_objects_that_are_parts_of_robot_rdr.py +0 -0
  158. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_sql_model.py +0 -0
  159. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_template_file_creator.py +0 -0
  160. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_user_interface/__init__.py +0 -0
  161. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_user_interface/test_ipython.py +0 -0
  162. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_user_interface/test_ipython_copilot.py +0 -0
  163. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_user_interface/test_prompt.py +0 -0
  164. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_user_interface/test_qt_gui_inline.py +0 -0
  165. {ripple_down_rules-0.6.49 → ripple_down_rules-0.6.51}/test/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ripple_down_rules
3
- Version: 0.6.49
3
+ Version: 0.6.51
4
4
  Summary: Implements the various versions of Ripple Down Rules (RDR) for knowledge representation and reasoning.
5
5
  Author-email: Abdelrhman Bassiouny <abassiou@uni-bremen.de>
6
6
  License: GNU GENERAL PUBLIC LICENSE
@@ -13,7 +13,7 @@ SCRDR, MCRDR, and GRDR logic were inspired from the book:
13
13
  ["Ripple Down Rules: An Alternative to Machine Learning"](https://www.taylorfrancis.com/books/mono/10.1201/9781003126157/ripple-rules-paul-compton-byeong-ho-kang) by Paul Compton, Byeong Ho Kang.
14
14
 
15
15
 
16
- ## 🚀 Enhanced Ripple-Down Rules Engine – Key Features
16
+ ## 🚀 Key Features
17
17
 
18
18
  ### 🧠 Data Model (Ontology) + Rule Base as One Entity
19
19
  - 🧬 Unified data structure: Data Model (Ontology) and rules use the same Python data structures.
@@ -73,7 +73,7 @@ from ripple_down_rules import CaseQuery, GeneralRDR
73
73
 
74
74
  grdr = GeneralRDR(save_dir='./', model_name='part_containment_rdr')
75
75
 
76
- case_query = CaseQuery(robot, "contained_objects", (PhysicalObject,), False)
76
+ case_query = CaseQuery(robot, "contained_objects", (PhysicalObject,), mutually_exclusive=False)
77
77
  ```
78
78
 
79
79
  ### Fit the Model to the Case Query by Answering the prompts.
@@ -83,7 +83,7 @@ grdr.fit_case(case_query)
83
83
 
84
84
  When prompted to write a rule, I press edit in GUI (or type %edit in the Ipython interface if not using GUI),
85
85
  I wrote the following inside the template function that the Ripple Down Rules created for me, this function takes a
86
- `case` object as input:
86
+ `case` object as input, in this exampke the case is the `Robot` instance:
87
87
 
88
88
  ```python
89
89
  contained_objects = []
@@ -86,7 +86,7 @@ assert contained_objects == [part_b]
86
86
 
87
87
  When prompted to write a rule, I press edit in GUI (or type %edit in the Ipython interface if not using GUI),
88
88
  I wrote the following inside the template function that the Ripple Down Rules created for me, this function takes a
89
- `case` object as input:
89
+ `case` object as input, in this exampke the case is the `Robot` instance:
90
90
 
91
91
  ```python
92
92
  contained_objects = []
@@ -114,8 +114,10 @@ This means that the rule will only be applied if the robot has parts.
114
114
  We can let the fit mode be `True`, but give the rdr a function that tells it when to prompt for an answer.
115
115
  For example, we can ask for an answer only when the robot's name is "tracy", which will result in the rdr not asking
116
116
  for an answer because the robot name is "pr2" for the current case.
117
- The input to the `ask_now` function is a dictionary with the original function arguments, while arguments like
118
- `self` and `cls` are passed as a special key `'self_'` or `'cls_'` respectively.
117
+ The {py:attr}`ripple_down_rules.rdr_decorators.RDRDecorator.ask_now` is a user provided callable function that outputs
118
+ a boolean indicating when to ask the expert for an answer. The input to the `ask_now` function is a dictionary with the
119
+ original function arguments, while arguments like `self` and `cls` are passed as a special key `'self_'` or `'cls_'`
120
+ respectively.
119
121
  ```python
120
122
  robot.containment_rdr.fit = True
121
123
  robot.containment_rdr.ask_now = lambda case: case['self_'].name == "tracy"
@@ -1,4 +1,4 @@
1
- __version__ = "0.6.49"
1
+ __version__ = "0.6.51"
2
2
 
3
3
  import logging
4
4
  import sys
@@ -130,8 +130,10 @@ class CallableExpression(SubclassJSONSerializer):
130
130
  conclusion_type = (conclusion_type,)
131
131
  self.conclusion_type = conclusion_type
132
132
  self.expected_types: Set[Type] = set(conclusion_type) if conclusion_type is not None else set()
133
- if not mutually_exclusive:
134
- self.expected_types.update({list, set})
133
+ if list in self.expected_types:
134
+ self.expected_types.remove(list)
135
+ if set in self.expected_types:
136
+ self.expected_types.add(set)
135
137
  self.scope: Optional[Dict[str, Any]] = scope if scope is not None else {}
136
138
  self.scope = get_used_scope(self.user_input, self.scope)
137
139
  self.expression_tree: AST = expression_tree if expression_tree else parse_string_to_expression(self.user_input)
@@ -149,6 +151,8 @@ class CallableExpression(SubclassJSONSerializer):
149
151
 
150
152
  def __call__(self, case: Any, **kwargs) -> Any:
151
153
  try:
154
+ # if not self.mutually_exclusive:
155
+ # self.expected_types.update({list, set})
152
156
  if self.user_input is not None:
153
157
  if not isinstance(case, Case):
154
158
  case = create_case(case, max_recursion_idx=3)
@@ -160,7 +164,6 @@ class CallableExpression(SubclassJSONSerializer):
160
164
  if self.mutually_exclusive and issubclass(type(output), (list, set)):
161
165
  raise ValueError(f"Mutually exclusive types cannot be lists or sets, got {type(output)}")
162
166
  output_types = {type(o) for o in make_list(output)}
163
- output_types.add(type(output))
164
167
  if not are_results_subclass_of_types(output_types, self.expected_types):
165
168
  raise ValueError(f"Not all result types {output_types} are subclasses of expected types"
166
169
  f" {self.conclusion_type}")
@@ -4,17 +4,18 @@ that can be used with any python function such that this function can benefit fr
4
4
  of the RDRs.
5
5
  """
6
6
  import os.path
7
+ from dataclasses import dataclass, field
7
8
  from functools import wraps
8
9
  from typing import get_origin
9
10
 
10
11
  from typing_extensions import Callable, Optional, Type, Tuple, Dict, Any, Self, get_type_hints, List, Union, Sequence
11
12
 
12
- from .utils import get_type_from_type_hint
13
13
  from .datastructures.case import Case
14
14
  from .datastructures.dataclasses import CaseQuery
15
15
  from .experts import Expert, Human
16
16
  from .rdr import GeneralRDR
17
- from . import logger
17
+ from .utils import get_type_from_type_hint
18
+
18
19
  try:
19
20
  from .user_interface.gui import RDRCaseViewer
20
21
  except ImportError:
@@ -23,63 +24,91 @@ from .utils import get_method_args_as_dict, get_func_rdr_model_name, make_set, \
23
24
  get_method_class_if_exists, str_to_snake_case, make_list
24
25
 
25
26
 
27
+ @dataclass(unsafe_hash=True)
26
28
  class RDRDecorator:
27
- rdr: GeneralRDR
28
-
29
- def __init__(self, models_dir: str,
30
- output_type: Tuple[Type],
31
- mutual_exclusive: bool,
32
- output_name: str = "output_",
33
- fit: bool = True,
34
- expert: Optional[Expert] = None,
35
- update_existing_rules: bool = True,
36
- viewer: Optional[RDRCaseViewer] = None,
37
- package_name: Optional[str] = None,
38
- use_generated_classifier: bool = False,
39
- ask_now: Callable[Dict[str, Any], bool] = lambda _: True,
40
- fitting_decorator: Optional[Callable] = None,
41
- generate_dot_file: bool = False) -> None:
42
- """
43
- :param models_dir: The directory to save/load the RDR models.
44
- :param output_type: The type of the output. This is used to create the RDR model.
45
- :param mutual_exclusive: If True, the output types are mutually exclusive.
46
- If None, the RDR model will not be saved as a python file.
47
- :param output_name: The name of the output. This is used to create the RDR model.
48
- :param fit: If True, the function will be in fit mode. This means that the RDR will prompt the user for the
49
- correct output if the function's output is not in the RDR model. If False, the function will be in
50
- classification mode. This means that the RDR will classify the function's output based on the RDR model.
51
- :param expert: The expert that will be used to prompt the user for the correct output. If None, a Human
52
- expert will be used.
53
- :param update_existing_rules: If True, the function will update the existing RDR rules
54
- even if they gave an output.
55
- :param viewer: The viewer to use for the RDR model. If None, no viewer will be used.
56
- :param package_name: The package name to use for relative imports in the RDR model.
57
- :param use_generated_classifier: If True, the function will use the generated classifier instead of the RDR model.
58
- :param ask_now: A callable that takes the case dictionary and returns True if the user should be asked for
59
- the output, or False if the function should return the output without asking.
60
- :param fitting_decorator: A decorator to use for the fitting function. If None, no decorator will be used.
61
- :param generate_dot_file: If True, the RDR model will generate a dot file for visualization.
62
- :return: A decorator to use a GeneralRDR as a classifier that monitors and modifies the function's output.
63
- """
64
- self.rdr_models_dir = models_dir
65
- self.model_name: Optional[str] = None
66
- self.output_type = output_type
67
- self.parsed_output_type: List[Type] = []
68
- self.mutual_exclusive = mutual_exclusive
69
- self.output_name = output_name
70
- self.fit: bool = fit
71
- self.expert: Optional[Expert] = expert
72
- self.update_existing_rules = update_existing_rules
73
- self.viewer = viewer
74
- self.package_name = package_name
75
- self.use_generated_classifier = use_generated_classifier
76
- self.generated_classifier: Optional[Callable] = None
77
- self.ask_now = ask_now
78
- self.fitting_decorator = fitting_decorator if fitting_decorator is not None else \
79
- lambda f: f # Default to no fitting decorator
80
- self.generate_dot_file = generate_dot_file
81
- self.not_none_output_found: bool = False
82
- self.origin_type: Optional[Type] = None
29
+ models_dir: str
30
+ """
31
+ The directory to save the RDR models in.
32
+ """
33
+ output_type: Tuple[Type, ...]
34
+ """
35
+ The type(s) of the output produced by the RDR model (The type(s) of the queried attribute).
36
+ """
37
+ mutual_exclusive: bool
38
+ """
39
+ Whether the queried attribute is mutually exclusive (i.e. allows for only one possible value) or not.
40
+ """
41
+ fit: bool = field(default=True)
42
+ """
43
+ Whether to run in fitting mode and prompt the expert or just classify using existing rules.
44
+ """
45
+ expert: Optional[Expert] = field(default=None)
46
+ """
47
+ The expert instance, this is used by the rdr to prompt for answers.
48
+ """
49
+ update_existing_rules: bool = field(default=True)
50
+ """
51
+ When in fitting mode, whether to ask for answers for existing rules as well or not.
52
+ """
53
+ package_name: Optional[str] = field(default=None)
54
+ """
55
+ The name of the user python package where the RDR model will be saved, this is useful for generating relative
56
+ imports in the generated rdr model files.
57
+ """
58
+ use_generated_classifier: bool = field(default=False)
59
+ """
60
+ Whether to use the generated classifier files of the rdr model instead of the RDR instance itself, this is useful
61
+ when you want to debug inside the rules.
62
+ """
63
+ ask_now: Callable[Dict[str, Any], bool] = field(default=lambda _: True)
64
+ """
65
+ A user provided callable function that outputs a boolean indicating when to ask the expert for an answer. The input
66
+ to the `ask_now` function is a dictionary with the original function arguments, while arguments like `self` and
67
+ `cls` are passed as a special key `self_` or `cls_` respectively.
68
+ """
69
+ fitting_decorator: Optional[Callable] = field(default=lambda f: f)
70
+ """
71
+ A user provided decorator that wraps the `py:meth:ripple_down_rules.rdr.RippleDownRules.fit_case` method which is
72
+ used when in fitting mode, this is useful when you want special logic pre and post the fitting operation, you can
73
+ for example freeze your system during fitting such that you have a stable state that you can query and use while
74
+ writing and testing your answer/rule.
75
+ """
76
+ generate_dot_file: bool = field(default=False)
77
+ """
78
+ Whether to generate a dynamic dot file representing the state of the rule tree each time the rdr is queried, showing
79
+ which rules fired and which rules didn't get evaluated, ...etc.
80
+ """
81
+ model_name: Optional[str] = field(default=None)
82
+ """
83
+ The name of the rdr model, this gets auto generated from the function signature and the class/file it is contained
84
+ in.
85
+ """
86
+ rdr: GeneralRDR = field(init=False)
87
+ """
88
+ The ripple down rules instance of the decorator class.
89
+ """
90
+ parsed_output_type: List[Type] = field(init=False, default_factory=list)
91
+ """
92
+ The output of a post processing done on the output types, for example converting typing module types
93
+ (i.e. type hints) to python types.
94
+ """
95
+ origin_type: Optional[Type] = field(init=False, default=None)
96
+ """
97
+ The origin of the type hint of the attribute, useful in the case of not mutually exclusive attributes to map the
98
+ result to the specified container type (e.g. a list instead of a set which is the default container type for rdr
99
+ output).
100
+ """
101
+ output_name: str = field(init=False, default='output_')
102
+ """
103
+ This is used to refer to the output value of the decorated function, this is used as part of the case as input to
104
+ the rdr model, but is never used in the rule logic to prevent cycles from happening. The correct way to use the
105
+ output of an rdr is through refinement rules which happens automatically by the rdr prompting for refinements.
106
+ """
107
+ _not_none_output_found: bool = field(init=False, default=False)
108
+ """
109
+ This is a flag that indicates that a not None output for the rdr has been inferred, this is used to update the
110
+ generated dot file if it is set to `True`.
111
+ """
83
112
 
84
113
  def decorator(self, func: Callable) -> Callable:
85
114
 
@@ -102,33 +131,33 @@ class RDRDecorator:
102
131
  if len(self.parsed_output_type) == 0:
103
132
  self.parsed_output_type = self.parse_output_type(func, self.output_type, *args)
104
133
  if self.expert is None:
105
- self.expert = Human(answers_save_path=self.rdr_models_dir + f'/{self.model_name}/expert_answers')
134
+ self.expert = Human(answers_save_path=self.models_dir + f'/{self.model_name}/expert_answers')
106
135
  case_query = self.create_case_query_from_method(func, func_output,
107
136
  self.parsed_output_type,
108
137
  self.mutual_exclusive,
109
138
  case, case_dict,
110
139
  *args, **kwargs)
111
140
  output = self.rdr.fit_case(case_query, expert=self.expert,
112
- update_existing_rules=self.update_existing_rules,
113
- viewer=self.viewer)
141
+ update_existing_rules=self.update_existing_rules)
114
142
  return output
115
-
143
+
116
144
  if self.fit and not self.use_generated_classifier and self.ask_now(case_dict):
117
145
  output = fit()
118
146
  else:
119
147
  if self.use_generated_classifier:
120
148
  if self.generated_classifier is None:
121
- model_path = os.path.join(self.rdr_models_dir, self.model_name)
149
+ model_path = os.path.join(self.models_dir, self.model_name)
122
150
  self.generated_classifier = self.rdr.get_rdr_classifier_from_python_file(model_path)
123
151
  output = self.generated_classifier(case)
124
152
  else:
125
153
  output = self.rdr.classify(case)
126
154
  if self.generate_dot_file:
127
155
  eval_rule_tree = self.rdr.get_evaluated_rule_tree()
128
- if not self.not_none_output_found or (eval_rule_tree and len(eval_rule_tree) > 1):
129
- self.rdr.render_evaluated_rule_tree(self.rdr_models_dir + f'/{self.model_name}', show_full_tree=True)
156
+ if not self._not_none_output_found or (eval_rule_tree and len(eval_rule_tree) > 1):
157
+ self.rdr.render_evaluated_rule_tree(self.models_dir + f'/{self.model_name}',
158
+ show_full_tree=True)
130
159
  if eval_rule_tree and len(eval_rule_tree) > 1:
131
- self.not_none_output_found = True
160
+ self._not_none_output_found = True
132
161
 
133
162
  if self.output_name in output:
134
163
  if self.origin_type == list:
@@ -189,7 +218,6 @@ class RDRDecorator:
189
218
  return Case(dict, id(case_dict), case_name, case_dict, **case_dict), case_dict
190
219
 
191
220
  def initialize_rdr_model_name_and_load(self, func: Callable) -> None:
192
- self.viewer = RDRCaseViewer.instances[0] if RDRCaseViewer is not None and len(RDRCaseViewer.instances) > 0 else self.viewer
193
221
  model_file_name = get_func_rdr_model_name(func, include_file_name=True)
194
222
  self.model_name = str_to_snake_case(model_file_name)
195
223
  self.load()
@@ -209,20 +237,8 @@ class RDRDecorator:
209
237
  parsed_output_type.append(ot)
210
238
  return parsed_output_type
211
239
 
212
- def save(self):
213
- """
214
- Save the RDR model to the specified directory.
215
- """
216
- self.rdr.save(self.rdr_models_dir, self.model_name, package_name=self.package_name)
217
-
218
240
  def load(self):
219
241
  """
220
- Load the RDR model from the specified directory.
221
- """
222
- self.rdr = GeneralRDR(save_dir=self.rdr_models_dir, model_name=self.model_name)
223
-
224
- def update_from_python(self):
225
- """
226
- Update the RDR model from a python file.
242
+ Load the RDR model from the specified directory, otherwise create a new one.
227
243
  """
228
- self.rdr.update_from_python(self.rdr_models_dir, parent_package_name=self.package_name)
244
+ self.rdr = GeneralRDR(save_dir=self.models_dir, model_name=self.model_name)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ripple_down_rules
3
- Version: 0.6.49
3
+ Version: 0.6.51
4
4
  Summary: Implements the various versions of Ripple Down Rules (RDR) for knowledge representation and reasoning.
5
5
  Author-email: Abdelrhman Bassiouny <abassiou@uni-bremen.de>
6
6
  License: GNU GENERAL PUBLIC LICENSE
@@ -14,7 +14,6 @@ class RDRDecoratorsTestCase(unittest.TestCase):
14
14
  self.physical_object._is_a_robot_rdr.fit = False
15
15
  self.assertFalse(self.physical_object.is_a_robot())
16
16
  self.assertTrue(self.robot.is_a_robot())
17
- self.physical_object._is_a_robot_rdr.save()
18
17
 
19
18
  def test_select_objects_that_are_parts_of_robots(self):
20
19
  self.physical_object._select_parts_rdr.fit = False
@@ -24,4 +23,3 @@ class RDRDecoratorsTestCase(unittest.TestCase):
24
23
  self.assertIn(part, self.robot.parts)
25
24
  self.assertNotIn(self.part_3, selected_parts)
26
25
  self.assertNotIn(self.robot, selected_parts)
27
- self.physical_object._select_parts_rdr.save()
@@ -11,8 +11,7 @@ save_dir = join(dirname(__file__), '..', 'src', 'ripple_down_rules')
11
11
  # viewer = RDRCaseViewer(save_dir=save_dir)
12
12
  viewer = None
13
13
  rdr_decorator: RDRDecorator = RDRDecorator(save_dir, (bool,), True,
14
- fit=False,
15
- viewer=viewer)
14
+ fit=False)
16
15
 
17
16
 
18
17
  @rdr_decorator.decorator