ripple-down-rules 0.6.18__tar.gz → 0.6.20__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 (153) hide show
  1. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/PKG-INFO +1 -1
  2. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/src/ripple_down_rules/__init__.py +1 -1
  3. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/src/ripple_down_rules/rdr_decorators.py +9 -1
  4. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/src/ripple_down_rules/utils.py +256 -4
  5. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/src/ripple_down_rules.egg-info/PKG-INFO +1 -1
  6. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/.github/workflows/build_and_deploy_doc.yml +0 -0
  7. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/.github/workflows/ci.yml +0 -0
  8. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/.github/workflows/publish-to-test-pypi.yml +0 -0
  9. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/.gitignore +0 -0
  10. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/.idea/shelf/Uncommitted_changes_before_Checkout_at_2_4_25,_6_32_PM_[Changes]/shelved.patch +0 -0
  11. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/.idea/shelf/Uncommitted_changes_before_Checkout_at_2_4_25,_6_32_PM_[Changes]1/shelved.patch +0 -0
  12. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/LICENSE +0 -0
  13. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/README.md +0 -0
  14. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/doc/_config.yml +0 -0
  15. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/doc/_toc.yml +0 -0
  16. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/doc/bibliography.md +0 -0
  17. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/doc/intro.md +0 -0
  18. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/doc/references.bib +0 -0
  19. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/doc/requirements.txt +0 -0
  20. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/examples/__init__.py +0 -0
  21. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/examples/animal_species.py +0 -0
  22. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/examples/part_containment_rdr/__init__.py +0 -0
  23. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/examples/part_containment_rdr/rdr_metadata/part_containment_rdr.json +0 -0
  24. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/examples/part_containment_rdr/robot_contained_objects_mcrdr.py +0 -0
  25. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/examples/part_containment_rdr/robot_contained_objects_mcrdr_defs.py +0 -0
  26. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/examples/part_containment_rdr/robot_rdr.py +0 -0
  27. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/examples/relational_example.py +0 -0
  28. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/images/scrdr.dot +0 -0
  29. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/images/scrdr.png +0 -0
  30. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/images/thinking_pr2.jpg +0 -0
  31. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/pyproject.toml +0 -0
  32. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/pytest.ini +0 -0
  33. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/requirements-dev-ci.txt +0 -0
  34. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/requirements-dev.txt +0 -0
  35. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/requirements-gui.txt +0 -0
  36. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/requirements-viz.txt +0 -0
  37. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/requirements.txt +0 -0
  38. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/results/complete_mcrdr_extra.dot +0 -0
  39. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/results/complete_mcrdr_extra.png +0 -0
  40. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/results/complete_mcrdr_stop_only.dot +0 -0
  41. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/results/complete_mcrdr_stop_only.png +0 -0
  42. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/results/complete_mcrdr_stop_plus_rule.dot +0 -0
  43. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/results/complete_mcrdr_stop_plus_rule.png +0 -0
  44. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/results/complete_scrdr.dot +0 -0
  45. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/results/complete_scrdr.png +0 -0
  46. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/results/complete_scrdr_2.dot +0 -0
  47. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/results/complete_scrdr_2.png +0 -0
  48. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/results/complete_scrdr_3.dot +0 -0
  49. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/results/complete_scrdr_3.png +0 -0
  50. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/results/grdr_Habitat.dot +0 -0
  51. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/results/grdr_Habitat.png +0 -0
  52. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/results/grdr_Species.dot +0 -0
  53. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/results/grdr_Species.png +0 -0
  54. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/results/mcrdr_extra.dot +0 -0
  55. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/results/mcrdr_extra.png +0 -0
  56. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/results/mcrdr_extra_classify.dot +0 -0
  57. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/results/mcrdr_extra_classify.png +0 -0
  58. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/results/mcrdr_stop_plus_rule_combined.dot +0 -0
  59. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/results/mcrdr_stop_plus_rule_combined.png +0 -0
  60. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/results/partial_mcrdr_extra.dot +0 -0
  61. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/results/partial_mcrdr_extra.png +0 -0
  62. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/results/relational_scrdr_classify.dot +0 -0
  63. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/results/relational_scrdr_classify.png +0 -0
  64. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/scripts/live_dot_server.py +0 -0
  65. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/setup.cfg +0 -0
  66. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/src/ripple_down_rules/datastructures/__init__.py +0 -0
  67. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/src/ripple_down_rules/datastructures/callable_expression.py +0 -0
  68. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/src/ripple_down_rules/datastructures/case.py +0 -0
  69. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/src/ripple_down_rules/datastructures/dataclasses.py +0 -0
  70. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/src/ripple_down_rules/datastructures/enums.py +0 -0
  71. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/src/ripple_down_rules/experts.py +0 -0
  72. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/src/ripple_down_rules/helpers.py +0 -0
  73. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/src/ripple_down_rules/rdr.py +0 -0
  74. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/src/ripple_down_rules/rules.py +0 -0
  75. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/src/ripple_down_rules/start-code-server.sh +0 -0
  76. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/src/ripple_down_rules/user_interface/__init__.py +0 -0
  77. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/src/ripple_down_rules/user_interface/gui.py +0 -0
  78. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/src/ripple_down_rules/user_interface/ipython_custom_shell.py +0 -0
  79. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/src/ripple_down_rules/user_interface/object_diagram.py +0 -0
  80. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/src/ripple_down_rules/user_interface/prompt.py +0 -0
  81. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/src/ripple_down_rules/user_interface/template_file_creator.py +0 -0
  82. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/src/ripple_down_rules.egg-info/SOURCES.txt +0 -0
  83. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/src/ripple_down_rules.egg-info/dependency_links.txt +0 -0
  84. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/src/ripple_down_rules.egg-info/requires.txt +0 -0
  85. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/src/ripple_down_rules.egg-info/top_level.txt +0 -0
  86. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/__init__.py +0 -0
  87. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/conf/__init__.py +0 -0
  88. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/conf/world/__init__.py +0 -0
  89. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/conf/world/base_config.py +0 -0
  90. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/conf/world/handles_and_containers.py +0 -0
  91. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/conftest.py +0 -0
  92. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/datasets.py +0 -0
  93. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/factories/__init__.py +0 -0
  94. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/factories/world/__init__.py +0 -0
  95. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/factories/world/handles_and_containers.py +0 -0
  96. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_expert_answers/correct_drawer_rdr_expert_answers_fit.json +0 -0
  97. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_expert_answers/drawer_cabinet_expert_answers_fit.json +0 -0
  98. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_expert_answers/grdr_expert_answers_classify.json +0 -0
  99. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_expert_answers/grdr_expert_answers_fit.json +0 -0
  100. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_expert_answers/grdr_expert_answers_fit_extra.json +0 -0
  101. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_expert_answers/grdr_expert_answers_fit_no_targets.json +0 -0
  102. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_expert_answers/mcrdr_expert_answers_classify.json +0 -0
  103. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_expert_answers/mcrdr_expert_answers_fit_no_targets.json +0 -0
  104. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_expert_answers/mcrdr_expert_answers_stop_only_fit.json +0 -0
  105. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_expert_answers/mcrdr_extra_expert_answers_classify.json +0 -0
  106. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_expert_answers/mcrdr_extra_expert_answers_fit.json +0 -0
  107. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_expert_answers/mcrdr_multi_line_expert_answers_fit.json +0 -0
  108. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_expert_answers/mcrdr_stop_only_answers_fit.json +0 -0
  109. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_expert_answers/mcrdr_stop_plus_rule_answers_fit.json +0 -0
  110. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_expert_answers/mcrdr_stop_plus_rule_combined_expert_answers_fit.json +0 -0
  111. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_expert_answers/mcrdr_stop_plus_rule_expert_answers_fit.json +0 -0
  112. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_expert_answers/mutagenic_expert_answers.json +0 -0
  113. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_expert_answers/relational_scrdr_expert_answers_classify.json +0 -0
  114. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_expert_answers/scrdr_expert_answers_classify.json +0 -0
  115. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_expert_answers/scrdr_expert_answers_fit.json +0 -0
  116. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_expert_answers/scrdr_expert_answers_fit_no_targets.json +0 -0
  117. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_expert_answers/scrdr_multi_line_expert_answers_fit.json +0 -0
  118. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_expert_answers/scrdr_world_expert_answers_fit.json +0 -0
  119. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_generated_rdrs/__init__.py +0 -0
  120. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_helpers/__init__.py +0 -0
  121. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_helpers/helpers.py +0 -0
  122. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_helpers/object_diagram_case_query.png +0 -0
  123. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_helpers/object_diagram_person.png +0 -0
  124. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_json_serialization.py +0 -0
  125. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_object_diagram.py +0 -0
  126. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_on_mutagenic.py +0 -0
  127. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_rdr.py +0 -0
  128. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_rdr_alchemy.py +0 -0
  129. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_rdr_decorators.py +0 -0
  130. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_rdr_helpers_rdrs.py +0 -0
  131. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_rdr_world/__init__.py +0 -0
  132. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_rdr_world/conftest.py +0 -0
  133. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_rdr_world/test_rdr_world.py +0 -0
  134. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_relational_rdr.py +0 -0
  135. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_relational_rdr_alchemy.py +0 -0
  136. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_results/datasets_physical_object_is_a_robot/__init__.py +0 -0
  137. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_results/datasets_physical_object_is_a_robot/physical_object_is_a_robot_output__scrdr.py +0 -0
  138. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_results/datasets_physical_object_is_a_robot/physical_object_is_a_robot_output__scrdr_defs.py +0 -0
  139. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_results/datasets_physical_object_is_a_robot/physical_object_is_a_robot_rdr.py +0 -0
  140. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_results/datasets_physical_object_is_a_robot/rdr_metadata/datasets_physical_object_is_a_robot.json +0 -0
  141. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_results/datasets_physical_object_select_objects_that_are_parts_of_robot/__init__.py +0 -0
  142. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/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
  143. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/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
  144. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/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
  145. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_results/datasets_physical_object_select_objects_that_are_parts_of_robot/rdr_metadata/datasets_physical_object_select_objects_that_are_parts_of_robot.json +0 -0
  146. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_sql_model.py +0 -0
  147. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_template_file_creator.py +0 -0
  148. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_user_interface/__init__.py +0 -0
  149. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_user_interface/test_ipython.py +0 -0
  150. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_user_interface/test_ipython_copilot.py +0 -0
  151. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_user_interface/test_prompt.py +0 -0
  152. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/test/test_user_interface/test_qt_gui_inline.py +0 -0
  153. {ripple_down_rules-0.6.18 → ripple_down_rules-0.6.20}/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.18
