ara-cli 0.1.9.94__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.
Files changed (40) hide show
  1. ara_cli/__init__.py +18 -1
  2. ara_cli/__main__.py +57 -11
  3. ara_cli/ara_command_action.py +31 -19
  4. ara_cli/ara_config.py +17 -2
  5. ara_cli/artefact_autofix.py +171 -23
  6. ara_cli/artefact_creator.py +5 -8
  7. ara_cli/artefact_deleter.py +2 -4
  8. ara_cli/artefact_fuzzy_search.py +13 -6
  9. ara_cli/artefact_models/artefact_templates.py +3 -3
  10. ara_cli/artefact_models/feature_artefact_model.py +25 -0
  11. ara_cli/artefact_reader.py +4 -5
  12. ara_cli/chat.py +79 -37
  13. ara_cli/commands/extract_command.py +4 -11
  14. ara_cli/error_handler.py +134 -0
  15. ara_cli/file_classifier.py +3 -2
  16. ara_cli/file_loaders/document_readers.py +233 -0
  17. ara_cli/file_loaders/file_loaders.py +123 -0
  18. ara_cli/file_loaders/image_processor.py +89 -0
  19. ara_cli/file_loaders/markdown_reader.py +75 -0
  20. ara_cli/file_loaders/text_file_loader.py +9 -11
  21. ara_cli/global_file_lister.py +61 -0
  22. ara_cli/prompt_extractor.py +1 -1
  23. ara_cli/prompt_handler.py +24 -4
  24. ara_cli/template_manager.py +14 -4
  25. ara_cli/update_config_prompt.py +7 -1
  26. ara_cli/version.py +1 -1
  27. {ara_cli-0.1.9.94.dist-info → ara_cli-0.1.9.96.dist-info}/METADATA +2 -1
  28. {ara_cli-0.1.9.94.dist-info → ara_cli-0.1.9.96.dist-info}/RECORD +40 -33
  29. tests/test_ara_command_action.py +66 -52
  30. tests/test_ara_config.py +28 -0
  31. tests/test_artefact_autofix.py +361 -5
  32. tests/test_chat.py +105 -36
  33. tests/test_file_classifier.py +23 -0
  34. tests/test_file_creator.py +3 -5
  35. tests/test_global_file_lister.py +131 -0
  36. tests/test_prompt_handler.py +26 -1
  37. tests/test_template_manager.py +5 -4
  38. {ara_cli-0.1.9.94.dist-info → ara_cli-0.1.9.96.dist-info}/WHEEL +0 -0
  39. {ara_cli-0.1.9.94.dist-info → ara_cli-0.1.9.96.dist-info}/entry_points.txt +0 -0
  40. {ara_cli-0.1.9.94.dist-info → ara_cli-0.1.9.96.dist-info}/top_level.txt +0 -0
ara_cli/prompt_handler.py CHANGED
@@ -256,6 +256,8 @@ def initialize_prompt_templates(classifier, parameter):
256
256
  # Mark the relevant artefact in the givens list
257
257
  generate_config_prompt_givens_file(prompt_data_path, "config.prompt_givens.md", artefact_to_mark=f"{parameter}.{classifier}")
258
258
 
259
+ generate_config_prompt_global_givens_file(prompt_data_path, "config.prompt_global_givens.md")
260
+
259
261
 
260
262
  def write_template_files_to_config(template_type, config_file, base_template_path):
261
263
  template_path = os.path.join(base_template_path, template_type)
@@ -383,10 +385,16 @@ def extract_and_load_markdown_files(md_prompt_file_path):
383
385
 
384
386
 
385
387
  def load_givens(file_path):
386
- content = "### GIVENS\n\n"
388
+ content = ""
387
389
  image_data_list = []
388
390
  markdown_items = extract_and_load_markdown_files(file_path)
389
391
 
392
+ # Only proceed and add the header if there are marked items to load.
393
+ if not markdown_items:
394
+ return "", []
395
+
396
+ content = "### GIVENS\n\n"
397
+
390
398
  for item in markdown_items:
391
399
  if item.lower().endswith(('.png', '.jpeg', '.jpg')):
392
400
  with open(item, "rb") as image_file:
@@ -449,7 +457,7 @@ def collect_file_content_by_extension(prompt_data_path, extensions):
449
457
  files = find_files_with_endings(prompt_data_path, [ext])
450
458
  for file_name in files:
451
459
  file_path = join(prompt_data_path, file_name)
452
- if ext == ".prompt_givens.md":
460
+ if ext in [".prompt_givens.md", ".prompt_global_givens.md"]:
453
461
  givens, image_data = load_givens(file_path)
454
462
  combined_content += givens
455
463
  image_data_list.extend(image_data)
@@ -494,7 +502,7 @@ def create_and_send_custom_prompt(classifier, parameter):
494
502
  prompt_data_path = f"ara/{sub_directory}/{parameter}.data/prompt.data"
495
503
  prompt_file_path_markdown = join(prompt_data_path, f"{classifier}.prompt.md")
496
504
 
497
- extensions = [".blueprint.md", ".rules.md", ".prompt_givens.md", ".intention.md", ".commands.md"]
505
+ extensions = [".blueprint.md", ".rules.md", ".prompt_givens.md", ".prompt_global_givens.md", ".intention.md", ".commands.md"]
498
506
  combined_content_markdown, image_data_list = collect_file_content_by_extension(prompt_data_path, extensions)
499
507
 
500
508
  with open(prompt_file_path_markdown, 'w', encoding='utf-8') as file:
@@ -561,4 +569,16 @@ def generate_config_prompt_givens_file(prompt_data_path, config_prompt_givens_na
561
569
 
562
570
  # Write the updated listing back to the file
563
571
  with open(config_prompt_givens_path, 'w', encoding='utf-8') as file:
564
- file.write("".join(updated_listing))
572
+ file.write("".join(updated_listing))
573
+
574
+ def generate_config_prompt_global_givens_file(prompt_data_path, config_prompt_givens_name, artefact_to_mark=None):
575
+ from ara_cli.global_file_lister import generate_global_markdown_listing
576
+ config_prompt_givens_path = os.path.join(prompt_data_path, config_prompt_givens_name)
577
+ config = ConfigManager.get_config()
578
+
579
+ if not hasattr(config, 'global_dirs') or not config.global_dirs:
580
+ return
581
+
582
+ dir_list = [path for d in config.global_dirs for path in d.values()]
583
+ print(f"used {dir_list} for global prompt givens file listing with absolute paths")
584
+ generate_global_markdown_listing(dir_list, config.ara_prompt_given_list_includes, config_prompt_givens_path)
@@ -129,6 +129,7 @@ class SpecificationBreakdownAspects:
129
129
  if aspect not in self.VALID_ASPECTS:
130
130
  raise ValueError(f"{aspect} does not exist. Please choose one of the {self.VALID_ASPECTS} list.")
131
131
 
132
+
132
133
  def create(self, artefact_name='artefact_name', classifier='classifier', aspect='specification_breakdown_aspect'):
133
134
  original_directory = os.getcwd()
134
135
  navigator = DirectoryNavigator()
@@ -139,8 +140,17 @@ class SpecificationBreakdownAspects:
139
140
  data_dir = self.file_manager.get_data_directory_path(artefact_name, classifier)
140
141
  self.file_manager.create_directory(artefact_file_path, data_dir)
141
142
  self.file_manager.copy_aspect_templates_to_directory(aspect, print_relative_to=original_directory)
143
+
142
144
  if (aspect == "step"):
143
- steps = self.file_manager.generate_behave_steps(artefact_name)
144
- self.file_manager.save_behave_steps_to_file(artefact_name, steps)
145
-
146
- os.chdir(original_directory)
145
+ # Instead of generating from behave command, read from the template file
146
+ template_file_path = f"{aspect}.md"
147
+ try:
148
+ with open(template_file_path, 'r', encoding='utf-8') as file:
149
+ steps_content = file.read()
150
+ self.file_manager.save_behave_steps_to_file(artefact_name, steps_content)
151
+ except FileNotFoundError:
152
+ # Fallback to the original behavior if template doesn't exist
153
+ steps = self.file_manager.generate_behave_steps(artefact_name)
154
+ self.file_manager.save_behave_steps_to_file(artefact_name, steps)
155
+
156
+ os.chdir(original_directory)
@@ -103,6 +103,7 @@ def handle_existing_file(file_path, tmp_file_path, generate_file_func, automatic
103
103
 
104
104
 
105
105
  def update_artefact_config_prompt_files(classifier, param, automatic_update=False):
106
+ from ara_cli.prompt_handler import generate_config_prompt_global_givens_file
106
107
  sub_directory = Classifier.get_sub_directory(classifier)
107
108
  artefact_data_path = os.path.join("ara", sub_directory, f"{param}.data")
108
109
  prompt_data_path = os.path.join(artefact_data_path, "prompt.data")
@@ -111,13 +112,18 @@ def update_artefact_config_prompt_files(classifier, param, automatic_update=Fals
111
112
 
112
113
  givens_file_name = "config.prompt_givens.md"
113
114
  givens_tmp_file_name = "config.prompt_givens_tmp.md"
115
+ global_givens_file_name = "config.prompt_global_givens.md"
116
+ global_givens_tmp_file_name = "config.prompt_global_givens_tmp.md"
114
117
  template_file_name = "config.prompt_templates.md"
115
118
  template_tmp_file_name = "config.prompt_templates_tmp.md"
116
119
 
117
120
  prompt_config_givens = os.path.join(prompt_data_path, givens_file_name)
118
121
  prompt_config_givens_tmp = os.path.join(prompt_data_path, givens_tmp_file_name)
122
+ prompt_config_global_givens = os.path.join(prompt_data_path, global_givens_file_name)
123
+ prompt_config_global_givens_tmp = os.path.join(prompt_data_path, global_givens_tmp_file_name)
119
124
  prompt_config_templates = os.path.join(prompt_data_path, template_file_name)
120
125
  prompt_config_templates_tmp = os.path.join(prompt_data_path, template_tmp_file_name)
121
126
 
122
127
  handle_existing_file(prompt_config_givens, prompt_config_givens_tmp, generate_config_prompt_givens_file, automatic_update)
123
- handle_existing_file(prompt_config_templates, prompt_config_templates_tmp, generate_config_prompt_template_file, automatic_update)
128
+ handle_existing_file(prompt_config_global_givens, prompt_config_global_givens_tmp, generate_config_prompt_global_givens_file, automatic_update)
129
+ handle_existing_file(prompt_config_templates, prompt_config_templates_tmp, generate_config_prompt_template_file, automatic_update)
ara_cli/version.py CHANGED
@@ -1,2 +1,2 @@
1
1
  # version.py
2
- __version__ = "0.1.9.94" # 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.94
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
@@ -13,6 +13,7 @@ Requires-Dist: json-repair
13
13
  Requires-Dist: argparse
14
14
  Requires-Dist: argcomplete
15
15
  Requires-Dist: cmd2>=2.5
16
+ Requires-Dist: charset-normalizer
16
17
  Requires-Dist: pydantic
17
18
  Requires-Dist: pydantic_ai
18
19
  Requires-Dist: python-docx
@@ -1,48 +1,50 @@
1
- ara_cli/__init__.py,sha256=oieeo07y5FLq0tmPzWZdp65j6tN8NOucSjSzrJw8qrQ,203
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
- ara_cli/ara_config.py,sha256=5uBo_flNgZSk7B9lmyfvzWyxfIQzb13LbieCpJfdZJI,8765
6
- ara_cli/artefact_autofix.py,sha256=WVTiIR-jo4YKmmz4eS3qTFvl45W1YKwAk1XSuz9QX10,20015
7
- ara_cli/artefact_creator.py,sha256=0Ory6cB-Ahkw-BDNb8QHnTbp_OHGABdkb9bhwcEdcIc,6063
8
- ara_cli/artefact_deleter.py,sha256=Co4wwCH3yW8H9NrOq7_2p5571EeHr0TsfE-H8KqoOfY,1900
9
- ara_cli/artefact_fuzzy_search.py,sha256=iBlDqjZf-_D3VUjFf7ZwkiQbpQDcwRndIU7aG_sRTgE,2668
5
+ ara_cli/ara_config.py,sha256=VJeage_v-446OtSXIfpazUbetpH7kGNv8Un1lKYx5ZE,9321
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=t17TCmx9xvKj5wrnUOJBqjWoSjEVOFrVd8RivChVX50,37980
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
25
+ ara_cli/global_file_lister.py,sha256=IIrtFoN5KYyJ3jVPanXZJ4UbYZfSdONRwxkZzvmq6-k,2806
24
26
  ara_cli/list_filter.py,sha256=qKGwwQsrWe7L5FbdxEbBYD1bbbi8c-RMypjXqXvLbgs,5291
25
27
  ara_cli/output_suppressor.py,sha256=nwiHaQLwabOjMoJOeUESBnZszGMxrQZfJ3N2OvahX7Y,389
26
28
  ara_cli/prompt_chat.py,sha256=kd_OINDQFit6jN04bb7mzgY259JBbRaTaNp9F-webkc,1346
27
- ara_cli/prompt_extractor.py,sha256=-_17aVYXYH6kPX5FOSb9T8lbEkKPXE6nlHWq1pvO_Og,8423
28
- ara_cli/prompt_handler.py,sha256=6yfiMFNHGHANREAsjT8dv9jKxBKeazPkF7xQQI4l6vQ,22312
29
+ ara_cli/prompt_extractor.py,sha256=WloRgfcEdIVq37BpdWAd2X3EMu0bcNN_Wuws1T2YiUg,8418
30
+ ara_cli/prompt_handler.py,sha256=8a9fcMwE_C6ntbw7UeroNJeU5LxrxEppiUtvYNUTB2U,23292
29
31
  ara_cli/prompt_rag.py,sha256=ydlhe4CUqz0jdzlY7jBbpKaf_5fjMrAZKnriKea3ZAg,7485
30
32
  ara_cli/run_file_lister.py,sha256=XbrrDTJXp1LFGx9Lv91SNsEHZPP-PyEMBF_P4btjbDA,2360
31
33
  ara_cli/tag_extractor.py,sha256=k2yRl7dAMZ4YTARzUke4wgY0oEIOmWkOHGet7nXB6uw,3317
32
- ara_cli/template_manager.py,sha256=YwrN6AYPpl6ZrW8BVQpVXx8yTRf-oNpJUIKeg4NAggs,6606
33
- ara_cli/update_config_prompt.py,sha256=Oy9vNTw6UhDohyTEfSKkqE5ifEMPlmWNYkKHgUrK_pY,4607
34
- ara_cli/version.py,sha256=MWb524qaDHLrSJsHhOq7o0m78CPLFil9qeyel6kPW-A,146
34
+ ara_cli/template_manager.py,sha256=l2c785YHB7m0e2TjE0CX-nwXrS4v3EiT9qrS5KuatAc,7105
35
+ ara_cli/update_config_prompt.py,sha256=moqj2Kha7S7fEGzTReU0v2y8UjXC8QfnoiieOQr35C4,5157
36
+ ara_cli/version.py,sha256=-IPlzWGTvEOC2B1-l8hULGEXt1iWj3_npgirLamZr10,146
35
37
  ara_cli/artefact_models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
36
38
  ara_cli/artefact_models/artefact_data_retrieval.py,sha256=CooXOJBYWSyiViN2xkC8baS8OUaslry3YGVVUeDxRAU,527
37
39
  ara_cli/artefact_models/artefact_load.py,sha256=IXzWxP-Q_j_oDGMno0m-OuXCQ7Vd5c_NctshGr4ROBw,621
38
40
  ara_cli/artefact_models/artefact_mapping.py,sha256=8aD0spBjkJ8toMAmFawc6UTUxB6-tEEViZXv2I-r88Q,1874
39
41
  ara_cli/artefact_models/artefact_model.py,sha256=qSbcrmFWAYgBqcNl9QARI1_uLQJm-TPVgP5q2AEFnjE,15983
40
- 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
41
43
  ara_cli/artefact_models/businessgoal_artefact_model.py,sha256=GYT5S2xEnQHwv-k-lEeX5NMSqA-UEfV3PhNjgPDUJpw,4698
42
44
  ara_cli/artefact_models/capability_artefact_model.py,sha256=SZqHx4O2mj4urn77Stnj4_Jxtlq3-LgBBU9SMkByppI,3079
43
45
  ara_cli/artefact_models/epic_artefact_model.py,sha256=h9pC00ZxCL-t_NMjwTCeOnIJZPa9hhB-R05wr110LXs,5619
44
46
  ara_cli/artefact_models/example_artefact_model.py,sha256=UXrKbaPotg1jwcrVSdCeo-XH4tTD_-U1e3giaBn5_xg,1384
45
- 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
46
48
  ara_cli/artefact_models/issue_artefact_model.py,sha256=v6CpKnkqiUh6Wch2kkEmyyW49c8ysdy1qz8l1Ft9uJA,2552
47
49
  ara_cli/artefact_models/keyfeature_artefact_model.py,sha256=J9oXLsCAo22AW31D5Z104y02ss0S0O4tPCcd09zYCD0,4066
48
50
  ara_cli/artefact_models/serialize_helper.py,sha256=Wks30wy-UrwJURetydKykLgJkdGRgXFHkDT24vHe5tU,595
@@ -51,7 +53,7 @@ ara_cli/artefact_models/userstory_artefact_model.py,sha256=2awH31ROtm7j4T44Bv4cy
51
53
  ara_cli/artefact_models/vision_artefact_model.py,sha256=frjaUJj-mmIlVHEhzAQztCGs-CtvNu_odSborgztfzo,5251
52
54
  ara_cli/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
53
55
  ara_cli/commands/command.py,sha256=Y_2dNeuxRjbyI3ScXNv55lptSe8Hs_ya78L0nPYNZHA,154
54
- ara_cli/commands/extract_command.py,sha256=qpi2_ac3DyxS7FiOz4GsTtRR4xtpegckUmfXzDOwymM,858
56
+ ara_cli/commands/extract_command.py,sha256=CzUOwDembG587PYbxg5rge4XSfdsuTyOPUvkobkXCIs,573
55
57
  ara_cli/commands/load_command.py,sha256=H3CfeHIL-criDU5oi4BONTSpyzJ4m8DzJ0ZCIiAZFeI,2204
56
58
  ara_cli/commands/load_image_command.py,sha256=g9-PXAYdqx5Ed1PdVo-FIb4CyJGEpRFbgQf9Dxg6DmM,886
57
59
  ara_cli/commands/read_command.py,sha256=bo1BvRWuNKdFqBNN1EWORNrX_yuFAOyBruDUolHq1Vc,3791
@@ -59,8 +61,12 @@ ara_cli/file_loaders/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hS
59
61
  ara_cli/file_loaders/binary_file_loader.py,sha256=1HHH1Nk4lEM83CTnf4z9wYz6rMLgpxydFoRcSgkBHmQ,940
60
62
  ara_cli/file_loaders/document_file_loader.py,sha256=VxGFChYyM9K-e6eOCK3yk5jQuEXgz01Mh_NoA6CA_RM,1017
61
63
  ara_cli/file_loaders/document_reader.py,sha256=SD9_5-XJ6homKUes6o8GWcG--X63UslfAosPbrJZQvo,7721
64
+ ara_cli/file_loaders/document_readers.py,sha256=aG7xrUJwLxWpuFTYlvxzDqoS00Idpvwzt865L0OuQcA,8124
62
65
  ara_cli/file_loaders/file_loader.py,sha256=bc1BrMG4pEtwsZLm3Ct53YsMPgnbSaEvZEd8isRDYRY,1711
63
- ara_cli/file_loaders/text_file_loader.py,sha256=x_ZqnOUb2glpdxziceWCBX8oEBk7JZhAluLRRvBjuQs,6626
66
+ ara_cli/file_loaders/file_loaders.py,sha256=9QqArTRDmcUUar58JEr-qnpiAtH9ySP-MV9bvooQNpI,4290
67
+ ara_cli/file_loaders/image_processor.py,sha256=laPThh-i0-obYyS_linQTMcTUwuxMxrSjedGRYb8cIA,3462
68
+ ara_cli/file_loaders/markdown_reader.py,sha256=R-hvvc9Sj9pWwENqJ0j6wrW0eN1tUqEKWcK2YUFsvsU,2542
69
+ ara_cli/file_loaders/text_file_loader.py,sha256=62U59RkWgAML0U0P-sUeFsK51mJM8Fu54gGlnmMwYpY,6804
64
70
  ara_cli/templates/agile.artefacts,sha256=nTA8dp98HWKAD-0qhmNpVYIfkVGoJshZqMJGnphiOsE,7932
65
71
  ara_cli/templates/template.businessgoal.prompt_log.md,sha256=xF6bkgj_GqAAqHxJWJiQNt11mEuSGemIqoZ2wOo6dI0,214
66
72
  ara_cli/templates/template.capability.prompt_log.md,sha256=eO8EzrHgb2vYJ-DP1jGzAfDlMo8nY75hZDfhh0s40uQ,208
@@ -135,28 +141,29 @@ ara_cli/templates/specification_breakdown_files/template.step.md,sha256=nzDRl9Xo
135
141
  ara_cli/templates/specification_breakdown_files/template.technology.exploration.md,sha256=zQyiJcmbUfXdte-5uZwZUpT6ey0zwfZ00P4VwI97jQk,2274
136
142
  ara_cli/templates/specification_breakdown_files/template.technology.md,sha256=bySiksz-8xtq0Nnj4svqe2MgUftWrVkbK9AcrDUE3KY,952
137
143
  tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
138
- tests/test_ara_command_action.py,sha256=JTLqXM9BSMlU33OQgrk_sZnoowFJZKZAx8q-st-wa34,25821
139
- tests/test_ara_config.py,sha256=H5GwDbab0GMSa6IbHdruzmbsHy5Ia0xX0uteJdfZ9Rg,14277
140
- tests/test_artefact_autofix.py,sha256=pApZ-N0dW8Ujt-cNLbgvd4bhiIIK8oXb-saLf6QlA-8,25022
144
+ tests/test_ara_command_action.py,sha256=gLXFAW6K0qCkNKvWvmbshfpJqczvdgBoNGT4rugF7JI,27181
145
+ tests/test_ara_config.py,sha256=RbVhS0SS1lr_SVopEMT1Fake5a-4rWN8MprgJtgI-FA,15883
146
+ tests/test_artefact_autofix.py,sha256=vcN11CY6XJq97N0php4OW-rPbEMEh_nYFISrg-pN1mE,38332
141
147
  tests/test_artefact_fuzzy_search.py,sha256=5Sh3_l9QK8-WHn6JpGPU1b6h4QEnl2JoMq1Tdp2cj1U,1261
142
148
  tests/test_artefact_link_updater.py,sha256=biqbEp2jCOz8giv72hu2P2hDfeJfJ9OrVGdAv5d9cK4,2191
143
149
  tests/test_artefact_lister.py,sha256=35R13UU-YsX1HOsEN8M2-vIiCUA9RSBm6SwestDaFhE,20388
144
150
  tests/test_artefact_reader.py,sha256=660K-d8ed-j8hulsUB_7baPD2-hhbg9TffUR5yVc4Uo,927
145
151
  tests/test_artefact_renamer.py,sha256=lSnKCCfoFGgKhTdDZrEaeBq1xJAak1QoqH5aSeOe9Ro,3494
146
152
  tests/test_artefact_scan.py,sha256=uNWgrt7ieZ4ogKACsPqzAsh59JF2BhTKSag31hpVrTQ,16887
147
- tests/test_chat.py,sha256=cCNIuYiSGoNtjgjyFiTvkMHJgCmMNXQhpawNc23-fmM,57037
153
+ tests/test_chat.py,sha256=UK1566DikkeXKzslw8h1it3UXqJEGLpxy02_Pch0Tfs,59433
148
154
  tests/test_classifier.py,sha256=grYGPksydNdPsaEBQxYHZTuTdcJWz7VQtikCKA6BNaQ,1920
149
155
  tests/test_directory_navigator.py,sha256=7G0MVrBbtBvbrFUpL0zb_9EkEWi1dulWuHsrQxMJxDY,140
150
- tests/test_file_classifier.py,sha256=kLWPiePu3F5mkVuI_lK_2QlLh2kXD_Mt2K8KZZ1fAnA,10940
151
- 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
152
158
  tests/test_file_lister.py,sha256=Q9HwhKKx540EPzTmfzOCnvtAgON0aMmpJE2eOe1J3EA,4324
159
+ tests/test_global_file_lister.py,sha256=ycvf2YL8q5QSEMwcnQfUdoWnQQ8xTSyEtccAeXwl6QU,5487
153
160
  tests/test_list_filter.py,sha256=fJA3d_SdaOAUkE7jn68MOVS0THXGghy1fye_64Zvo1U,7964
154
- tests/test_prompt_handler.py,sha256=3-lYBvyHLQgD29MODkXB3YylUWXmRCYdAwrQrtlW8WU,30871
161
+ tests/test_prompt_handler.py,sha256=kW8FU09ho4I5qC-f4G9r4ZgI-NlqdOkTmAazG7FaTrw,32299
155
162
  tests/test_tag_extractor.py,sha256=nSiAYlTKZ7TLAOtcJpwK5zTWHhFYU0tI5xKnivLc1dU,2712
156
- tests/test_template_manager.py,sha256=q-LMHRG4rHkD6ON6YW4cpZxUx9hul6Or8wVVRC2kb-8,4099
163
+ tests/test_template_manager.py,sha256=qliEeYgAEakn8JIqIHa8u0Ht6DY4L3T6DcHBXkjzR4I,4167
157
164
  tests/test_update_config_prompt.py,sha256=xsqj1WTn4BsG5Q2t-sNPfu7EoMURFcS-hfb5VSXUnJc,6765
158
- ara_cli-0.1.9.94.dist-info/METADATA,sha256=CPz0aDXI8_4hJtbN9tm56-aNUNEum3G01dD9DMIwGdg,6755
159
- ara_cli-0.1.9.94.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
160
- ara_cli-0.1.9.94.dist-info/entry_points.txt,sha256=v4h7MzysTgSIDYfEo3oj4Kz_8lzsRa3hq-KJHEcLVX8,45
161
- ara_cli-0.1.9.94.dist-info/top_level.txt,sha256=WM4cLHT5DYUaWzLtRj-gu3yVNFpGQ6lLRI3FMmC-38I,14
162
- ara_cli-0.1.9.94.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
tests/test_ara_config.py CHANGED
@@ -115,6 +115,34 @@ class TestARAconfig:
115
115
  assert config.glossary_dir == "./glossary"
116
116
  assert "Warning: Value for 'glossary_dir' is missing or empty. Using default." in mock_stdout.getvalue()
117
117
 
118
+ @patch('sys.stdout', new_callable=StringIO)
119
+ def test_validator_with_empty_llm_config(self, mock_stdout):
120
+ """Tests validator when llm_config is empty, setting default and extraction to None."""
121
+ config = ARAconfig(llm_config={})
122
+ assert config.llm_config == {}
123
+ assert config.default_llm is None
124
+ assert config.extraction_llm is None
125
+ assert "Warning: 'llm_config' is empty" in mock_stdout.getvalue()
126
+
127
+ @patch('sys.stdout', new_callable=StringIO)
128
+ def test_validator_with_invalid_default_llm(self, mock_stdout):
129
+ """Tests that an invalid default_llm is reverted to the first available model."""
130
+ config = ARAconfig(default_llm="non_existent_model")
131
+ first_llm = next(iter(config.llm_config))
132
+ assert config.default_llm == first_llm
133
+ output = mock_stdout.getvalue()
134
+ assert "Warning: The configured 'default_llm' ('non_existent_model') does not exist" in output
135
+ assert f"-> Reverting to the first available model: '{first_llm}'" in output
136
+
137
+ @patch('sys.stdout', new_callable=StringIO)
138
+ def test_validator_with_invalid_extraction_llm(self, mock_stdout):
139
+ """Tests that an invalid extraction_llm is reverted to the default_llm."""
140
+ config = ARAconfig(default_llm="gpt-4o", extraction_llm="non_existent_model")
141
+ assert config.extraction_llm == "gpt-4o"
142
+ output = mock_stdout.getvalue()
143
+ assert "Warning: The configured 'extraction_llm' ('non_existent_model') does not exist" in output
144
+ assert "-> Reverting to the 'default_llm' value: 'gpt-4o'" in output
145
+
118
146
  # --- Test Helper Functions ---
119
147
 
120
148
  class TestEnsureDirectoryExists: