ripple-down-rules 0.4.4__tar.gz → 0.4.8__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.
- {ripple_down_rules-0.4.4 → ripple_down_rules-0.4.8}/PKG-INFO +17 -3
- {ripple_down_rules-0.4.4 → ripple_down_rules-0.4.8}/pyproject.toml +19 -6
- {ripple_down_rules-0.4.4 → ripple_down_rules-0.4.8}/src/ripple_down_rules/rules.py +2 -2
- {ripple_down_rules-0.4.4 → ripple_down_rules-0.4.8}/src/ripple_down_rules/user_interface/gui.py +4 -1
- {ripple_down_rules-0.4.4 → ripple_down_rules-0.4.8}/src/ripple_down_rules/user_interface/ipython_custom_shell.py +4 -1
- {ripple_down_rules-0.4.4 → ripple_down_rules-0.4.8}/src/ripple_down_rules/user_interface/prompt.py +2 -2
- {ripple_down_rules-0.4.4 → ripple_down_rules-0.4.8}/src/ripple_down_rules/user_interface/template_file_creator.py +59 -31
- {ripple_down_rules-0.4.4 → ripple_down_rules-0.4.8}/src/ripple_down_rules/utils.py +9 -6
- {ripple_down_rules-0.4.4 → ripple_down_rules-0.4.8}/src/ripple_down_rules.egg-info/PKG-INFO +17 -3
- {ripple_down_rules-0.4.4 → ripple_down_rules-0.4.8}/src/ripple_down_rules.egg-info/SOURCES.txt +2 -0
- ripple_down_rules-0.4.8/src/ripple_down_rules.egg-info/requires.txt +16 -0
- ripple_down_rules-0.4.8/test/test_template_file_creator.py +57 -0
- {ripple_down_rules-0.4.4 → ripple_down_rules-0.4.8}/LICENSE +0 -0
- {ripple_down_rules-0.4.4 → ripple_down_rules-0.4.8}/README.md +0 -0
- {ripple_down_rules-0.4.4 → ripple_down_rules-0.4.8}/setup.cfg +0 -0
- {ripple_down_rules-0.4.4 → ripple_down_rules-0.4.8}/src/ripple_down_rules/__init__.py +0 -0
- {ripple_down_rules-0.4.4 → ripple_down_rules-0.4.8}/src/ripple_down_rules/datasets.py +0 -0
- {ripple_down_rules-0.4.4 → ripple_down_rules-0.4.8}/src/ripple_down_rules/datastructures/__init__.py +0 -0
- {ripple_down_rules-0.4.4 → ripple_down_rules-0.4.8}/src/ripple_down_rules/datastructures/callable_expression.py +0 -0
- {ripple_down_rules-0.4.4 → ripple_down_rules-0.4.8}/src/ripple_down_rules/datastructures/case.py +0 -0
- {ripple_down_rules-0.4.4 → ripple_down_rules-0.4.8}/src/ripple_down_rules/datastructures/dataclasses.py +0 -0
- {ripple_down_rules-0.4.4 → ripple_down_rules-0.4.8}/src/ripple_down_rules/datastructures/enums.py +0 -0
- {ripple_down_rules-0.4.4 → ripple_down_rules-0.4.8}/src/ripple_down_rules/experts.py +0 -0
- {ripple_down_rules-0.4.4 → ripple_down_rules-0.4.8}/src/ripple_down_rules/failures.py +0 -0
- {ripple_down_rules-0.4.4 → ripple_down_rules-0.4.8}/src/ripple_down_rules/helpers.py +0 -0
- {ripple_down_rules-0.4.4 → ripple_down_rules-0.4.8}/src/ripple_down_rules/rdr.py +0 -0
- {ripple_down_rules-0.4.4 → ripple_down_rules-0.4.8}/src/ripple_down_rules/rdr_decorators.py +0 -0
- {ripple_down_rules-0.4.4 → ripple_down_rules-0.4.8}/src/ripple_down_rules/user_interface/__init__.py +0 -0
- {ripple_down_rules-0.4.4 → ripple_down_rules-0.4.8}/src/ripple_down_rules/user_interface/object_diagram.py +0 -0
- {ripple_down_rules-0.4.4 → ripple_down_rules-0.4.8}/src/ripple_down_rules.egg-info/dependency_links.txt +0 -0
- {ripple_down_rules-0.4.4 → ripple_down_rules-0.4.8}/src/ripple_down_rules.egg-info/top_level.txt +0 -0
- {ripple_down_rules-0.4.4 → ripple_down_rules-0.4.8}/test/test_json_serialization.py +0 -0
- {ripple_down_rules-0.4.4 → ripple_down_rules-0.4.8}/test/test_object_diagram.py +0 -0
- {ripple_down_rules-0.4.4 → ripple_down_rules-0.4.8}/test/test_on_mutagenic.py +0 -0
- {ripple_down_rules-0.4.4 → ripple_down_rules-0.4.8}/test/test_rdr.py +0 -0
- {ripple_down_rules-0.4.4 → ripple_down_rules-0.4.8}/test/test_rdr_alchemy.py +0 -0
- {ripple_down_rules-0.4.4 → ripple_down_rules-0.4.8}/test/test_rdr_decorators.py +0 -0
- {ripple_down_rules-0.4.4 → ripple_down_rules-0.4.8}/test/test_rdr_world.py +0 -0
- {ripple_down_rules-0.4.4 → ripple_down_rules-0.4.8}/test/test_relational_rdr.py +0 -0
- {ripple_down_rules-0.4.4 → ripple_down_rules-0.4.8}/test/test_relational_rdr_alchemy.py +0 -0
- {ripple_down_rules-0.4.4 → ripple_down_rules-0.4.8}/test/test_sql_model.py +0 -0
- {ripple_down_rules-0.4.4 → ripple_down_rules-0.4.8}/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.4.
|
3
|
+
Version: 0.4.8
|
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
|
@@ -677,12 +677,26 @@ License: GNU GENERAL PUBLIC LICENSE
|
|
677
677
|
the library. If this is what you want to do, use the GNU Lesser General
|
678
678
|
Public License instead of this License. But first, please read
|
679
679
|
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
680
|
-
Project-URL: Homepage, https://github.com/AbdelrhmanBassiouny/ripple_down_rules
|
681
680
|
Keywords: robotics,knowledge,reasoning,representation
|
682
681
|
Classifier: Programming Language :: Python :: 3
|
683
|
-
Requires-Python: >=3.10
|
684
682
|
Description-Content-Type: text/markdown
|
685
683
|
License-File: LICENSE
|
684
|
+
Requires-Dist: anytree>=2.8.0
|
685
|
+
Requires-Dist: pandas>=2.0.3
|
686
|
+
Requires-Dist: networkx>=3.1
|
687
|
+
Requires-Dist: ordered_set>=4
|
688
|
+
Requires-Dist: pygraphviz>=1.7
|
689
|
+
Requires-Dist: ucimlrepo>=0.0.7
|
690
|
+
Requires-Dist: typing-extensions>=4.12.2
|
691
|
+
Requires-Dist: matplotlib>=3.7.5
|
692
|
+
Requires-Dist: sqlalchemy
|
693
|
+
Requires-Dist: pyqt6
|
694
|
+
Requires-Dist: qtconsole
|
695
|
+
Requires-Dist: graphviz
|
696
|
+
Requires-Dist: tabulate
|
697
|
+
Requires-Dist: ipython
|
698
|
+
Requires-Dist: requests
|
699
|
+
Requires-Dist: colorama
|
686
700
|
Dynamic: license-file
|
687
701
|
|
688
702
|
# Ripple Down Rules (RDR)
|
@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
|
|
6
6
|
|
7
7
|
[project]
|
8
8
|
name = "ripple_down_rules"
|
9
|
-
version = "0.4.
|
9
|
+
version = "0.4.8"
|
10
10
|
description = "Implements the various versions of Ripple Down Rules (RDR) for knowledge representation and reasoning."
|
11
11
|
readme = "README.md"
|
12
12
|
authors = [{ name = "Abdelrhman Bassiouny", email = "abassiou@uni-bremen.de" }]
|
@@ -15,8 +15,21 @@ classifiers = [
|
|
15
15
|
"Programming Language :: Python :: 3",
|
16
16
|
]
|
17
17
|
keywords = ["robotics", "knowledge", "reasoning", "representation"]
|
18
|
-
dependencies = [
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
18
|
+
dependencies = [
|
19
|
+
"anytree>=2.8.0",
|
20
|
+
"pandas>=2.0.3",
|
21
|
+
"networkx>=3.1",
|
22
|
+
"ordered_set>=4",
|
23
|
+
"pygraphviz>=1.7",
|
24
|
+
"ucimlrepo>=0.0.7",
|
25
|
+
"typing-extensions>=4.12.2",
|
26
|
+
"matplotlib>=3.7.5",
|
27
|
+
"sqlalchemy",
|
28
|
+
"pyqt6",
|
29
|
+
"qtconsole",
|
30
|
+
"graphviz",
|
31
|
+
"tabulate",
|
32
|
+
"ipython",
|
33
|
+
"requests",
|
34
|
+
"colorama",
|
35
|
+
]
|
@@ -1,11 +1,11 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
+
import logging
|
3
4
|
import re
|
4
5
|
from abc import ABC, abstractmethod
|
5
6
|
from uuid import uuid4
|
6
7
|
|
7
8
|
from anytree import NodeMixin
|
8
|
-
from rospy import logwarn, logdebug
|
9
9
|
from sqlalchemy.orm import DeclarativeBase as SQLTable
|
10
10
|
from typing_extensions import List, Optional, Self, Union, Dict, Any, Tuple
|
11
11
|
|
@@ -164,7 +164,7 @@ class Rule(NodeMixin, SubclassJSONSerializer, ABC):
|
|
164
164
|
try:
|
165
165
|
corner_case = Case.from_json(data["corner_case"])
|
166
166
|
except Exception as e:
|
167
|
-
|
167
|
+
logging.debug("Failed to load corner case from json, setting it to None.")
|
168
168
|
corner_case = None
|
169
169
|
loaded_rule = cls(conditions=CallableExpression.from_json(data["conditions"]),
|
170
170
|
conclusion=CallableExpression.from_json(data["conclusion"]),
|
{ripple_down_rules-0.4.4 → ripple_down_rules-0.4.8}/src/ripple_down_rules/user_interface/gui.py
RENAMED
@@ -475,7 +475,10 @@ class RDRCaseViewer(QMainWindow):
|
|
475
475
|
def _load(self):
|
476
476
|
if not self.template_file_creator:
|
477
477
|
return
|
478
|
-
self.code_lines = self.template_file_creator.load(
|
478
|
+
self.code_lines, updates = self.template_file_creator.load(self.template_file_creator.temp_file_path,
|
479
|
+
self.template_file_creator.func_name,
|
480
|
+
self.template_file_creator.print_func)
|
481
|
+
self.ipython_console.kernel.shell.user_ns.update(updates)
|
479
482
|
if self.code_lines is not None:
|
480
483
|
self.user_input = encapsulate_code_lines_into_a_function(
|
481
484
|
self.code_lines, self.template_file_creator.func_name,
|
@@ -30,7 +30,10 @@ class MyMagics(Magics):
|
|
30
30
|
|
31
31
|
@line_magic
|
32
32
|
def load(self, line):
|
33
|
-
self.all_code_lines = self.rule_editor.load(
|
33
|
+
self.all_code_lines, updates = self.rule_editor.load(self.rule_editor.temp_file_path,
|
34
|
+
self.rule_editor.func_name,
|
35
|
+
self.rule_editor.print_func)
|
36
|
+
self.shell.user_ns.update(updates)
|
34
37
|
|
35
38
|
@line_magic
|
36
39
|
def help(self, line):
|
{ripple_down_rules-0.4.4 → ripple_down_rules-0.4.8}/src/ripple_down_rules/user_interface/prompt.py
RENAMED
@@ -134,14 +134,14 @@ class UserPrompt:
|
|
134
134
|
"""
|
135
135
|
while True:
|
136
136
|
if user_input is None:
|
137
|
-
if
|
137
|
+
if self.viewer is None:
|
138
138
|
shell = IPythonShell() if shell is None else shell
|
139
139
|
shell.run()
|
140
140
|
user_input = shell.user_input
|
141
141
|
else:
|
142
142
|
app = QApplication.instance()
|
143
143
|
if app is None:
|
144
|
-
|
144
|
+
raise RuntimeError("QApplication instance is None. Please run the application first.")
|
145
145
|
self.viewer.show()
|
146
146
|
app.exec()
|
147
147
|
user_input = self.viewer.user_input
|
@@ -9,13 +9,13 @@ from textwrap import indent, dedent
|
|
9
9
|
|
10
10
|
from colorama import Fore, Style
|
11
11
|
from ipykernel.inprocess.ipkernel import InProcessInteractiveShell
|
12
|
-
from typing_extensions import Optional, Type, List, Callable
|
12
|
+
from typing_extensions import Optional, Type, List, Callable, Tuple, Dict
|
13
13
|
|
14
14
|
from ..datastructures.case import Case
|
15
15
|
from ..datastructures.dataclasses import CaseQuery
|
16
16
|
from ..datastructures.enums import Editor, PromptFor
|
17
17
|
from ..utils import str_to_snake_case, get_imports_from_scope, make_list, typing_hint_to_str, \
|
18
|
-
get_imports_from_types, extract_function_source
|
18
|
+
get_imports_from_types, extract_function_source, extract_imports
|
19
19
|
|
20
20
|
|
21
21
|
def detect_available_editor() -> Optional[Editor]:
|
@@ -49,6 +49,9 @@ def start_code_server(workspace):
|
|
49
49
|
stderr=subprocess.PIPE, text=True)
|
50
50
|
|
51
51
|
|
52
|
+
FunctionData = Tuple[Optional[List[str]], Optional[Dict[str, Callable]]]
|
53
|
+
|
54
|
+
|
52
55
|
class TemplateFileCreator:
|
53
56
|
"""
|
54
57
|
A class to create a rule template file for a given case and prompt for the user to edit it.
|
@@ -71,15 +74,15 @@ class TemplateFileCreator:
|
|
71
74
|
"""
|
72
75
|
|
73
76
|
def __init__(self, shell: InProcessInteractiveShell, case_query: CaseQuery, prompt_for: PromptFor,
|
74
|
-
code_to_modify: Optional[str] = None, print_func:
|
75
|
-
self.print_func = print_func
|
77
|
+
code_to_modify: Optional[str] = None, print_func: Callable[[str], None] = print):
|
78
|
+
self.print_func = print_func
|
76
79
|
self.shell = shell
|
77
80
|
self.code_to_modify = code_to_modify
|
78
81
|
self.prompt_for = prompt_for
|
79
82
|
self.case_query = case_query
|
80
83
|
self.output_type = self.get_output_type()
|
81
84
|
self.user_edit_line = 0
|
82
|
-
self.func_name: str = self.get_func_name()
|
85
|
+
self.func_name: str = self.get_func_name(self.prompt_for, self.case_query)
|
83
86
|
self.func_doc: str = self.get_func_doc()
|
84
87
|
self.function_signature: str = self.get_function_signature()
|
85
88
|
self.editor: Optional[Editor] = detect_available_editor()
|
@@ -146,7 +149,7 @@ class TemplateFileCreator:
|
|
146
149
|
|
147
150
|
def get_function_signature(self) -> str:
|
148
151
|
if self.func_name is None:
|
149
|
-
self.func_name = self.get_func_name()
|
152
|
+
self.func_name = self.get_func_name(self.prompt_for, self.case_query)
|
150
153
|
output_type_hint = self.get_output_type_hint()
|
151
154
|
func_args = self.get_func_args()
|
152
155
|
return f"def {self.func_name}({func_args}){output_type_hint}:"
|
@@ -228,25 +231,40 @@ class TemplateFileCreator:
|
|
228
231
|
imports = set(imports)
|
229
232
|
return '\n'.join(imports)
|
230
233
|
|
234
|
+
@staticmethod
|
235
|
+
def get_core_attribute_types(case_query: CaseQuery) -> List[Type]:
|
236
|
+
"""
|
237
|
+
Get the core attribute types of the case query.
|
238
|
+
|
239
|
+
:return: A list of core attribute types.
|
240
|
+
"""
|
241
|
+
attr_types = [t for t in case_query.core_attribute_type if t.__module__ != "builtins" and t is not None
|
242
|
+
and t is not type(None)]
|
243
|
+
return attr_types
|
244
|
+
|
231
245
|
def get_func_doc(self) -> Optional[str]:
|
232
246
|
"""
|
233
247
|
:return: A string containing the function docstring.
|
234
248
|
"""
|
249
|
+
type_data = f" of type {' or '.join(map(lambda c: c.__name__, self.get_core_attribute_types(self.case_query)))}"
|
235
250
|
if self.prompt_for == PromptFor.Conditions:
|
236
251
|
return (f"Get conditions on whether it's possible to conclude a value"
|
237
|
-
f" for {self.case_query.name}")
|
252
|
+
f" for {self.case_query.name} {type_data}.")
|
238
253
|
else:
|
239
|
-
return f"Get possible value(s) for {self.case_query.name}"
|
254
|
+
return f"Get possible value(s) for {self.case_query.name} {type_data}."
|
240
255
|
|
241
|
-
|
256
|
+
@staticmethod
|
257
|
+
def get_func_name(prompt_for, case_query) -> Optional[str]:
|
242
258
|
func_name = ""
|
243
|
-
if
|
244
|
-
func_name = f"{
|
245
|
-
case_name =
|
246
|
-
if
|
259
|
+
if prompt_for == PromptFor.Conditions:
|
260
|
+
func_name = f"{prompt_for.value.lower()}_for_"
|
261
|
+
case_name = case_query.name.replace(".", "_")
|
262
|
+
if case_query.is_function:
|
247
263
|
# convert any CamelCase word into snake_case by adding _ before each capital letter
|
248
|
-
case_name = case_name.replace(f"_{
|
264
|
+
case_name = case_name.replace(f"_{case_query.attribute_name}", "")
|
249
265
|
func_name += case_name
|
266
|
+
func_name += f"_of_type_{'_or_'.join(map(lambda c: c.__name__,
|
267
|
+
TemplateFileCreator.get_core_attribute_types(case_query)))}"
|
250
268
|
return str_to_snake_case(func_name)
|
251
269
|
|
252
270
|
@cached_property
|
@@ -259,33 +277,43 @@ class TemplateFileCreator:
|
|
259
277
|
case = self.case_query.scope['case']
|
260
278
|
return case._obj_type if isinstance(case, Case) else type(case)
|
261
279
|
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
280
|
+
@staticmethod
|
281
|
+
def load(file_path: str, func_name: str, print_func: Callable = print) -> FunctionData:
|
282
|
+
"""
|
283
|
+
Load the function from the given file path.
|
284
|
+
|
285
|
+
:param file_path: The path to the file to load.
|
286
|
+
:param func_name: The name of the function to load.
|
287
|
+
:param print_func: The function to use for printing messages.
|
288
|
+
:return: A tuple containing the function source code and the function object as a dictionary
|
289
|
+
with the function name as the key and the function object as the value.
|
290
|
+
"""
|
291
|
+
if not file_path:
|
292
|
+
print_func(f"{Fore.RED}ERROR:: No file to load. Run %edit first.{Style.RESET_ALL}")
|
293
|
+
return None, None
|
266
294
|
|
267
|
-
with open(
|
295
|
+
with open(file_path, 'r') as f:
|
268
296
|
source = f.read()
|
269
297
|
|
270
298
|
tree = ast.parse(source)
|
271
299
|
updates = {}
|
272
300
|
for node in tree.body:
|
273
|
-
if isinstance(node, ast.FunctionDef) and node.name ==
|
301
|
+
if isinstance(node, ast.FunctionDef) and node.name == func_name:
|
274
302
|
exec_globals = {}
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
303
|
+
scope = extract_imports(tree=tree)
|
304
|
+
exec(source, scope, exec_globals)
|
305
|
+
user_function = exec_globals[func_name]
|
306
|
+
updates[func_name] = user_function
|
307
|
+
print_func(f"{Fore.BLUE}Loaded `{func_name}` function into user namespace.{Style.RESET_ALL}")
|
279
308
|
break
|
280
309
|
if updates:
|
281
|
-
|
282
|
-
|
283
|
-
[
|
284
|
-
|
285
|
-
return self.all_code_lines
|
310
|
+
all_code_lines = extract_function_source(file_path,
|
311
|
+
[func_name],
|
312
|
+
join_lines=False)[func_name]
|
313
|
+
return all_code_lines, updates
|
286
314
|
else:
|
287
|
-
|
288
|
-
return None
|
315
|
+
print_func(f"{Fore.RED}ERROR:: Function `{func_name}` not found.{Style.RESET_ALL}")
|
316
|
+
return None, None
|
289
317
|
|
290
318
|
def __del__(self):
|
291
319
|
if hasattr(self, 'process') and self.process is not None and self.process.poll() is None:
|
@@ -14,6 +14,7 @@ from collections import UserDict
|
|
14
14
|
from copy import deepcopy, copy
|
15
15
|
from dataclasses import is_dataclass, fields
|
16
16
|
from enum import Enum
|
17
|
+
from textwrap import dedent
|
17
18
|
from types import NoneType
|
18
19
|
|
19
20
|
import matplotlib
|
@@ -22,7 +23,6 @@ import requests
|
|
22
23
|
from anytree import Node, RenderTree
|
23
24
|
from anytree.exporter import DotExporter
|
24
25
|
from matplotlib import pyplot as plt
|
25
|
-
from rospy import logwarn
|
26
26
|
from sqlalchemy import MetaData, inspect
|
27
27
|
from sqlalchemy.orm import Mapped, registry, class_mapper, DeclarativeBase as SQLTable, Session
|
28
28
|
from tabulate import tabulate
|
@@ -106,9 +106,12 @@ def get_imports_from_scope(scope: Dict[str, Any]) -> List[str]:
|
|
106
106
|
return imports
|
107
107
|
|
108
108
|
|
109
|
-
def extract_imports(file_path):
|
110
|
-
|
111
|
-
|
109
|
+
def extract_imports(file_path: Optional[str] = None, tree: Optional[ast.AST] = None) -> Dict[str, Any]:
|
110
|
+
if tree is None:
|
111
|
+
if file_path is None:
|
112
|
+
raise ValueError("Either file_path or tree must be provided")
|
113
|
+
with open(file_path, "r") as f:
|
114
|
+
tree = ast.parse(f.read(), filename=file_path)
|
112
115
|
|
113
116
|
scope = {}
|
114
117
|
|
@@ -130,7 +133,7 @@ def extract_imports(file_path):
|
|
130
133
|
module = importlib.import_module(module_name)
|
131
134
|
scope[asname] = getattr(module, name)
|
132
135
|
except (ImportError, AttributeError) as e:
|
133
|
-
|
136
|
+
logging.warning(f"Could not import {module_name}: {e} while extracting imports from {file_path}")
|
134
137
|
|
135
138
|
return scope
|
136
139
|
|
@@ -168,7 +171,7 @@ def extract_function_source(file_path: str,
|
|
168
171
|
if not include_signature:
|
169
172
|
func_lines = func_lines[1:]
|
170
173
|
line_numbers.append((node.lineno, node.end_lineno))
|
171
|
-
functions_source[node.name] = "\n".join(func_lines) if join_lines else func_lines
|
174
|
+
functions_source[node.name] = dedent("\n".join(func_lines)) if join_lines else func_lines
|
172
175
|
if len(functions_source) == len(function_names):
|
173
176
|
break
|
174
177
|
if len(functions_source) != len(function_names):
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: ripple_down_rules
|
3
|
-
Version: 0.4.
|
3
|
+
Version: 0.4.8
|
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
|
@@ -677,12 +677,26 @@ License: GNU GENERAL PUBLIC LICENSE
|
|
677
677
|
the library. If this is what you want to do, use the GNU Lesser General
|
678
678
|
Public License instead of this License. But first, please read
|
679
679
|
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
680
|
-
Project-URL: Homepage, https://github.com/AbdelrhmanBassiouny/ripple_down_rules
|
681
680
|
Keywords: robotics,knowledge,reasoning,representation
|
682
681
|
Classifier: Programming Language :: Python :: 3
|
683
|
-
Requires-Python: >=3.10
|
684
682
|
Description-Content-Type: text/markdown
|
685
683
|
License-File: LICENSE
|
684
|
+
Requires-Dist: anytree>=2.8.0
|
685
|
+
Requires-Dist: pandas>=2.0.3
|
686
|
+
Requires-Dist: networkx>=3.1
|
687
|
+
Requires-Dist: ordered_set>=4
|
688
|
+
Requires-Dist: pygraphviz>=1.7
|
689
|
+
Requires-Dist: ucimlrepo>=0.0.7
|
690
|
+
Requires-Dist: typing-extensions>=4.12.2
|
691
|
+
Requires-Dist: matplotlib>=3.7.5
|
692
|
+
Requires-Dist: sqlalchemy
|
693
|
+
Requires-Dist: pyqt6
|
694
|
+
Requires-Dist: qtconsole
|
695
|
+
Requires-Dist: graphviz
|
696
|
+
Requires-Dist: tabulate
|
697
|
+
Requires-Dist: ipython
|
698
|
+
Requires-Dist: requests
|
699
|
+
Requires-Dist: colorama
|
686
700
|
Dynamic: license-file
|
687
701
|
|
688
702
|
# Ripple Down Rules (RDR)
|
{ripple_down_rules-0.4.4 → ripple_down_rules-0.4.8}/src/ripple_down_rules.egg-info/SOURCES.txt
RENAMED
@@ -13,6 +13,7 @@ src/ripple_down_rules/utils.py
|
|
13
13
|
src/ripple_down_rules.egg-info/PKG-INFO
|
14
14
|
src/ripple_down_rules.egg-info/SOURCES.txt
|
15
15
|
src/ripple_down_rules.egg-info/dependency_links.txt
|
16
|
+
src/ripple_down_rules.egg-info/requires.txt
|
16
17
|
src/ripple_down_rules.egg-info/top_level.txt
|
17
18
|
src/ripple_down_rules/datastructures/__init__.py
|
18
19
|
src/ripple_down_rules/datastructures/callable_expression.py
|
@@ -35,4 +36,5 @@ test/test_rdr_world.py
|
|
35
36
|
test/test_relational_rdr.py
|
36
37
|
test/test_relational_rdr_alchemy.py
|
37
38
|
test/test_sql_model.py
|
39
|
+
test/test_template_file_creator.py
|
38
40
|
test/test_utils.py
|
@@ -0,0 +1,57 @@
|
|
1
|
+
import os
|
2
|
+
from textwrap import dedent
|
3
|
+
|
4
|
+
from ripple_down_rules.datastructures.dataclasses import CaseQuery
|
5
|
+
from ripple_down_rules.datastructures.enums import PromptFor
|
6
|
+
from ripple_down_rules.user_interface.template_file_creator import TemplateFileCreator
|
7
|
+
from test_rdr_world import World, Handle, Container
|
8
|
+
|
9
|
+
|
10
|
+
|
11
|
+
def test_func_name_with_one_type():
|
12
|
+
# Test the function name
|
13
|
+
world = World()
|
14
|
+
case_query: CaseQuery = CaseQuery(world, "views", (Handle,), False)
|
15
|
+
|
16
|
+
func_name = TemplateFileCreator.get_func_name(PromptFor.Conclusion, case_query)
|
17
|
+
assert func_name == "world_views_of_type_handle"
|
18
|
+
|
19
|
+
func_name = TemplateFileCreator.get_func_name(PromptFor.Conditions, case_query)
|
20
|
+
assert func_name == "conditions_for_world_views_of_type_handle"
|
21
|
+
|
22
|
+
def test_func_name_with_two_type():
|
23
|
+
# Test the function name
|
24
|
+
world = World()
|
25
|
+
case_query: CaseQuery = CaseQuery(world, "views", (Handle, Container), False)
|
26
|
+
|
27
|
+
func_name = TemplateFileCreator.get_func_name(PromptFor.Conclusion, case_query)
|
28
|
+
assert func_name == "world_views_of_type_handle_or_container"
|
29
|
+
|
30
|
+
func_name = TemplateFileCreator.get_func_name(PromptFor.Conditions, case_query)
|
31
|
+
assert func_name == "conditions_for_world_views_of_type_handle_or_container"
|
32
|
+
|
33
|
+
def test_func_name_with_not_needed_types():
|
34
|
+
# Test the function name
|
35
|
+
world = World()
|
36
|
+
case_query: CaseQuery = CaseQuery(world, "views", (Handle, list, bool, type(None)), False)
|
37
|
+
|
38
|
+
func_name = TemplateFileCreator.get_func_name(PromptFor.Conclusion, case_query)
|
39
|
+
assert func_name == "world_views_of_type_handle"
|
40
|
+
|
41
|
+
func_name = TemplateFileCreator.get_func_name(PromptFor.Conditions, case_query)
|
42
|
+
assert func_name == "conditions_for_world_views_of_type_handle"
|
43
|
+
|
44
|
+
def test_load():
|
45
|
+
# Test the load function
|
46
|
+
world = World()
|
47
|
+
imports = "from test_rdr_world import World\n\n\n"
|
48
|
+
func_code = "def test_func(case):\n return case"
|
49
|
+
source_code = f"{imports}{func_code}\n"
|
50
|
+
source_code = dedent(source_code)
|
51
|
+
with open("test.py", "w") as f:
|
52
|
+
f.write(source_code)
|
53
|
+
code_lines, updates = TemplateFileCreator.load("test.py", "test_func")
|
54
|
+
assert code_lines == func_code.splitlines()
|
55
|
+
assert list(updates.keys()) == ["test_func"]
|
56
|
+
assert updates["test_func"](world) == world
|
57
|
+
os.remove("test.py")
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{ripple_down_rules-0.4.4 → ripple_down_rules-0.4.8}/src/ripple_down_rules/datastructures/__init__.py
RENAMED
File without changes
|
File without changes
|
{ripple_down_rules-0.4.4 → ripple_down_rules-0.4.8}/src/ripple_down_rules/datastructures/case.py
RENAMED
File without changes
|
File without changes
|
{ripple_down_rules-0.4.4 → ripple_down_rules-0.4.8}/src/ripple_down_rules/datastructures/enums.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{ripple_down_rules-0.4.4 → ripple_down_rules-0.4.8}/src/ripple_down_rules/user_interface/__init__.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
{ripple_down_rules-0.4.4 → ripple_down_rules-0.4.8}/src/ripple_down_rules.egg-info/top_level.txt
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|