3
+ Version: 0.6.20
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
@@ -1,4 +1,4 @@
1
- __version__ = "0.6.18"
1
+ __version__ = "0.6.20"
2
2
 
3
3
  import logging
4
4
  logger = logging.Logger("rdr")
@@ -34,7 +34,8 @@ class RDRDecorator:
34
34
  package_name: Optional[str] = None,
35
35
  use_generated_classifier: bool = False,
36
36
  ask_now: Callable[Dict[str, Any], bool] = lambda _: True,
37
- fitting_decorator: Optional[Callable] = None):
37
+ fitting_decorator: Optional[Callable] = None,
38
+ generate_dot_file: bool = False) -> None:
38
39
  """
39
40
  :param models_dir: The directory to save/load the RDR models.
40
41
  :param output_type: The type of the output. This is used to create the RDR model.
@@ -51,6 +52,10 @@ class RDRDecorator:
51
52
  :param viewer: The viewer to use for the RDR model. If None, no viewer will be used.
52
53
  :param package_name: The package name to use for relative imports in the RDR model.
53
54
  :param use_generated_classifier: If True, the function will use the generated classifier instead of the RDR model.
55
+ :param ask_now: A callable that takes the case dictionary and returns True if the user should be asked for
56
+ the output, or False if the function should return the output without asking.
57
+ :param fitting_decorator: A decorator to use for the fitting function. If None, no decorator will be used.
58
+ :param generate_dot_file: If True, the RDR model will generate a dot file for visualization.
54
59
  :return: A decorator to use a GeneralRDR as a classifier that monitors and modifies the function's output.
55
60
  """
56
61
  self.rdr_models_dir = models_dir
@@ -69,6 +74,7 @@ class RDRDecorator:
69
74
  self.ask_now = ask_now
70
75
  self.fitting_decorator = fitting_decorator if fitting_decorator is not None else \
71
76
  lambda f: f # Default to no fitting decorator
77
+ self.generate_dot_file = generate_dot_file
72
78
  self.load()
73
79
 
74
80
  def decorator(self, func: Callable) -> Callable:
@@ -110,6 +116,8 @@ class RDRDecorator:
110
116
  output = self.generated_classifier(case)
111
117
  else:
112
118
  output = self.rdr.classify(case)
119
+ if self.generate_dot_file:
120
+ self.rdr.render_evaluated_rule_tree(self.rdr_models_dir + f'/{self.model_name}')
113
121
 
114
122
  if self.output_name in output:
115
123
  return output[self.output_name]
@@ -1,6 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import builtins
4
+ import codecs
4
5
  import copyreg
5
6
  import importlib
6
7
  import json
@@ -16,9 +17,12 @@ from dataclasses import is_dataclass, fields
16
17
  from enum import Enum
17
18
  from os.path import dirname
18
19
  from pathlib import Path
20
+ from subprocess import check_call
21
+ from tempfile import NamedTemporaryFile
19
22
  from textwrap import dedent
