ara-cli 0.1.9.95__py3-none-any.whl → 0.1.9.96__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.
@@ -1,3 +1,4 @@
1
+ from . import error_handler
1
2
  from ara_cli.classifier import Classifier
2
3
  from ara_cli.file_classifier import FileClassifier
3
4
  from ara_cli.artefact_models.artefact_model import Artefact
@@ -12,8 +13,7 @@ class ArtefactReader:
12
13
  @staticmethod
13
14
  def read_artefact_data(artefact_name, classifier, classified_file_info = None) -> tuple[str, dict[str, str]]:
14
15
  if not Classifier.is_valid_classifier(classifier):
15
- print("Invalid classifier provided. Please provide a valid classifier.")
16
- return None, None
16
+ raise ValueError("Invalid classifier provided. Please provide a valid classifier.")
17
17
 
18
18
  if not classified_file_info:
19
19
  file_classifier = FileClassifier(os)
@@ -74,7 +74,6 @@ class ArtefactReader:
74
74
 
75
75
  @staticmethod
76
76
  def read_artefacts(classified_artefacts=None, file_system=os, tags=None) -> Dict[str, List[Artefact]]:
77
- from ara_cli.artefact_models.artefact_load import artefact_from_content
78
77
 
79
78
  if classified_artefacts is None:
80
79
  file_classifier = FileClassifier(file_system)
@@ -89,7 +88,7 @@ class ArtefactReader:
89
88
  artefact = ArtefactReader.read_artefact(title, artefact_type, classified_artefacts)
90
89
  artefacts[artefact_type].append(artefact)
91
90
  except Exception as e:
92
- print(f"Failed to read {artefact_type} '{title}' with an error: ", e)
91
+ error_handler.report_error(e, f"reading {artefact_type} '{title}'")
93
92
  continue
94
93
  return artefacts
95
94
 
@@ -143,7 +142,7 @@ class ArtefactReader:
143
142
  ArtefactReader._ensure_classifier_key(classifier, artefacts_by_classifier)
144
143
 
145
144
  artefact = ArtefactReader._find_artefact_by_name(
146
- artefact_name,
145
+ artefact_name,
147
146
  classified_artefacts.get(classifier, [])
148
147
  )
149
148
 
ara_cli/chat.py CHANGED
@@ -1,8 +1,8 @@
1
1
  import os
2
2
  import argparse
3
3
  import cmd2
4
+ from . import error_handler
4
5
  from ara_cli.prompt_handler import send_prompt
5
- from ara_cli.file_loaders.markdown_reader import MarkdownReader
6
6
 
7
7
  from ara_cli.file_loaders.document_file_loader import DocumentFileLoader
8
8
  from ara_cli.file_loaders.binary_file_loader import BinaryFileLoader
@@ -17,12 +17,6 @@ load_parser = argparse.ArgumentParser()
17
17
  load_parser.add_argument('file_name', nargs='?', default='', help='File to load')
18
18
  load_parser.add_argument('--load-images', action='store_true', help='Extract and describe images from documents')
19
19
 
20
-
21
- from ara_cli.file_loaders.document_file_loader import DocumentFileLoader
22
- from ara_cli.file_loaders.binary_file_loader import BinaryFileLoader
23
- from ara_cli.file_loaders.text_file_loader import TextFileLoader
24
-
25
-
26
20
  extract_parser = argparse.ArgumentParser()
27
21
  extract_parser.add_argument('-f', '--force', action='store_true', help='Force extraction')
28
22
  extract_parser.add_argument('-w','--write', action='store_true', help='Overwrite existing files without using LLM for merging.')
@@ -32,7 +26,6 @@ load_parser.add_argument('file_name', nargs='?', default='', help='File to load'
32
26
  load_parser.add_argument('--load-images', action='store_true', help='Extract and describe images from documents')
33
27
 
34
28
 
35
-
36
29
  class Chat(cmd2.Cmd):
37
30
  CATEGORY_CHAT_CONTROL = "Chat control commands"
38
31
  CATEGORY_LLM_CONTROL = "Language model controls"
@@ -64,7 +57,7 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
64
57
  ".jpg": "image/jpeg",
65
58
  ".jpeg": "image/jpeg",
66
59
  }
67
-
60
+
68
61
  DOCUMENT_TYPE_EXTENSIONS = [".docx", ".doc", ".odt", ".pdf"]
69
62
 
70
63
  def __init__(
@@ -507,6 +500,13 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
507
500
  self.last_result = True
508
501
  return True
509
502
 
503
+ def onecmd(self, *args, **kwargs):
504
+ try:
505
+ return super().onecmd(*args, **kwargs)
506
+ except Exception as e:
507
+ error_handler.report_error(e)
508
+ return False
509
+
510
510
  def onecmd_plus_hooks(self, line, orig_rl_history_length):
511
511
  # store the full line for use with default()
512
512
  self.full_input = line
@@ -832,8 +832,7 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
832
832
  file_name=self.chat_name,
833
833
  force=args.force,
834
834
  write=args.write,
835
- output=self.poutput,
836
- error_output=self.perror
835
+ output=self.poutput
837
836
  )
838
837
  command.execute()
839
838
 
@@ -919,7 +918,7 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
919
918
 
920
919
  artefact = template_artefact_of_type(''.join(template_name))
921
920
  if not artefact:
922
- return
921
+ raise ValueError(f"No template for '{template_name}' found.")
923
922
  write_content = artefact.serialize()
924
923
  self.add_prompt_tag_if_needed(self.chat_name)
925
924
  with open(self.chat_name, 'a', encoding='utf-8') as chat_file:
@@ -927,7 +926,7 @@ Start chatting (type 'HELP'/'h' for available commands, 'QUIT'/'q' to exit chat
927
926
  print(f"Loaded {template_name} artefact template")
928
927
 
929
928
  def complete_LOAD_TEMPLATE(self, text, line, begidx, endidx):
930
- return self._complete_classifiers(self, text, line, begidx, endidx)
929
+ return self._complete_classifiers(text, line, begidx, endidx)
931
930
 
932
931
  def _complete_classifiers(self, text, line, begidx, endidx):
933
932
  from ara_cli.classifier import Classifier
@@ -3,20 +3,13 @@ from ara_cli.prompt_extractor import extract_responses
3
3
  import os
4
4
 
5
5
  class ExtractCommand(Command):
6
- def __init__(self, file_name, force=False, write=False, output=None, error_output=None):
6
+ def __init__(self, file_name, force=False, write=False, output=None):
7
7
  self.file_name = file_name
8
8
  self.force = force
9
9
  self.write = write
10
10
  self.output = output # Callable for standard output (optional)
11
- self.error_output = error_output # Callable for errors (optional)
12
11
 
13
12
  def execute(self, *args, **kwargs):
14
- try:
15
- extract_responses(self.file_name, True, force=self.force, write=self.write)
16
- if self.output:
17
- self.output("End of extraction")
18
- except Exception as e:
19
- if self.error_output:
20
- self.error_output(f"Extraction failed: {e}")
21
- else:
22
- raise
13
+ extract_responses(self.file_name, True, force=self.force, write=self.write)
14
+ if self.output:
15
+ self.output("End of extraction")
@@ -0,0 +1,134 @@
1
+ import sys
2
+ import traceback
3
+ from typing import Optional
4
+ from enum import Enum
5
+ from functools import wraps
6
+
7
+
8
+ RED = '\033[91m'
9
+ RESET = '\033[0m'
10
+
11
+
12
+ class ErrorLevel(Enum):
13
+ INFO = "INFO"
14
+ WARNING = "WARNING"
15
+ ERROR = "ERROR"
16
+ CRITICAL = "CRITICAL"
17
+
18
+
19
+ class AraError(Exception):
20
+ """Base exception class for ARA CLI errors"""
21
+
22
+ def __init__(
23
+ self, message: str, error_code: int = 1, level: ErrorLevel = ErrorLevel.ERROR
24
+ ):
25
+ self.message = message
26
+ self.error_code = error_code
27
+ self.level = level
28
+ super().__init__(self.message)
29
+
30
+
31
+ class AraValidationError(AraError):
32
+ """Raised when validation fails"""
33
+
34
+ def __init__(self, message: str):
35
+ super().__init__(message, error_code=2, level=ErrorLevel.ERROR)
36
+
37
+
38
+ class AraConfigurationError(AraError):
39
+ """Raised when configuration is invalid"""
40
+
41
+ def __init__(self, message: str):
42
+ super().__init__(message, error_code=4, level=ErrorLevel.ERROR)
43
+
44
+
45
+ class ErrorHandler:
46
+ """Centralized error handler for ARA CLI"""
47
+
48
+ def __init__(self, debug_mode: bool = False):
49
+ self.debug_mode = debug_mode
50
+
51
+ def handle_error(self, error: Exception, context: Optional[str] = None) -> None:
52
+ """Handle any error with standardized output"""
53
+ if isinstance(error, AraError):
54
+ self._handle_ara_error(error, context)
55
+ else:
56
+ self._handle_generic_error(error, context)
57
+
58
+ def _handle_ara_error(self, error: AraError, context: Optional[str] = None) -> None:
59
+ """Handle ARA-specific errors"""
60
+ self._report_ara_error(error, context)
61
+
62
+ sys.exit(error.error_code)
63
+
64
+ def _handle_generic_error(
65
+ self, error: Exception, context: Optional[str] = None
66
+ ) -> None:
67
+ """Handle generic Python errors"""
68
+ self._report_generic_error(error, context)
69
+
70
+ sys.exit(1)
71
+
72
+
73
+ def report_error(self, error: Exception, context: Optional[str] = None) -> None:
74
+ """Report error with standardized formatting but don't exit"""
75
+ if isinstance(error, AraError):
76
+ self._report_ara_error(error, context)
77
+ else:
78
+ self._report_generic_error(error, context)
79
+
80
+
81
+ def _report_ara_error(self, error: AraError, context: Optional[str] = None) -> None:
82
+ """Report ARA-specific errors without exiting"""
83
+ error_prefix = f"[{error.level.value}]"
84
+
85
+ if context:
86
+ print(f"{RED}{error_prefix} {context}: {error.message}{RESET}", file=sys.stderr)
87
+ else:
88
+ print(f"{RED}{error_prefix} {error.message}{RESET}", file=sys.stderr)
89
+
90
+ if self.debug_mode:
91
+ traceback.print_exc()
92
+
93
+
94
+ def _report_generic_error(self, error: Exception, context: Optional[str] = None) -> None:
95
+ """Report generic Python errors without exiting"""
96
+ error_type = type(error).__name__
97
+
98
+ if context:
99
+ print(f"{RED}[ERROR] {context}: {error_type}: {str(error)}{RESET}", file=sys.stderr)
100
+ else:
101
+ print(f"{RED}[ERROR] {error_type}: {str(error)}{RESET}", file=sys.stderr)
102
+
103
+ if self.debug_mode:
104
+ traceback.print_exc()
105
+
106
+
107
+ def validate_and_exit(
108
+ self, condition: bool, message: str, error_code: int = 1
109
+ ) -> None:
110
+ """Validate condition and exit with error if false"""
111
+ if not condition:
112
+ raise AraValidationError(message)
113
+
114
+
115
+ def handle_errors(_func=None, context: Optional[str] = None, error_handler: Optional[ErrorHandler] = None):
116
+ """Decorator to handle errors in action functions"""
117
+
118
+ def decorator(func):
119
+ @wraps(func)
120
+ def wrapper(*args, **kwargs):
121
+ nonlocal error_handler
122
+ if error_handler is None:
123
+ error_handler = ErrorHandler()
124
+
125
+ try:
126
+ return func(*args, **kwargs)
127
+ except Exception as e:
128
+ error_handler.handle_error(e, context or func.__name__)
129
+
130
+ return wrapper
131
+
132
+ if callable(_func):
133
+ return decorator(_func)
134
+ return decorator
@@ -1,3 +1,4 @@
1
+ from . import error_handler
1
2
  from ara_cli.classifier import Classifier
2
3
  from ara_cli.artefact_models.artefact_model import Artefact
3
4
  from ara_cli.artefact_fuzzy_search import find_closest_name_matches
@@ -33,8 +34,8 @@ class FileClassifier:
33
34
  if byte > 127:
34
35
  return True
35
36
  except Exception as e:
36
- # Handle unexpected errors while reading the file in binary mode
37
- print(f"Error while checking if file is binary: {e}")
37
+ error_handler.report_error(e, "checking if file is binary")
38
+ # print(f"Error while checking if file is binary: {e}")
38
39
  return False
39
40
 
40
41
  def read_file_with_fallback(self, file_path):
@@ -17,7 +17,7 @@ def extract_code_blocks_md(markdown_text):
17
17
 
18
18
 
19
19
  def extract_responses(document_path, relative_to_ara_root=False, force=False, write=False):
20
- print(f"Debug: Starting extraction from {document_path}")
20
+ print(f"Starting extraction from '{document_path}'")
21
21
  block_extraction_counter = 0
22
22
 
23
23
  with open(document_path, 'r', encoding='utf-8', errors='replace') as file:
ara_cli/version.py CHANGED
@@ -1,2 +1,2 @@
1
1
  # version.py
2
- __version__ = "0.1.9.95" # fith parameter like .0 for local install test purposes only. official numbers should be 4 digit numbers
2
+ __version__ = "0.1.9.96" # fith parameter like .0 for local install test purposes only. official numbers should be 4 digit numbers
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ara_cli
3
- Version: 0.1.9.95
3
+ Version: 0.1.9.96
4
4
  Summary: Powerful, open source command-line tool for managing, structuring and automating software development artifacts in line with Business-Driven Development (BDD) and AI-assisted processes
5
5
  Description-Content-Type: text/markdown
6
6
  Requires-Dist: litellm
@@ -1,49 +1,50 @@
1
- ara_cli/__init__.py,sha256=CzGZUcf4WQP051xeNziNKQj8oNr-n_lZCW5_cR_WNVw,455
2
- ara_cli/__main__.py,sha256=J5DCDLRZ6UcpYwM1-NkjaLo4PTetcSj2dB4HrrftkUw,2064
3
- ara_cli/ara_command_action.py,sha256=uyMN05ZYffWqN9nwL53MmQ_yHpuxHVqZ_scAMEoD1jw,21516
1
+ ara_cli/__init__.py,sha256=Kozfk9i2DfbDi8GTkXjbqIoIxWXmbDhxb_edRv73oUU,495
2
+ ara_cli/__main__.py,sha256=1GaJ2LJPOfAKZVPaKIkJ0x1L2p8yGMAgckzoRn_6JvA,3474
3
+ ara_cli/ara_command_action.py,sha256=iPDiIaN60TEpVCnOT6Esestu0fNJFzbyhNENQytbkEo,22822
4
4
  ara_cli/ara_command_parser.py,sha256=A1lMc9Gc0EMJt-380PTcv3aKoxbXGfx5gGax-sZqV3I,21020
5
5
  ara_cli/ara_config.py,sha256=VJeage_v-446OtSXIfpazUbetpH7kGNv8Un1lKYx5ZE,9321
6
- ara_cli/artefact_autofix.py,sha256=w6erUYrpPiwtHToiZEfjkDgDDPPSA9zaNc7w2NqrZ2M,20730
7
- ara_cli/artefact_creator.py,sha256=wchIq1w636ui_kRCfNWPffqiIiXqSb49pgTpQj3KzA0,6132
8
- ara_cli/artefact_deleter.py,sha256=Co4wwCH3yW8H9NrOq7_2p5571EeHr0TsfE-H8KqoOfY,1900
9
- ara_cli/artefact_fuzzy_search.py,sha256=iBlDqjZf-_D3VUjFf7ZwkiQbpQDcwRndIU7aG_sRTgE,2668
6
+ ara_cli/artefact_autofix.py,sha256=9j_bh0HGnN6HVT9OGKVp85VgDklpx3XpSc9MxBCldU4,25050
7
+ ara_cli/artefact_creator.py,sha256=fRrDaGZvOqJqDb_DLXqMTed2XfIvQMIHjLgOuHOi3Qg,5973
8
+ ara_cli/artefact_deleter.py,sha256=T1vS2s3k_BW86Sd8FExx8nC3BIL05xE9KZLkeZsZrKM,1891
9
+ ara_cli/artefact_fuzzy_search.py,sha256=XMzbMBOJ2YrgFi566jYNB3XeRAmJh7-zqV2QJYbhtlc,3006
10
10
  ara_cli/artefact_link_updater.py,sha256=nKdxTpDKqWTOAMD8viKmUaklSFGWzJZ8S8E8xW_ADuM,3775
11
11
  ara_cli/artefact_lister.py,sha256=M-ggazAgZ-OLeW9NB48r_sd6zPx0p4hEpeS63qHwI1A,4176
12
- ara_cli/artefact_reader.py,sha256=Pho0_Eqm7kD9CNbVMhKb6mkNM0I3iJiCJXbXmVp1DJU,7827
12
+ ara_cli/artefact_reader.py,sha256=-6E1VhIlh2oJE1Rn8ARcHRc_E9N4uk8cEViKMoywm6E,7753
13
13
  ara_cli/artefact_renamer.py,sha256=8S4QWD19_FGKsKlWojnu_RUOxx0u9rmLugydM4s4VDc,4219
14
14
  ara_cli/artefact_scan.py,sha256=msPCm-vPWOAZ_e_z5GylXxq1MtNlmJ4zvKrsdOFCWF4,4813
15
- ara_cli/chat.py,sha256=i2v-Ctem66sgO-HUV3kvMbk4wfotsc2oNet_i1-wfAI,39901
15
+ ara_cli/chat.py,sha256=SCllSt821naybvF6K4afJEtZvFZq7UO52O4fOm0Ieic,39859
16
16
  ara_cli/classifier.py,sha256=zWskj7rBYdqYBGjksBm46iTgVU5IIf2PZsJr4qeiwVU,1878
17
17
  ara_cli/codefusionretriever.py,sha256=fCHgXdIBRzkVAnapX-KI2NQ44XbrrF4tEQmn5J6clUI,1980
18
18
  ara_cli/codehierachieretriever.py,sha256=Xd3EgEWWhkSf1TmTWtf8X5_YvyE_4B66nRrqarwSiTU,1182
19
19
  ara_cli/commandline_completer.py,sha256=b00Dqb5n7SecpxYIDLxAfYhp8X6e3c8a5qYz6ko0i3E,1192
20
20
  ara_cli/directory_navigator.py,sha256=6QbSAjJrJ5a6Lutol9J4HFgVDMiAQ672ny9TATrh04U,3318
21
- ara_cli/file_classifier.py,sha256=A7wilPtIFm81iMgvqD0PjkOVL_QMUc9TB2w2Z9UcPcM,4001
21
+ ara_cli/error_handler.py,sha256=nNaJSq82f3xiz_QFRKPg5kX_-oI-UoFdRJ2OTj1AR18,4019
22
+ ara_cli/file_classifier.py,sha256=nUcNrhflUydCyCRbXHjEEXYwwwfUm65lYnNEvc86fpM,4026
22
23
  ara_cli/file_lister.py,sha256=0C-j8IzajXo5qlvnuy5WFfe43ALwJ-0JFh2K6Xx2ccw,2332
23
24
  ara_cli/filename_validator.py,sha256=Aw9PL8d5-Ymhp3EY6lDrUBk3cudaNqo1Uw5RzPpI1jA,118
24
25
  ara_cli/global_file_lister.py,sha256=IIrtFoN5KYyJ3jVPanXZJ4UbYZfSdONRwxkZzvmq6-k,2806
25
26
  ara_cli/list_filter.py,sha256=qKGwwQsrWe7L5FbdxEbBYD1bbbi8c-RMypjXqXvLbgs,5291
26
27
  ara_cli/output_suppressor.py,sha256=nwiHaQLwabOjMoJOeUESBnZszGMxrQZfJ3N2OvahX7Y,389
27
28
  ara_cli/prompt_chat.py,sha256=kd_OINDQFit6jN04bb7mzgY259JBbRaTaNp9F-webkc,1346
28
- ara_cli/prompt_extractor.py,sha256=-_17aVYXYH6kPX5FOSb9T8lbEkKPXE6nlHWq1pvO_Og,8423
29
+ ara_cli/prompt_extractor.py,sha256=WloRgfcEdIVq37BpdWAd2X3EMu0bcNN_Wuws1T2YiUg,8418
29
30
  ara_cli/prompt_handler.py,sha256=8a9fcMwE_C6ntbw7UeroNJeU5LxrxEppiUtvYNUTB2U,23292
30
31
  ara_cli/prompt_rag.py,sha256=ydlhe4CUqz0jdzlY7jBbpKaf_5fjMrAZKnriKea3ZAg,7485
31
32
  ara_cli/run_file_lister.py,sha256=XbrrDTJXp1LFGx9Lv91SNsEHZPP-PyEMBF_P4btjbDA,2360
32
33
  ara_cli/tag_extractor.py,sha256=k2yRl7dAMZ4YTARzUke4wgY0oEIOmWkOHGet7nXB6uw,3317
33
34
  ara_cli/template_manager.py,sha256=l2c785YHB7m0e2TjE0CX-nwXrS4v3EiT9qrS5KuatAc,7105
34
35
  ara_cli/update_config_prompt.py,sha256=moqj2Kha7S7fEGzTReU0v2y8UjXC8QfnoiieOQr35C4,5157
35
- ara_cli/version.py,sha256=rYDZfGIzWScBRjMjgeqPAsdSGThurJ7PgpedF2Ekr2U,146
36
+ ara_cli/version.py,sha256=-IPlzWGTvEOC2B1-l8hULGEXt1iWj3_npgirLamZr10,146
36
37
  ara_cli/artefact_models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
37
38
  ara_cli/artefact_models/artefact_data_retrieval.py,sha256=CooXOJBYWSyiViN2xkC8baS8OUaslry3YGVVUeDxRAU,527
38
39
  ara_cli/artefact_models/artefact_load.py,sha256=IXzWxP-Q_j_oDGMno0m-OuXCQ7Vd5c_NctshGr4ROBw,621
39
40
  ara_cli/artefact_models/artefact_mapping.py,sha256=8aD0spBjkJ8toMAmFawc6UTUxB6-tEEViZXv2I-r88Q,1874
40
41
  ara_cli/artefact_models/artefact_model.py,sha256=qSbcrmFWAYgBqcNl9QARI1_uLQJm-TPVgP5q2AEFnjE,15983
41
- ara_cli/artefact_models/artefact_templates.py,sha256=8HNM-TsNvKgTpruOBs751yRDXJypTiJhc1tkWCiYG7s,9830
42
+ ara_cli/artefact_models/artefact_templates.py,sha256=CFa_vIA-cnbZEHuACd24vNJB_7LueQi-8x7ga_AyLKI,9830
42
43
  ara_cli/artefact_models/businessgoal_artefact_model.py,sha256=GYT5S2xEnQHwv-k-lEeX5NMSqA-UEfV3PhNjgPDUJpw,4698
43
44
  ara_cli/artefact_models/capability_artefact_model.py,sha256=SZqHx4O2mj4urn77Stnj4_Jxtlq3-LgBBU9SMkByppI,3079
44
45
  ara_cli/artefact_models/epic_artefact_model.py,sha256=h9pC00ZxCL-t_NMjwTCeOnIJZPa9hhB-R05wr110LXs,5619
45
46
  ara_cli/artefact_models/example_artefact_model.py,sha256=UXrKbaPotg1jwcrVSdCeo-XH4tTD_-U1e3giaBn5_xg,1384
46
- ara_cli/artefact_models/feature_artefact_model.py,sha256=FrR7_xydOmMySAz0QpWgrNFF6UcbFsDj7Ji1R2dc82g,19179
47
+ ara_cli/artefact_models/feature_artefact_model.py,sha256=iUCrdgH_VhRCBVyCQARpl9cWzavC310lKZHWLofsq9s,20256
47
48
  ara_cli/artefact_models/issue_artefact_model.py,sha256=v6CpKnkqiUh6Wch2kkEmyyW49c8ysdy1qz8l1Ft9uJA,2552
48
49
  ara_cli/artefact_models/keyfeature_artefact_model.py,sha256=J9oXLsCAo22AW31D5Z104y02ss0S0O4tPCcd09zYCD0,4066
49
50
  ara_cli/artefact_models/serialize_helper.py,sha256=Wks30wy-UrwJURetydKykLgJkdGRgXFHkDT24vHe5tU,595
@@ -52,7 +53,7 @@ ara_cli/artefact_models/userstory_artefact_model.py,sha256=2awH31ROtm7j4T44Bv4cy
52
53
  ara_cli/artefact_models/vision_artefact_model.py,sha256=frjaUJj-mmIlVHEhzAQztCGs-CtvNu_odSborgztfzo,5251
53
54
  ara_cli/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
54
55
  ara_cli/commands/command.py,sha256=Y_2dNeuxRjbyI3ScXNv55lptSe8Hs_ya78L0nPYNZHA,154
55
- ara_cli/commands/extract_command.py,sha256=qpi2_ac3DyxS7FiOz4GsTtRR4xtpegckUmfXzDOwymM,858
56
+ ara_cli/commands/extract_command.py,sha256=CzUOwDembG587PYbxg5rge4XSfdsuTyOPUvkobkXCIs,573
56
57
  ara_cli/commands/load_command.py,sha256=H3CfeHIL-criDU5oi4BONTSpyzJ4m8DzJ0ZCIiAZFeI,2204
57
58
  ara_cli/commands/load_image_command.py,sha256=g9-PXAYdqx5Ed1PdVo-FIb4CyJGEpRFbgQf9Dxg6DmM,886
58
59
  ara_cli/commands/read_command.py,sha256=bo1BvRWuNKdFqBNN1EWORNrX_yuFAOyBruDUolHq1Vc,3791
@@ -140,20 +141,20 @@ ara_cli/templates/specification_breakdown_files/template.step.md,sha256=nzDRl9Xo
140
141
  ara_cli/templates/specification_breakdown_files/template.technology.exploration.md,sha256=zQyiJcmbUfXdte-5uZwZUpT6ey0zwfZ00P4VwI97jQk,2274
141
142
  ara_cli/templates/specification_breakdown_files/template.technology.md,sha256=bySiksz-8xtq0Nnj4svqe2MgUftWrVkbK9AcrDUE3KY,952
142
143
  tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
143
- tests/test_ara_command_action.py,sha256=JTLqXM9BSMlU33OQgrk_sZnoowFJZKZAx8q-st-wa34,25821
144
+ tests/test_ara_command_action.py,sha256=gLXFAW6K0qCkNKvWvmbshfpJqczvdgBoNGT4rugF7JI,27181
144
145
  tests/test_ara_config.py,sha256=RbVhS0SS1lr_SVopEMT1Fake5a-4rWN8MprgJtgI-FA,15883
145
- tests/test_artefact_autofix.py,sha256=pApZ-N0dW8Ujt-cNLbgvd4bhiIIK8oXb-saLf6QlA-8,25022
146
+ tests/test_artefact_autofix.py,sha256=vcN11CY6XJq97N0php4OW-rPbEMEh_nYFISrg-pN1mE,38332
146
147
  tests/test_artefact_fuzzy_search.py,sha256=5Sh3_l9QK8-WHn6JpGPU1b6h4QEnl2JoMq1Tdp2cj1U,1261
147
148
  tests/test_artefact_link_updater.py,sha256=biqbEp2jCOz8giv72hu2P2hDfeJfJ9OrVGdAv5d9cK4,2191
148
149
  tests/test_artefact_lister.py,sha256=35R13UU-YsX1HOsEN8M2-vIiCUA9RSBm6SwestDaFhE,20388
149
150
  tests/test_artefact_reader.py,sha256=660K-d8ed-j8hulsUB_7baPD2-hhbg9TffUR5yVc4Uo,927
150
151
  tests/test_artefact_renamer.py,sha256=lSnKCCfoFGgKhTdDZrEaeBq1xJAak1QoqH5aSeOe9Ro,3494
151
152
  tests/test_artefact_scan.py,sha256=uNWgrt7ieZ4ogKACsPqzAsh59JF2BhTKSag31hpVrTQ,16887
152
- tests/test_chat.py,sha256=sf4mXmOjXZeaYPNSYXSyfz0b5pZA6Mq7_R3gWjQaJw4,56152
153
+ tests/test_chat.py,sha256=UK1566DikkeXKzslw8h1it3UXqJEGLpxy02_Pch0Tfs,59433
153
154
  tests/test_classifier.py,sha256=grYGPksydNdPsaEBQxYHZTuTdcJWz7VQtikCKA6BNaQ,1920
154
155
  tests/test_directory_navigator.py,sha256=7G0MVrBbtBvbrFUpL0zb_9EkEWi1dulWuHsrQxMJxDY,140
155
- tests/test_file_classifier.py,sha256=kLWPiePu3F5mkVuI_lK_2QlLh2kXD_Mt2K8KZZ1fAnA,10940
156
- tests/test_file_creator.py,sha256=D3G7MbgE0m8JmZihxnTryxLco6iZdbV--2CGc0L20FM,2109
156
+ tests/test_file_classifier.py,sha256=4O1C_iDpGGm35b7aI-HIJd5kkWxFUOrI2n4lEpiDNTM,11855
157
+ tests/test_file_creator.py,sha256=tgBCq6KPv-qMSDhj9AZvQIJABiAqgpFRnEg1fqbVrTI,2013
157
158
  tests/test_file_lister.py,sha256=Q9HwhKKx540EPzTmfzOCnvtAgON0aMmpJE2eOe1J3EA,4324
158
159
  tests/test_global_file_lister.py,sha256=ycvf2YL8q5QSEMwcnQfUdoWnQQ8xTSyEtccAeXwl6QU,5487
159
160
  tests/test_list_filter.py,sha256=fJA3d_SdaOAUkE7jn68MOVS0THXGghy1fye_64Zvo1U,7964
@@ -161,8 +162,8 @@ tests/test_prompt_handler.py,sha256=kW8FU09ho4I5qC-f4G9r4ZgI-NlqdOkTmAazG7FaTrw,
161
162
  tests/test_tag_extractor.py,sha256=nSiAYlTKZ7TLAOtcJpwK5zTWHhFYU0tI5xKnivLc1dU,2712
162
163
  tests/test_template_manager.py,sha256=qliEeYgAEakn8JIqIHa8u0Ht6DY4L3T6DcHBXkjzR4I,4167
163
164
  tests/test_update_config_prompt.py,sha256=xsqj1WTn4BsG5Q2t-sNPfu7EoMURFcS-hfb5VSXUnJc,6765
164
- ara_cli-0.1.9.95.dist-info/METADATA,sha256=ZVJWS_s9Xmdeftrsy6337QTfO_BVESYERmL5r_2tT3s,6789
165
- ara_cli-0.1.9.95.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
166
- ara_cli-0.1.9.95.dist-info/entry_points.txt,sha256=v4h7MzysTgSIDYfEo3oj4Kz_8lzsRa3hq-KJHEcLVX8,45
167
- ara_cli-0.1.9.95.dist-info/top_level.txt,sha256=WM4cLHT5DYUaWzLtRj-gu3yVNFpGQ6lLRI3FMmC-38I,14
168
- ara_cli-0.1.9.95.dist-info/RECORD,,
165
+ ara_cli-0.1.9.96.dist-info/METADATA,sha256=rwUSTke0fhW8QCSyel4M0oASJkfy6AASVOkQMzdPBDo,6789
166
+ ara_cli-0.1.9.96.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
167
+ ara_cli-0.1.9.96.dist-info/entry_points.txt,sha256=v4h7MzysTgSIDYfEo3oj4Kz_8lzsRa3hq-KJHEcLVX8,45
168
+ ara_cli-0.1.9.96.dist-info/top_level.txt,sha256=WM4cLHT5DYUaWzLtRj-gu3yVNFpGQ6lLRI3FMmC-38I,14
169
+ ara_cli-0.1.9.96.dist-info/RECORD,,
@@ -1,5 +1,6 @@
1
1
  import pytest
2
2
  from unittest.mock import patch, MagicMock, call, mock_open
3
+ from ara_cli.error_handler import AraValidationError
3
4
  from ara_cli.ara_command_action import (
4
5
  check_validity,
5
6
  create_action,
@@ -16,6 +17,12 @@ from ara_cli.ara_command_action import (
16
17
  )
17
18
 
18
19
 
20
+ @pytest.fixture
21
+ def mock_handle_errors():
22
+ with patch("ara_cli.ara_command_action.handle_errors", lambda context: (lambda f: f)):
23
+ yield
24
+
25
+
19
26
  @pytest.fixture
20
27
  def mock_dependencies():
21
28
  with patch(
@@ -28,8 +35,10 @@ def mock_dependencies():
28
35
  "ara_cli.template_manager.SpecificationBreakdownAspects"
29
36
  ) as MockSpecificationBreakdownAspects, patch(
30
37
  "ara_cli.artefact_fuzzy_search.find_closest_rule"
31
- ) as mock_find_closest_rule:
32
- yield MockArtefactCreator, MockClassifier, mock_is_valid_filename, MockSpecificationBreakdownAspects, mock_find_closest_rule
38
+ ) as mock_find_closest_rule, patch(
39
+ "ara_cli.artefact_reader.ArtefactReader"
40
+ ) as MockArtefactReader:
41
+ yield MockArtefactCreator, MockClassifier, mock_is_valid_filename, MockSpecificationBreakdownAspects, mock_find_closest_rule, MockArtefactReader
33
42
 
34
43
 
35
44
  @pytest.fixture
@@ -102,65 +111,70 @@ def mock_suggest_close_name_matches():
102
111
  yield mock_suggest_close_name_matches
103
112
 
104
113
 
105
- @pytest.mark.parametrize(
106
- "condition, error_message",
107
- [(True, "This should not be printed"),
108
- (False, "This is a test error message")],
109
- )
110
- def test_check_validity(condition, error_message):
111
- with patch("sys.exit") as mock_exit, patch("builtins.print") as mock_print:
112
- if condition:
113
- check_validity(condition, error_message)
114
- mock_exit.assert_not_called()
115
- mock_print.assert_not_called()
116
- else:
117
- check_validity(condition, error_message)
118
- mock_exit.assert_called_once_with(1)
119
- mock_print.assert_called_once_with(error_message)
114
+ def test_check_validity_with_true_condition():
115
+ """Test that check_validity does nothing when condition is True."""
116
+ # This should not raise any exception
117
+ check_validity(True, "This should not be printed")
120
118
 
121
119
 
122
- @pytest.mark.parametrize(
123
- "classifier_valid, filename_valid",
124
- [(True, True), (False, True), (True, False), (False, False)],
125
- )
126
- def test_create_action_validity_checks(
127
- mock_dependencies, classifier_valid, filename_valid
128
- ):
129
- (
130
- MockArtefactCreator,
131
- MockClassifier,
132
- mock_is_valid_filename,
133
- MockSpecificationBreakdownAspects,
134
- mock_find_closest_rule,
135
- ) = mock_dependencies
120
+ def test_check_validity_with_false_condition():
121
+ """Test that check_validity raises AraValidationError when condition is False."""
122
+ error_message = "This is a test error message"
123
+
124
+ with pytest.raises(AraValidationError, match=error_message):
125
+ check_validity(False, error_message)
126
+
127
+
128
+ def test_check_validity_error_message_content():
129
+ """Test that the raised exception contains the correct error message."""
130
+ error_message = "Custom validation error"
131
+
132
+ with pytest.raises(AraValidationError) as exc_info:
133
+ check_validity(False, error_message)
134
+
135
+ assert str(exc_info.value) == error_message
136
+
137
+
138
+ def setup_create_args_and_mocks(classifier_valid, filename_valid, mock_dependencies):
139
+ (MockArtefactCreator, MockClassifier, mock_is_valid_filename, _, _, MockArtefactReader) = mock_dependencies
136
140
  MockClassifier.is_valid_classifier.return_value = classifier_valid
137
141
  mock_is_valid_filename.return_value = filename_valid
138
- mock_find_closest_rule.return_value = None
142
+ MockArtefactReader.read_artefact.return_value = (None, None)
139
143
 
140
144
  args = MagicMock()
141
145
  args.classifier = "test_classifier"
142
146
  args.parameter = "test_parameter"
147
+ return args
143
148
 
149
+ # Test for valid classifier and filename
150
+ def test_create_action_with_valid_params(mock_handle_errors, mock_dependencies):
151
+ args = setup_create_args_and_mocks(True, True, mock_dependencies)
144
152
  with patch("ara_cli.ara_command_action.check_validity") as mock_check_validity:
145
- if classifier_valid and filename_valid:
146
- create_action(args)
147
- mock_check_validity.assert_any_call(
148
- True, "Invalid classifier provided. Please provide a valid classifier."
149
- )
150
- mock_check_validity.assert_any_call(
151
- True, "Invalid filename provided. Please provide a valid filename."
152
- )
153
- else:
154
- create_action(args)
155
- if not classifier_valid:
156
- mock_check_validity.assert_any_call(
157
- False,
158
- "Invalid classifier provided. Please provide a valid classifier.",
159
- )
160
- if not filename_valid:
161
- mock_check_validity.assert_any_call(
162
- False, "Invalid filename provided. Please provide a valid filename."
163
- )
153
+ create_action(args)
154
+ mock_check_validity.assert_any_call(True, "Invalid classifier provided. Please provide a valid classifier.")
155
+ mock_check_validity.assert_any_call(True, "Invalid filename provided. Please provide a valid filename.")
156
+
157
+ # Test for invalid classifier
158
+ def test_create_action_with_invalid_classifier(mock_handle_errors, mock_dependencies):
159
+ args = setup_create_args_and_mocks(False, True, mock_dependencies)
160
+ with patch("ara_cli.ara_command_action.check_validity") as mock_check_validity:
161
+ create_action(args)
162
+ mock_check_validity.assert_any_call(False, "Invalid classifier provided. Please provide a valid classifier.")
163
+
164
+ # Test for invalid filename
165
+ def test_create_action_with_invalid_filename(mock_handle_errors, mock_dependencies):
166
+ args = setup_create_args_and_mocks(True, False, mock_dependencies)
167
+ with patch("ara_cli.ara_command_action.check_validity") as mock_check_validity:
168
+ create_action(args)
169
+ mock_check_validity.assert_any_call(False, "Invalid filename provided. Please provide a valid filename.")
170
+
171
+ # Test for both invalid classifier and filename
172
+ def test_create_action_with_invalid_classifier_and_filename(mock_handle_errors, mock_dependencies):
173
+ args = setup_create_args_and_mocks(False, False, mock_dependencies)
174
+ with patch("ara_cli.ara_command_action.check_validity") as mock_check_validity:
175
+ create_action(args)
176
+ mock_check_validity.assert_any_call(False, "Invalid classifier provided. Please provide a valid classifier.")
177
+ mock_check_validity.assert_any_call(False, "Invalid filename provided. Please provide a valid filename.")
164
178
 
165
179
 
166
180
  @pytest.mark.parametrize(
@@ -406,7 +420,7 @@ def test_read_status_action(classifier, artefact_name, artefact_exists, status,
406
420
  # Verify behavior
407
421
  if not artefact_exists:
408
422
  # Should suggest close matches when artefact not found
409
- mock_suggest_close_name_matches.assert_called_once_with(artefact_name, all_artefact_names)
423
+ mock_suggest_close_name_matches.assert_called_once_with(artefact_name, all_artefact_names, report_as_error=True)
410
424
  mock_open.assert_not_called()
411
425
  else:
412
426
  # Should open the file and read content