ripple-down-rules 0.4.83__py3-none-any.whl → 0.4.84__py3-none-any.whl

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.
@@ -0,0 +1 @@
1
+ __version__ = "0.4.84"
@@ -1,6 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import json
4
+ import logging
4
5
  from abc import ABC, abstractmethod
5
6
 
6
7
  from typing_extensions import Optional, TYPE_CHECKING, List
@@ -9,7 +10,10 @@ from .datastructures.callable_expression import CallableExpression
9
10
  from .datastructures.enums import PromptFor
10
11
  from .datastructures.dataclasses import CaseQuery
11
12
  from .datastructures.case import show_current_and_corner_cases
12
- from .user_interface.gui import RDRCaseViewer
13
+ try:
14
+ from .user_interface.gui import RDRCaseViewer
15
+ except ImportError as e:
16
+ RDRCaseViewer = None
13
17
  from .user_interface.prompt import UserPrompt
14
18
 
15
19
  if TYPE_CHECKING:
ripple_down_rules/rdr.py CHANGED
@@ -2,13 +2,22 @@ from __future__ import annotations
2
2
 
3
3
  import copyreg
4
4
  import importlib
5
+ import logging
5
6
  import sys
6
7
  from abc import ABC, abstractmethod
7
8
  from copy import copy
8
9
  from io import TextIOWrapper
9
10
  from types import ModuleType
10
11
 
11
- from matplotlib import pyplot as plt
12
+ try:
13
+ from matplotlib import pyplot as plt
14
+ Figure = plt.Figure
15
+ except ImportError as e:
16
+ logging.debug(f"{e}: matplotlib is not installed")
17
+ matplotlib = None
18
+ Figure = None
19
+ plt = None
20
+
12
21
  from sqlalchemy.orm import DeclarativeBase as SQLTable
13
22
  from typing_extensions import List, Optional, Dict, Type, Union, Any, Self, Tuple, Callable, Set
14
23
 
@@ -19,7 +28,10 @@ from .datastructures.enums import MCRDRMode
19
28
  from .experts import Expert, Human
20
29
  from .helpers import is_matching
21
30
  from .rules import Rule, SingleClassRule, MultiClassTopRule, MultiClassStopRule
22
- from .user_interface.gui import RDRCaseViewer
31
+ try:
32
+ from .user_interface.gui import RDRCaseViewer
33
+ except ImportError as e:
34
+ RDRCaseViewer = None
23
35
  from .utils import draw_tree, make_set, copy_case, \
24
36
  SubclassJSONSerializer, make_list, get_type_from_string, \
25
37
  is_conflicting, update_case, get_imports_from_scope, extract_function_source, extract_imports, get_full_class_name
@@ -29,7 +41,7 @@ class RippleDownRules(SubclassJSONSerializer, ABC):
29
41
  """
30
42
  The abstract base class for the ripple down rules classifiers.
31
43
  """
32
- fig: Optional[plt.Figure] = None
44
+ fig: Optional[Figure] = None
33
45
  """
34
46
  The figure to draw the tree on.
35
47
  """
@@ -55,7 +67,7 @@ class RippleDownRules(SubclassJSONSerializer, ABC):
55
67
  :param start_rule: The starting rule for the classifier.
56
68
  """
57
69
  self.start_rule = start_rule
58
- self.fig: Optional[plt.Figure] = None
70
+ self.fig: Optional[Figure] = None
59
71
  self.viewer: Optional[RDRCaseViewer] = viewer
60
72
  if self.viewer is not None:
61
73
  self.viewer.set_save_function(self.save)
@@ -86,6 +98,8 @@ class RippleDownRules(SubclassJSONSerializer, ABC):
86
98
  """
87
99
  targets = []
88
100
  if animate_tree:
101
+ if plt is None:
102
+ raise ImportError("matplotlib is not installed, cannot animate the tree.")
89
103
  plt.ion()
90
104
  i = 0
91
105
  stop_iterating = False
@@ -755,7 +769,7 @@ class GeneralRDR(RippleDownRules):
755
769
  self.start_rules_dict: Dict[str, Union[SingleClassRDR, MultiClassRDR]] \
756
770
  = category_rdr_map if category_rdr_map else {}
757
771
  super(GeneralRDR, self).__init__(**kwargs)
758
- self.all_figs: List[plt.Figure] = [sr.fig for sr in self.start_rules_dict.values()]
772
+ self.all_figs: List[Figure] = [sr.fig for sr in self.start_rules_dict.values()]
759
773
 