20
23
  from types import NoneType
21
24
 
25
+ import six
22
26
  from sqlalchemy.exc import NoInspectionAvailable
23
27
 
24
28
  try:
@@ -1629,12 +1633,204 @@ def edge_attr_setter(parent, child):
1629
1633
  return ""
1630
1634
 
1631
1635
 
1632
- class FilteredDotExporter(DotExporter):
1633
- def __init__(self, root, include_nodes=None, **kwargs):
1636
+ _RE_ESC = re.compile(r'["\\]')
1637
+ class FilteredDotExporter(object):
1638
+
1639
+ def __init__(self, node, include_nodes=None, graph="digraph", name="tree", options=None,
1640
+ indent=4, nodenamefunc=None, nodeattrfunc=None,
1641
+ edgeattrfunc=None, edgetypefunc=None, maxlevel=None):
1642
+ """
1643
+ Dot Language Exporter.
1644
+
1645
+ Args:
1646
+ node (Node): start node.
1647
+
1648
+ Keyword Args:
1649
+ graph: DOT graph type.
1650
+
1651
+ name: DOT graph name.
1652
+
1653
+ options: list of options added to the graph.
1654
+
1655
+ indent (int): number of spaces for indent.
1656
+
1657
+ nodenamefunc: Function to extract node name from `node` object.
1658
+ The function shall accept one `node` object as
1659
+ argument and return the name of it.
1660
+
1661
+ nodeattrfunc: Function to decorate a node with attributes.
1662
+ The function shall accept one `node` object as
1663
+ argument and return the attributes.
1664
+
1665
+ edgeattrfunc: Function to decorate a edge with attributes.
1666
+ The function shall accept two `node` objects as
1667
+ argument. The first the node and the second the child
1668
+ and return the attributes.
1669
+
1670
+ edgetypefunc: Function to which gives the edge type.
1671
+ The function shall accept two `node` objects as
1672
+ argument. The first the node and the second the child
1673
+ and return the edge (i.e. '->').
1674
+
1675
+ maxlevel (int): Limit export to this number of levels.
1676
+
1677
+ >>> from anytree import Node
1678
+ >>> root = Node("root")
1679
+ >>> s0 = Node("sub0", parent=root, edge=2)
1680
+ >>> s0b = Node("sub0B", parent=s0, foo=4, edge=109)
1681
+ >>> s0a = Node("sub0A", parent=s0, edge="")
1682
+ >>> s1 = Node("sub1", parent=root, edge="")
1683
+ >>> s1a = Node("sub1A", parent=s1, edge=7)
1684
+ >>> s1b = Node("sub1B", parent=s1, edge=8)
1685
+ >>> s1c = Node("sub1C", parent=s1, edge=22)
1686
+ >>> s1ca = Node("sub1Ca", parent=s1c, edge=42)
1687
+
1688
+ .. note:: If the node names are not unqiue, see :any:`UniqueDotExporter`.
1689
+
1690
+ A directed graph:
1691
+
1692
+ >>> from anytree.exporter import DotExporter
1693
+ >>> for line in DotExporter(root):
1694
+ ... print(line)
1695
+ digraph tree {
1696
+ "root";
1697
+ "sub0";
1698
+ "sub0B";
1699
+ "sub0A";
1700
+ "sub1";
1701
+ "sub1A";
1702
+ "sub1B";
1703
+ "sub1C";
1704
+ "sub1Ca";
1705
+ "root" -> "sub0";
1706
+ "root" -> "sub1";
1707
+ "sub0" -> "sub0B";
1708
+ "sub0" -> "sub0A";
1709
+ "sub1" -> "sub1A";
1710
+ "sub1" -> "sub1B";
1711
+ "sub1" -> "sub1C";
1712
+ "sub1C" -> "sub1Ca";
1713
+ }
1714
+
1715
+ The resulting graph:
1716
+
1717
+ .. image:: ../static/dotexporter0.png
1718
+
1719
+ An undirected graph:
1720
+
1721
+ >>> def nodenamefunc(node):
1722
+ ... return '%s:%s' % (node.name, node.depth)
1723
+ >>> def edgeattrfunc(node, child):
1724
+ ... return 'label="%s:%s"' % (node.name, child.name)
1725
+ >>> def edgetypefunc(node, child):
1726
+ ... return '--'
1727
+ >>> from anytree.exporter import DotExporter
1728
+ >>> for line in DotExporter(root, graph="graph",
1729
+ ... nodenamefunc=nodenamefunc,
1730
+ ... nodeattrfunc=lambda node: "shape=box",
1731
+ ... edgeattrfunc=edgeattrfunc,
1732
+ ... edgetypefunc=edgetypefunc):
1733
+ ... print(line)
1734
+ graph tree {
1735
+ "root:0" [shape=box];
1736
+ "sub0:1" [shape=box];
1737
+ "sub0B:2" [shape=box];
1738
+ "sub0A:2" [shape=box];
1739
+ "sub1:1" [shape=box];
1740
+ "sub1A:2" [shape=box];
1741
+ "sub1B:2" [shape=box];
1742
+ "sub1C:2" [shape=box];
1743
+ "sub1Ca:3" [shape=box];
1744
+ "root:0" -- "sub0:1" [label="root:sub0"];
1745
+ "root:0" -- "sub1:1" [label="root:sub1"];
1746
+ "sub0:1" -- "sub0B:2" [label="sub0:sub0B"];
1747
+ "sub0:1" -- "sub0A:2" [label="sub0:sub0A"];
1748
+ "sub1:1" -- "sub1A:2" [label="sub1:sub1A"];
1749
+ "sub1:1" -- "sub1B:2" [label="sub1:sub1B"];
1750
+ "sub1:1" -- "sub1C:2" [label="sub1:sub1C"];
1751
+ "sub1C:2" -- "sub1Ca:3" [label="sub1C:sub1Ca"];
1752
+ }
1753
+
1754
+ The resulting graph:
1755
+
1756
+ .. image:: ../static/dotexporter1.png
1757
+
1758
+ To export custom node implementations or :any:`AnyNode`, please provide a proper `nodenamefunc`:
1759
+
1760
+ >>> from anytree import AnyNode
1761
+ >>> root = AnyNode(id="root")
1762
+ >>> s0 = AnyNode(id="sub0", parent=root)
1763
+ >>> s0b = AnyNode(id="s0b", parent=s0)
1764
+ >>> s0a = AnyNode(id="s0a", parent=s0)
1765
+
1766
+ >>> from anytree.exporter import DotExporter
1767
+ >>> for line in DotExporter(root, nodenamefunc=lambda n: n.id):
1768
+ ... print(line)
1769
+ digraph tree {
1770
+ "root";
1771
+ "sub0";
1772
+ "s0b";
1773
+ "s0a";
1774
+ "root" -> "sub0";
1775
+ "sub0" -> "s0b";
1776
+ "sub0" -> "s0a";
1777
+ }
1778
+ """
1779
+ self.node = node
1780
+ self.graph = graph
1781
+ self.name = name
1782
+ self.options = options
1783
+ self.indent = indent
1784
+ self.nodenamefunc = nodenamefunc
1785
+ self.nodeattrfunc = nodeattrfunc
1786
+ self.edgeattrfunc = edgeattrfunc
1787
+ self.edgetypefunc = edgetypefunc
1788
+ self.maxlevel = maxlevel
1634
1789
  self.include_nodes = include_nodes
1635
- node_name_func = get_unique_node_names_func(root)
1790
+ node_name_func = get_unique_node_names_func(node)
1636
1791
  self.include_node_names = [node_name_func(n) for n in self.include_nodes] if include_nodes else None
1637
- super().__init__(root, **kwargs)
1792
+
1793
+ def __iter__(self):
1794
+ # prepare
1795
+ indent = " " * self.indent
1796
+ nodenamefunc = self.nodenamefunc or self._default_nodenamefunc
1797
+ nodeattrfunc = self.nodeattrfunc or self._default_nodeattrfunc
1798
+ edgeattrfunc = self.edgeattrfunc or self._default_edgeattrfunc
1799
+ edgetypefunc = self.edgetypefunc or self._default_edgetypefunc
1800
+ return self.__iter(indent, nodenamefunc, nodeattrfunc, edgeattrfunc,
1801
+ edgetypefunc)
1802
+
1803
+ @staticmethod
1804
+ def _default_nodenamefunc(node):
1805
+ return node.name
1806
+
1807
+ @staticmethod
1808
+ def _default_nodeattrfunc(node):
1809
+ return None
1810
+
1811
+ @staticmethod
1812
+ def _default_edgeattrfunc(node, child):
1813
+ return None
1814
+
1815
+ @staticmethod
1816
+ def _default_edgetypefunc(node, child):
1817
+ return "->"
1818
+
1819
+ def __iter(self, indent, nodenamefunc, nodeattrfunc, edgeattrfunc, edgetypefunc):
1820
+ yield "{self.graph} {self.name} {{".format(self=self)
1821
+ for option in self.__iter_options(indent):
1822
+ yield option
1823
+ for node in self.__iter_nodes(indent, nodenamefunc, nodeattrfunc):
1824
+ yield node
1825
+ for edge in self.__iter_edges(indent, nodenamefunc, edgeattrfunc, edgetypefunc):
1826
+ yield edge
1827
+ yield "}"
1828
+
1829
+ def __iter_options(self, indent):
1830
+ options = self.options
1831
+ if options:
1832
+ for option in options:
1833
+ yield "%s%s" % (indent, option)
1638
1834
 