760
774
  def add_rdr(self, rdr: Union[SingleClassRDR, MultiClassRDR], case_query: Optional[CaseQuery] = None):
761
775
  """
@@ -0,0 +1,27 @@
1
+ #!/bin/bash
2
+ set -e
3
+ if [ -z "$RDR_EDITOR_PORT" ]; then
4
+ echo "RDR_EDITOR_PORT is not set. Using default port 8080."
5
+ RDR_EDITOR_PORT=8080
6
+ fi
7
+ ADDR="0.0.0.0:$RDR_EDITOR_PORT"
8
+ # DATA_DIR="/root/.local/share/code-server"
9
+ echo "🚀 Starting code-server on $ADDR"
10
+ # Activate your Python virtual environment if exists else ignore
11
+ if [ -z "$RDR_VENV_PATH" ]; then
12
+ echo "No virtual environment found. Skipping activation."
13
+ else
14
+ source "$RDR_VENV_PATH/bin/activate"
15
+ # Set the default Python interpreter for VS Code
16
+ export DEFAULT_PYTHON_PATH=$(which python)
17
+ fi
18
+
19
+ # Start code-server.
20
+ echo "🚀 Starting code-server on $ADDR"
21
+ if [ -z "$CODE_SERVER_USER_DATA_DIR" ]; then
22
+ echo "No user data directory found. Using default"
23
+ code-server --bind-addr $ADDR --auth none "$@"
24
+ else
25
+ echo "Using user data directory: $CODE_SERVER_USER_DATA_DIR"
26
+ code-server --bind-addr $ADDR --user-data-dir $CODE_SERVER_USER_DATA_DIR --auth none "$@"
27
+ fi
@@ -1,23 +1,29 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import inspect
4
- from copy import copy
4
+ import logging
5
5
  from types import MethodType
6
6
 
7
- from PyQt6.QtCore import Qt
8
- from PyQt6.QtGui import QPixmap, QPainter, QPalette
9
- from PyQt6.QtWidgets import (
10
- QWidget, QVBoxLayout, QLabel, QScrollArea,
11
- QSizePolicy, QToolButton, QHBoxLayout, QPushButton, QMainWindow, QGraphicsView, QGraphicsScene, QGraphicsPixmapItem
12
- )
13
- from qtconsole.inprocess import QtInProcessKernelManager
14
- from qtconsole.rich_jupyter_widget import RichJupyterWidget
7
+ try:
8
+ from PyQt6.QtCore import Qt
9
+ from PyQt6.QtGui import QPixmap, QPainter, QPalette
10
+ from PyQt6.QtWidgets import (
11
+ QWidget, QVBoxLayout, QLabel, QScrollArea,
12
+ QSizePolicy, QToolButton, QHBoxLayout, QPushButton, QMainWindow, QGraphicsView, QGraphicsScene, QGraphicsPixmapItem
13
+ )
14
+ from qtconsole.inprocess import QtInProcessKernelManager
15
+ from qtconsole.rich_jupyter_widget import RichJupyterWidget
16
+ except ImportError as e:
17
+ logging.debug("RDRCaseViewer is not available. GUI features will not work. "
18
+ "Make sure you have PyQt6 installed if you want to use the GUI features.")
19
+ raise ImportError("PyQt6 is required for the GUI features. Please install it using 'pip install PyQt6'") from e
20
+
15
21
  from typing_extensions import Optional, Any, List, Dict, Callable
16
22
 
17
23
  from ..datastructures.dataclasses import CaseQuery
18
24
  from ..datastructures.enums import PromptFor
19
25
  from .template_file_creator import TemplateFileCreator
20
- from ..utils import is_iterable, contains_return_statement, encapsulate_user_input
26
+ from ..utils import is_iterable, contains_return_statement, encapsulate_code_lines_into_a_function
21
27
  from .object_diagram import generate_object_graph
22
28
 
23
29
 
@@ -561,28 +567,6 @@ class RDRCaseViewer(QMainWindow):
561
567
  layout.addWidget(item_label)
562
568
 
563
569
 
564
- def encapsulate_code_lines_into_a_function(code_lines: List[str], function_name: str, function_signature: str,
565
- func_doc: str, case_query: CaseQuery) -> str:
566
- """
567
- Encapsulate the given code lines into a function with the specified name, signature, and docstring.
568
-
569
- :param code_lines: The lines of code to include in the user input.
570
- :param function_name: The name of the function to include in the user input.
571
- :param function_signature: The function signature to include in the user input.
572
- :param func_doc: The function docstring to include in the user input.
573
- :param case_query: The case query object.
574
- """
575
- code = '\n'.join(code_lines)
576
- code = encapsulate_user_input(code, function_signature, func_doc)
577
- if case_query.is_function:
578
- args = "**case"
579
- else:
580
- args = "case"
581
- if f"return {function_name}({args})" not in code:
582
- code = code.strip() + f"\nreturn {function_name}({args})"
583
- return code
584
-
585
-
586
570
  class IPythonConsole(RichJupyterWidget):
587
571
  def __init__(self, namespace=None, parent=None):
588
572
  super(IPythonConsole, self).__init__(parent)
@@ -8,9 +8,8 @@ from traitlets.config import Config
8
8
 
9
9
  from ..datastructures.dataclasses import CaseQuery
10
10
  from ..datastructures.enums import PromptFor
11
- from .gui import encapsulate_code_lines_into_a_function
12
11
  from .template_file_creator import TemplateFileCreator
13
- from ..utils import contains_return_statement, extract_dependencies
12
+ from ..utils import contains_return_statement, extract_dependencies, encapsulate_code_lines_into_a_function
14
13
 
15
14
 
16
15
  @magics_class
@@ -1,4 +1,10 @@
1
- import graphviz
1
+ import logging
2
+
3
+ try:
4
+ import graphviz
5
+ except ImportError:
6
+ graphviz = None
7
+ logging.debug("Graphviz is not installed")
2
8
 
3
9
 
4
10
  def is_simple(obj):
@@ -4,8 +4,10 @@ from _ast import AST
4
4
 
5
5
  try:
6
6
  from PyQt6.QtWidgets import QApplication
7
+ from .gui import RDRCaseViewer
7
8
  except ImportError:
8
9
  QApplication = None
10
+ RDRCaseViewer = None
9
11
 
10
12
  from colorama import Fore, Style
11
13
  from pygments import highlight
@@ -16,7 +18,6 @@ from typing_extensions import Optional, Tuple
16
18
  from ..datastructures.callable_expression import CallableExpression, parse_string_to_expression
17
19
  from ..datastructures.dataclasses import CaseQuery
18
20
  from ..datastructures.enums import PromptFor
19
- from .gui import RDRCaseViewer
20
21
  from .ipython_custom_shell import IPythonShell
21
22
  from ..utils import make_list
22
23
 
@@ -16,13 +16,27 @@ from dataclasses import is_dataclass, fields
16
16
  from enum import Enum
17
17
  from textwrap import dedent
18
18
  from types import NoneType
19
+ from typing import List
20
+
21
+ try:
22
+ import matplotlib
23
+ from matplotlib import pyplot as plt
24
+ Figure = plt.Figure
25
+ except ImportError as e:
26
+ matplotlib = None
27
+ plt = None
28
+ Figure = None
29
+ logging.debug(f"{e}: matplotlib is not installed")
30
+
31
+ try:
32
+ import networkx as nx
33
+ except ImportError as e:
34
+ nx = None
35
+ logging.debug(f"{e}: networkx is not installed")
19
36
 
20
- import matplotlib
21
- import networkx as nx
22
37
  import requests
23
38
  from anytree import Node, RenderTree
24
39
  from anytree.exporter import DotExporter
25
- from matplotlib import pyplot as plt
26
40
  from sqlalchemy import MetaData, inspect
27
41
  from sqlalchemy.orm import Mapped, registry, class_mapper, DeclarativeBase as SQLTable, Session
28
42
  from tabulate import tabulate
@@ -1350,7 +1364,7 @@ def render_tree(root: Node, use_dot_exporter: bool = False,
1350
1364
  de.to_picture(f"{filename}{'.png'}")
1351
1365
 
1352
1366
 
1353
- def draw_tree(root: Node, fig: plt.Figure):
1367
+ def draw_tree(root: Node, fig: Figure):
1354
1368
  """