1639
1835
  def __iter_nodes(self, indent, nodenamefunc, nodeattrfunc):
1640
1836
  for node in PreOrderIter(self.node, maxlevel=self.maxlevel):
@@ -1653,12 +1849,68 @@ class FilteredDotExporter(DotExporter):
1653
1849
  continue
1654
1850
  for child in node.children:
1655
1851
  childname = nodenamefunc(child)
1852
+ if self.include_nodes is not None and childname not in self.include_node_names:
1853
+ continue
1656
1854
  edgeattr = edgeattrfunc(node, child)
1657
1855
  edgetype = edgetypefunc(node, child)
1658
1856
  edgeattr = " [%s]" % edgeattr if edgeattr is not None else ""
1659
1857
  yield '%s"%s" %s "%s"%s;' % (indent, DotExporter.esc(nodename), edgetype,
1660
1858
  DotExporter.esc(childname), edgeattr)
1661
1859
 
1860
+ def to_dotfile(self, filename):
1861
+ """
1862
+ Write graph to `filename`.
1863
+
1864
+ >>> from anytree import Node
1865
+ >>> root = Node("root")
1866
+ >>> s0 = Node("sub0", parent=root)
1867
+ >>> s0b = Node("sub0B", parent=s0)
1868
+ >>> s0a = Node("sub0A", parent=s0)
1869
+ >>> s1 = Node("sub1", parent=root)
1870
+ >>> s1a = Node("sub1A", parent=s1)
1871
+ >>> s1b = Node("sub1B", parent=s1)
1872
+ >>> s1c = Node("sub1C", parent=s1)
1873
+ >>> s1ca = Node("sub1Ca", parent=s1c)
1874
+
1875
+ >>> from anytree.exporter import DotExporter
1876
+ >>> DotExporter(root).to_dotfile("tree.dot")
1877
+
1878
+ The generated file should be handed over to the `dot` tool from the
1879
+ http://www.graphviz.org/ package::
1880
+
1881
+ $ dot tree.dot -T png -o tree.png
1882
+ """
1883
+ with codecs.open(filename, "w", "utf-8") as file:
1884
+ for line in self:
1885
+ file.write("%s\n" % line)
1886
+
1887
+ def to_picture(self, filename):
1888
+ """
1889
+ Write graph to a temporary file and invoke `dot`.
1890
+
1891
+ The output file type is automatically detected from the file suffix.
1892
+
1893
+ *`graphviz` needs to be installed, before usage of this method.*
1894
+ """
1895
+ fileformat = os.path.splitext(filename)[1][1:]
1896
+ with NamedTemporaryFile("wb", delete=False) as dotfile:
1897
+ dotfilename = dotfile.name
1898
+ for line in self:
1899
+ dotfile.write(("%s\n" % line).encode("utf-8"))
1900
+ dotfile.flush()
1901
+ cmd = ["dot", dotfilename, "-T", fileformat, "-o", filename]
1902
+ check_call(cmd)
1903
+ try:
1904
+ os.remove(dotfilename)
1905
+ except Exception: # pragma: no cover
1906
+ msg = 'Could not remove temporary file %s' % dotfilename
1907
+ logging.getLogger(__name__).warn(msg)
1908
+
1909
+ @staticmethod
1910
+ def esc(value):
1911
+ """Escape Strings."""
1912
+ return _RE_ESC.sub(lambda m: r"\%s" % m.group(0), six.text_type(value))
1913
+
1662
1914
 
1663
1915
  def render_tree(root: Node, use_dot_exporter: bool = False,
1664
1916
  filename: str = "scrdr", only_nodes: List[Node] = None):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ripple_down_rules
3
- Version: 0.6.18
3
+ Version: 0.6.20
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