1355
1369
  Draw the tree using matplotlib and networkx.
1356
1370
  """
@@ -1374,3 +1388,25 @@ def draw_tree(root: Node, fig: plt.Figure):
1374
1388
  nx.draw_networkx_edge_labels(graph, pos, edge_labels=nx.get_edge_attributes(graph, 'weight'),
1375
1389
  ax=fig.gca(), rotate=False, clip_on=False)
1376
1390
  plt.pause(0.1)
1391
+
1392
+
1393
+ def encapsulate_code_lines_into_a_function(code_lines: List[str], function_name: str, function_signature: str,
1394
+ func_doc: str, case_query: CaseQuery) -> str:
1395
+ """
1396
+ Encapsulate the given code lines into a function with the specified name, signature, and docstring.
1397
+
1398
+ :param code_lines: The lines of code to include in the user input.
1399
+ :param function_name: The name of the function to include in the user input.
1400
+ :param function_signature: The function signature to include in the user input.
1401
+ :param func_doc: The function docstring to include in the user input.
1402
+ :param case_query: The case query object.
1403
+ """
1404
+ code = '\n'.join(code_lines)
1405
+ code = encapsulate_user_input(code, function_signature, func_doc)
1406
+ if case_query.is_function:
1407
+ args = "**case"
1408
+ else:
1409
+ args = "case"
1410
+ if f"return {function_name}({args})" not in code:
1411
+ code = code.strip() + f"\nreturn {function_name}({args})"
1412
+ return code
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ripple_down_rules
3
- Version: 0.4.83
3
+ Version: 0.4.84
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
@@ -682,21 +682,30 @@ Classifier: Programming Language :: Python :: 3
682
682
  Description-Content-Type: text/markdown
683
683
  License-File: LICENSE
684
684
  Requires-Dist: anytree>=2.8.0
685
- Requires-Dist: pandas>=2.0.3
686
- Requires-Dist: networkx>=3.1
687
685
  Requires-Dist: ordered_set>=4
688
686
  Requires-Dist: pygraphviz>=1.7
689
- Requires-Dist: ucimlrepo>=0.0.7
690
687
  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
688
  Requires-Dist: graphviz
696
689
  Requires-Dist: tabulate
697
690
  Requires-Dist: ipython
698
691
  Requires-Dist: requests
699
692
  Requires-Dist: colorama
693
+ Requires-Dist: pygments
694
+ Provides-Extra: gui
695
+ Requires-Dist: pyqt6; extra == "gui"
696
+ Requires-Dist: qtconsole; extra == "gui"
697
+ Provides-Extra: visualization
698
+ Requires-Dist: matplotlib; extra == "visualization"
699
+ Requires-Dist: networkx; extra == "visualization"
700
+ Provides-Extra: dev
701
+ Requires-Dist: pyqt6; extra == "dev"
702
+ Requires-Dist: qtconsole; extra == "dev"
703
+ Requires-Dist: matplotlib; extra == "dev"
704
+ Requires-Dist: networkx; extra == "dev"
705
+ Requires-Dist: pytest; extra == "dev"
706
+ Requires-Dist: sqlalchemy; extra == "dev"
707
+ Requires-Dist: ucimlrepo>=0.0.7; extra == "dev"
708
+ Requires-Dist: pdbpp; extra == "dev"
700
709
  Dynamic: license-file
701
710
 
702
711
  # Ripple Down Rules (RDR)
@@ -1,25 +1,26 @@
1
- ripple_down_rules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1
+ ripple_down_rules/__init__.py,sha256=zRwAqNXnDyzZDar8uxB-BdzoKCO_yX1Bm6oT55ROH4I,22
2
2
  ripple_down_rules/datasets.py,sha256=fJbZ7V-UUYTu5XVVpFinTbuzN3YePCnUB01L3AyZVM8,6837
3
- ripple_down_rules/experts.py,sha256=dEZKv58sdicDByj0T0bu0q6coIBMce6o4t9gJICQy1k,6556
3
+ ripple_down_rules/experts.py,sha256=RWDR-xxbeFIrUQiMYLEDr_PLQFdpPZ-hOXo4dpeiUpI,6630
4
4
  ripple_down_rules/failures.py,sha256=E6ajDUsw3Blom8eVLbA7d_Qnov2conhtZ0UmpQ9ZtSE,302
5
5
  ripple_down_rules/helpers.py,sha256=TvTJU0BA3dPcAyzvZFvAu7jZqsp8Lu0HAAwvuizlGjg,2018
6
- ripple_down_rules/rdr.py,sha256=HpvRpg_cenoJGzYeF_5xlYriWOb0xKQjpbeDyHJNeRg,45389
6
+ ripple_down_rules/rdr.py,sha256=qELIEEokGTWj-VBZZeEM_TiHxaWrlvaKRt2qShuxfvo,45739
7
7
  ripple_down_rules/rdr_decorators.py,sha256=VdmE0JrE8j89b6Af1R1tLZiKfy3h1VCvhAUefN_FLLQ,6753
8
8
  ripple_down_rules/rules.py,sha256=7NB8qWW7XEB45tmJRYsKJqBG8DN3v02fzAFYmOkX8ow,17458
9
- ripple_down_rules/utils.py,sha256=5dpkujZDj6vjOpl4dCrhAF30xFABwSCleFrioVxgjs8,49375
9
+ ripple_down_rules/start-code-server.sh,sha256=otClk7VmDgBOX2TS_cjws6K0UwvgAUJhoA0ugkPCLqQ,949
10
+ ripple_down_rules/utils.py,sha256=iM2bYRYanuWTnq7dflRar8tMwRxL88B__hWkayGLVz4,50675
10
11
  ripple_down_rules/datastructures/__init__.py,sha256=V2aNgf5C96Y5-IGghra3n9uiefpoIm_QdT7cc_C8cxQ,111
11
12
  ripple_down_rules/datastructures/callable_expression.py,sha256=jA7424_mWPbOoPICW3eLMX0-ypxnsW6gOqxrJ7JpDbE,11610
12
13
  ripple_down_rules/datastructures/case.py,sha256=oC8OSdhXvHE-Zx1IIQlad-fsKzQQqr6MZBW24c-dbeU,15191
13
14
  ripple_down_rules/datastructures/dataclasses.py,sha256=GWnUF4h4zfNHSsyBIz3L9y8sLkrXRv0FK_OxzzLc8L8,8183
14
15
  ripple_down_rules/datastructures/enums.py,sha256=ce7tqS0otfSTNAOwsnXlhsvIn4iW_Y_N3TNebF3YoZs,5700
15
16
  ripple_down_rules/user_interface/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
16
- ripple_down_rules/user_interface/gui.py,sha256=mzkyFs0Z7iS22WpPnCwT7HVQYkB72fy8EifXTTYLEf4,27917
17
- ripple_down_rules/user_interface/ipython_custom_shell.py,sha256=XS3URpfoGCYA__fKOo2AmJ7wQerp7UXKdhdDKiL5gDY,6537
18
- ripple_down_rules/user_interface/object_diagram.py,sha256=84JlEH0nQmtGmP8Su5iRX3ZfqByYHbVwd0BQYYPuckY,4436
19
- ripple_down_rules/user_interface/prompt.py,sha256=9QViZOL8kfwSKXb6A_Fr9hkGGgKg12tdFOizvAN0N-4,8053
17
+ ripple_down_rules/user_interface/gui.py,sha256=u0vsd6arUzvHl9HGTwAb0XF-usiifjdXmTagWpaxT-U,27274
18
+ ripple_down_rules/user_interface/ipython_custom_shell.py,sha256=qRQ0g3rnWy8KVG8jBToJ5u13ofou7umdXaDtX2-_Vvc,6521
19
+ ripple_down_rules/user_interface/object_diagram.py,sha256=tsB6iuLNEbHxp5lR2WjyejjWbnAX_nHF9xS8jNPOQVk,4548
20
+ ripple_down_rules/user_interface/prompt.py,sha256=AkkltdDIaioN43lkRKDPKSjJcmdSSGZDMYz7AL7X9lE,8082
20
21
  ripple_down_rules/user_interface/template_file_creator.py,sha256=-0L0jGW1VTrL0aer67mIdjFr3gKjXKA6zRZ5IXbY5vY,13959
21
- ripple_down_rules-0.4.83.dist-info/licenses/LICENSE,sha256=ixuiBLtpoK3iv89l7ylKkg9rs2GzF9ukPH7ynZYzK5s,35148
22
- ripple_down_rules-0.4.83.dist-info/METADATA,sha256=GE3bwcxMmoJd2cOUoGOTD2w3DnQiJzsF6xR64aUuEEo,43218
23
- ripple_down_rules-0.4.83.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
24
- ripple_down_rules-0.4.83.dist-info/top_level.txt,sha256=VeoLhEhyK46M1OHwoPbCQLI1EifLjChqGzhQ6WEUqeM,18
25
- ripple_down_rules-0.4.83.dist-info/RECORD,,
22
+ ripple_down_rules-0.4.84.dist-info/licenses/LICENSE,sha256=ixuiBLtpoK3iv89l7ylKkg9rs2GzF9ukPH7ynZYzK5s,35148
23
+ ripple_down_rules-0.4.84.dist-info/METADATA,sha256=OhD2lKh1beytOqH6r0pAdkyGE67TfH8nC46r1n24sAM,43622
24
+ ripple_down_rules-0.4.84.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
25
+ ripple_down_rules-0.4.84.dist-info/top_level.txt,sha256=VeoLhEhyK46M1OHwoPbCQLI1EifLjChqGzhQ6WEUqeM,18
26
+ ripple_down_rules-0.4.84.dist-info/RECORD,,