ara-cli 0.1.9.76__py3-none-any.whl → 0.1.9.78__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.
Potentially problematic release.
This version of ara-cli might be problematic. Click here for more details.
- ara_cli/__main__.py +11 -4
- ara_cli/ara_command_parser.py +300 -92
- ara_cli/artefact_autofix.py +167 -89
- ara_cli/artefact_models/artefact_load.py +11 -3
- ara_cli/artefact_models/task_artefact_model.py +31 -23
- ara_cli/artefact_reader.py +74 -50
- ara_cli/chat.py +68 -1
- ara_cli/version.py +1 -1
- ara_cli-0.1.9.78.dist-info/METADATA +208 -0
- {ara_cli-0.1.9.76.dist-info → ara_cli-0.1.9.78.dist-info}/RECORD +15 -15
- tests/test_artefact_autofix.py +88 -1
- tests/test_chat.py +169 -30
- ara_cli-0.1.9.76.dist-info/METADATA +0 -16
- {ara_cli-0.1.9.76.dist-info → ara_cli-0.1.9.78.dist-info}/WHEEL +0 -0
- {ara_cli-0.1.9.76.dist-info → ara_cli-0.1.9.78.dist-info}/entry_points.txt +0 -0
- {ara_cli-0.1.9.76.dist-info → ara_cli-0.1.9.78.dist-info}/top_level.txt +0 -0
tests/test_chat.py
CHANGED
|
@@ -185,7 +185,7 @@ def test_disable_commands(temp_chat_file):
|
|
|
185
185
|
(["This is a line.", "Another line here.", "Yet another line."], None),
|
|
186
186
|
(["This is a line.", "# ara prompt:", "Another line here."], "# ara prompt:"),
|
|
187
187
|
(["This is a line.", "# ara prompt:", "Another line here.", "# ara response:"], "# ara response:"),
|
|
188
|
-
(["This is a line.", " # ara prompt: ", "Another line here.", " # ara response:
|
|
188
|
+
(["This is a line.", " # ara prompt: ", "Another line here.", " # ara response: "], "# ara response:"),
|
|
189
189
|
(["# ara prompt:", "# ara response:"], "# ara response:"),
|
|
190
190
|
(["# ara response:", "# ara prompt:", "# ara prompt:", "# ara response:"], "# ara response:"),
|
|
191
191
|
([], None)
|
|
@@ -233,8 +233,8 @@ def test_start(temp_chat_file):
|
|
|
233
233
|
(["This is a line.\n", "# ara prompt:\n", "Another line here.\n", "# ara response:\n"],
|
|
234
234
|
["This is a line.\n", "# ara prompt:\n", "Another line here.\n", "# ara response:\n", "\n", "# ara prompt:"]),
|
|
235
235
|
|
|
236
|
-
(["This is a line.\n", " # ara prompt: \n", "Another line here.\n", " # ara response:
|
|
237
|
-
["This is a line.\n", " # ara prompt: \n", "Another line here.\n", " # ara response:
|
|
236
|
+
(["This is a line.\n", " # ara prompt: \n", "Another line here.\n", " # ara response: \n"],
|
|
237
|
+
["This is a line.\n", " # ara prompt: \n", "Another line here.\n", " # ara response: \n", "\n", "# ara prompt:"]),
|
|
238
238
|
|
|
239
239
|
(["# ara prompt:\n", "# ara response:\n"],
|
|
240
240
|
["# ara prompt:\n", "# ara response:\n", "\n", "# ara prompt:"]),
|
|
@@ -257,7 +257,7 @@ def test_add_prompt_tag_if_needed(temp_chat_file, initial_content, expected_cont
|
|
|
257
257
|
|
|
258
258
|
|
|
259
259
|
@pytest.mark.parametrize("lines, expected", [
|
|
260
|
-
(["\n", "
|
|
260
|
+
(["\n", " ", "# ara prompt:", "Another line here.", " \n"], "Another line here."),
|
|
261
261
|
(["This is a line.", "Another line here.", " \n", "\n"], "Another line here."),
|
|
262
262
|
(["\n", " \n", " \n"], ""),
|
|
263
263
|
(["This is a line.", "Another line here.", "# ara response:", " \n"], "# ara response:"),
|
|
@@ -270,7 +270,7 @@ def test_get_last_non_empty_line(lines, expected, temp_chat_file):
|
|
|
270
270
|
assert Chat.get_last_non_empty_line(Chat, file) == expected
|
|
271
271
|
|
|
272
272
|
@pytest.mark.parametrize("lines, expected", [
|
|
273
|
-
(["\n", "
|
|
273
|
+
(["\n", " ", "# ara prompt:", "Another line here.", " \n"], ""),
|
|
274
274
|
(["This is a line.", "Another line here."], "Another line here."),
|
|
275
275
|
(["\n", " \n", " \n"], ""),
|
|
276
276
|
(["This is a line.", "Another line here.", "# ara response:", " \n"], ""),
|
|
@@ -290,7 +290,7 @@ def test_get_last_line(lines, expected, temp_chat_file):
|
|
|
290
290
|
(["Text with image", "(data:image/png;base64,abc123)"],
|
|
291
291
|
"Text with image",
|
|
292
292
|
[{"type": "image_url", "image_url": {"url": "data:image/png;base64,abc123"}}]),
|
|
293
|
-
(["Just text", "Another (data:image/png;base64,xyz789) image"],
|
|
293
|
+
(["Just text", "Another (data:image/png;base64,xyz789) image"],
|
|
294
294
|
"Just text",
|
|
295
295
|
[{"type": "image_url", "image_url": {"url": "data:image/png;base64,xyz789"}}]),
|
|
296
296
|
(["No images here at all"], "No images here at all", []),
|
|
@@ -392,7 +392,7 @@ def test_save_message(temp_chat_file, role, message, initial_content, expected_c
|
|
|
392
392
|
def test_resend_message(temp_chat_file, initial_content, expected_content):
|
|
393
393
|
temp_chat_file.writelines(initial_content)
|
|
394
394
|
temp_chat_file.flush()
|
|
395
|
-
|
|
395
|
+
|
|
396
396
|
mock_config = get_default_config()
|
|
397
397
|
with patch('ara_cli.prompt_handler.ConfigManager.get_config', return_value=mock_config):
|
|
398
398
|
chat = Chat(temp_chat_file.name, reset=False)
|
|
@@ -456,7 +456,7 @@ def test_determine_file_path(temp_chat_file):
|
|
|
456
456
|
]
|
|
457
457
|
|
|
458
458
|
with patch('os.path.exists') as mock_exists, \
|
|
459
|
-
|
|
459
|
+
patch('os.path.dirname', return_value="current_directory") as mock_dirname:
|
|
460
460
|
|
|
461
461
|
for file_name, exists_in_current, exists_elsewhere, expected_path in test_cases:
|
|
462
462
|
mock_exists.side_effect = [exists_in_current, exists_elsewhere]
|
|
@@ -501,9 +501,9 @@ def test_load_text_file_file_not_found(temp_chat_file):
|
|
|
501
501
|
with patch("builtins.open", mock_open()) as mock_file:
|
|
502
502
|
result = chat.load_text_file("nonexistent.txt")
|
|
503
503
|
|
|
504
|
-
|
|
504
|
+
assert result is False
|
|
505
505
|
|
|
506
|
-
|
|
506
|
+
mock_file.assert_not_called()
|
|
507
507
|
|
|
508
508
|
|
|
509
509
|
@pytest.mark.parametrize("file_name, mime_type, file_content, expected, path_exists", [
|
|
@@ -516,7 +516,6 @@ def test_load_binary_file(temp_chat_file, file_name, mime_type, file_content, ex
|
|
|
516
516
|
with patch('ara_cli.prompt_handler.ConfigManager.get_config', return_value=mock_config):
|
|
517
517
|
chat = Chat(temp_chat_file.name, reset=False)
|
|
518
518
|
|
|
519
|
-
# Mock open to handle both read and write operations
|
|
520
519
|
mock_file = mock_open(read_data=file_content)
|
|
521
520
|
|
|
522
521
|
with patch('builtins.open', mock_file) as mocked_open, \
|
|
@@ -535,36 +534,112 @@ def test_load_binary_file(temp_chat_file, file_name, mime_type, file_content, ex
|
|
|
535
534
|
assert result is False
|
|
536
535
|
|
|
537
536
|
|
|
538
|
-
@pytest.mark.parametrize("file_name,
|
|
539
|
-
(
|
|
540
|
-
|
|
537
|
+
@pytest.mark.parametrize("file_name, loader_path, mock_setup, expected_content", [
|
|
538
|
+
(
|
|
539
|
+
"test.docx",
|
|
540
|
+
"docx.Document",
|
|
541
|
+
lambda mock: setattr(mock.return_value, 'paragraphs', [MagicMock(text="Docx content")]),
|
|
542
|
+
"Docx content"
|
|
543
|
+
),
|
|
544
|
+
pytest.param(
|
|
545
|
+
"test.pdf",
|
|
546
|
+
"pymupdf4llm.to_markdown",
|
|
547
|
+
lambda mock: setattr(mock, 'return_value', "PDF content"),
|
|
548
|
+
"PDF content",
|
|
549
|
+
marks=pytest.mark.filterwarnings("ignore::DeprecationWarning")
|
|
550
|
+
),
|
|
551
|
+
pytest.param(
|
|
552
|
+
"test.odt",
|
|
553
|
+
"pymupdf4llm.to_markdown",
|
|
554
|
+
lambda mock: setattr(mock, 'return_value', "ODT content"),
|
|
555
|
+
"ODT content",
|
|
556
|
+
marks=pytest.mark.filterwarnings("ignore::DeprecationWarning")
|
|
557
|
+
),
|
|
541
558
|
])
|
|
542
|
-
def
|
|
559
|
+
def test_load_document_file(temp_chat_file, file_name, loader_path, mock_setup, expected_content):
|
|
560
|
+
mock_config = get_default_config()
|
|
561
|
+
with patch('ara_cli.prompt_handler.ConfigManager.get_config', return_value=mock_config):
|
|
562
|
+
chat = Chat(temp_chat_file.name, reset=False)
|
|
563
|
+
|
|
564
|
+
with patch(loader_path, create=True) as mock_loader, \
|
|
565
|
+
patch("builtins.open", mock_open()) as mock_chat_open:
|
|
566
|
+
|
|
567
|
+
mock_setup(mock_loader)
|
|
568
|
+
|
|
569
|
+
with patch.object(chat, 'determine_file_path', return_value=file_name):
|
|
570
|
+
result = chat.load_document_file(file_name, prefix="Prefix-", suffix="-Suffix", block_delimiter="```")
|
|
571
|
+
|
|
572
|
+
assert result is True
|
|
573
|
+
|
|
574
|
+
if loader_path == "pymupdf4llm.to_markdown":
|
|
575
|
+
mock_loader.assert_called_once_with(file_name, write_images=False)
|
|
576
|
+
else:
|
|
577
|
+
mock_loader.assert_called_once_with(file_name)
|
|
578
|
+
|
|
579
|
+
expected_write = f"Prefix-```\n{expected_content}\n```-Suffix\n"
|
|
580
|
+
mock_chat_open.assert_called_with(chat.chat_name, 'a', encoding='utf-8')
|
|
581
|
+
mock_chat_open().write.assert_called_once_with(expected_write)
|
|
582
|
+
|
|
583
|
+
|
|
584
|
+
def test_load_document_file_unsupported(temp_chat_file, capsys):
|
|
585
|
+
mock_config = get_default_config()
|
|
586
|
+
with patch('ara_cli.prompt_handler.ConfigManager.get_config', return_value=mock_config):
|
|
587
|
+
chat = Chat(temp_chat_file.name, reset=False)
|
|
588
|
+
|
|
589
|
+
unsupported_file = "test.txt"
|
|
590
|
+
with patch.object(chat, 'determine_file_path', return_value=unsupported_file):
|
|
591
|
+
result = chat.load_document_file(unsupported_file)
|
|
592
|
+
|
|
593
|
+
assert result is False
|
|
594
|
+
captured = capsys.readouterr()
|
|
595
|
+
assert "Unsupported document type." in captured.out
|
|
596
|
+
|
|
597
|
+
|
|
598
|
+
@pytest.mark.parametrize("file_name, file_type, mime_type", [
|
|
599
|
+
("image.png", "binary", "image/png"),
|
|
600
|
+
("document.txt", "text", None),
|
|
601
|
+
("document.docx", "document", None),
|
|
602
|
+
("document.pdf", "document", None),
|
|
603
|
+
("archive.zip", "text", None),
|
|
604
|
+
])
|
|
605
|
+
def test_load_file(temp_chat_file, file_name, file_type, mime_type):
|
|
543
606
|
mock_config = get_default_config()
|
|
544
607
|
with patch('ara_cli.prompt_handler.ConfigManager.get_config', return_value=mock_config):
|
|
545
608
|
chat = Chat(temp_chat_file.name, reset=False)
|
|
546
609
|
|
|
547
610
|
with patch.object(chat, 'load_binary_file', return_value=True) as mock_load_binary, \
|
|
548
|
-
patch.object(chat, 'load_text_file', return_value=True) as mock_load_text
|
|
611
|
+
patch.object(chat, 'load_text_file', return_value=True) as mock_load_text, \
|
|
612
|
+
patch.object(chat, 'load_document_file', return_value=True) as mock_load_document:
|
|
549
613
|
|
|
550
|
-
chat.load_file(file_name=file_name)
|
|
614
|
+
chat.load_file(file_name=file_name, prefix="p-", suffix="-s", block_delimiter="b")
|
|
551
615
|
|
|
552
|
-
if
|
|
616
|
+
if file_type == "binary":
|
|
553
617
|
mock_load_binary.assert_called_once_with(
|
|
554
618
|
file_name=file_name,
|
|
555
|
-
mime_type=
|
|
556
|
-
prefix="",
|
|
557
|
-
suffix=""
|
|
619
|
+
mime_type=mime_type,
|
|
620
|
+
prefix="p-",
|
|
621
|
+
suffix="-s"
|
|
558
622
|
)
|
|
559
623
|
mock_load_text.assert_not_called()
|
|
624
|
+
mock_load_document.assert_not_called()
|
|
625
|
+
elif file_type == "document":
|
|
626
|
+
mock_load_binary.assert_not_called()
|
|
627
|
+
mock_load_text.assert_not_called()
|
|
628
|
+
mock_load_document.assert_called_once_with(
|
|
629
|
+
file_name=file_name,
|
|
630
|
+
prefix="p-",
|
|
631
|
+
suffix="-s",
|
|
632
|
+
block_delimiter="b"
|
|
633
|
+
)
|
|
560
634
|
else:
|
|
635
|
+
mock_load_binary.assert_not_called()
|
|
561
636
|
mock_load_text.assert_called_once_with(
|
|
562
637
|
file_name=file_name,
|
|
563
|
-
prefix="",
|
|
564
|
-
suffix="",
|
|
565
|
-
block_delimiter=""
|
|
638
|
+
prefix="p-",
|
|
639
|
+
suffix="-s",
|
|
640
|
+
block_delimiter="b"
|
|
566
641
|
)
|
|
567
|
-
|
|
642
|
+
mock_load_document.assert_not_called()
|
|
568
643
|
|
|
569
644
|
|
|
570
645
|
@pytest.mark.parametrize("files, pattern, user_input, expected_output, expected_file", [
|
|
@@ -788,6 +863,71 @@ def test_complete_LOAD(monkeypatch, temp_chat_file, text, line, begidx, endidx,
|
|
|
788
863
|
assert completions == matching_files
|
|
789
864
|
|
|
790
865
|
|
|
866
|
+
@pytest.mark.parametrize("file_name, is_image, expected_mime", [
|
|
867
|
+
("test.png", True, "image/png"),
|
|
868
|
+
("test.jpg", True, "image/jpeg"),
|
|
869
|
+
("test.jpeg", True, "image/jpeg"),
|
|
870
|
+
("test.txt", False, None)
|
|
871
|
+
])
|
|
872
|
+
def test_load_image(capsys, temp_chat_file, file_name, is_image, expected_mime):
|
|
873
|
+
mock_config = get_default_config()
|
|
874
|
+
with patch('ara_cli.prompt_handler.ConfigManager.get_config', return_value=mock_config):
|
|
875
|
+
chat = Chat(temp_chat_file.name, reset=False)
|
|
876
|
+
|
|
877
|
+
with patch.object(chat, 'load_binary_file', return_value=True) as mock_load_binary:
|
|
878
|
+
chat.load_image(file_name=file_name, prefix="p-", suffix="-s")
|
|
879
|
+
|
|
880
|
+
if is_image:
|
|
881
|
+
mock_load_binary.assert_called_once_with(
|
|
882
|
+
file_name=file_name,
|
|
883
|
+
mime_type=expected_mime,
|
|
884
|
+
prefix="p-",
|
|
885
|
+
suffix="-s"
|
|
886
|
+
)
|
|
887
|
+
else:
|
|
888
|
+
mock_load_binary.assert_not_called()
|
|
889
|
+
captured = capsys.readouterr()
|
|
890
|
+
assert f"File {file_name} not recognized as image, could not load" in captured.out
|
|
891
|
+
|
|
892
|
+
|
|
893
|
+
def test_do_LOAD_DOCUMENT(capsys, temp_chat_file):
|
|
894
|
+
mock_config = get_default_config()
|
|
895
|
+
with patch('ara_cli.prompt_handler.ConfigManager.get_config', return_value=mock_config):
|
|
896
|
+
chat = Chat(temp_chat_file.name, reset=False)
|
|
897
|
+
|
|
898
|
+
doc_file = "test.docx"
|
|
899
|
+
with patch.object(chat, 'find_matching_files_to_load', return_value=[doc_file]) as mock_find, \
|
|
900
|
+
patch.object(chat, 'load_document_file', return_value=True) as mock_load, \
|
|
901
|
+
patch.object(chat, 'add_prompt_tag_if_needed') as mock_add_tag:
|
|
902
|
+
|
|
903
|
+
chat.do_LOAD_DOCUMENT(doc_file)
|
|
904
|
+
|
|
905
|
+
mock_find.assert_called_once_with(doc_file)
|
|
906
|
+
mock_add_tag.assert_called_once_with(chat.chat_name)
|
|
907
|
+
mock_load.assert_called_once_with(doc_file, prefix=f"\nFile: {doc_file}\n")
|
|
908
|
+
captured = capsys.readouterr()
|
|
909
|
+
assert f"Loaded document file {doc_file}" in captured.out
|
|
910
|
+
|
|
911
|
+
|
|
912
|
+
def test_do_LOAD_IMAGE(capsys, temp_chat_file):
|
|
913
|
+
mock_config = get_default_config()
|
|
914
|
+
with patch('ara_cli.prompt_handler.ConfigManager.get_config', return_value=mock_config):
|
|
915
|
+
chat = Chat(temp_chat_file.name, reset=False)
|
|
916
|
+
|
|
917
|
+
image_file = "test.png"
|
|
918
|
+
with patch.object(chat, 'find_matching_files_to_load', return_value=[image_file]) as mock_find, \
|
|
919
|
+
patch.object(chat, 'load_image', return_value=True) as mock_load, \
|
|
920
|
+
patch.object(chat, 'add_prompt_tag_if_needed') as mock_add_tag:
|
|
921
|
+
|
|
922
|
+
chat.do_LOAD_IMAGE(image_file)
|
|
923
|
+
|
|
924
|
+
mock_find.assert_called_once_with(image_file)
|
|
925
|
+
mock_add_tag.assert_called_once_with(chat.chat_name)
|
|
926
|
+
mock_load.assert_called_once_with(image_file, prefix=f"\nFile: {image_file}\n")
|
|
927
|
+
captured = capsys.readouterr()
|
|
928
|
+
assert f"Loaded image file {image_file}" in captured.out
|
|
929
|
+
|
|
930
|
+
|
|
791
931
|
@pytest.mark.parametrize("input_chat_name, expected_chat_name", [
|
|
792
932
|
("", "What should be the new chat name? "),
|
|
793
933
|
("new_chat", "new_chat_chat.md"),
|
|
@@ -796,13 +936,13 @@ def test_complete_LOAD(monkeypatch, temp_chat_file, text, line, begidx, endidx,
|
|
|
796
936
|
def test_do_new(monkeypatch, temp_chat_file, input_chat_name, expected_chat_name):
|
|
797
937
|
def mock_input(prompt):
|
|
798
938
|
return "input_chat_name"
|
|
799
|
-
|
|
939
|
+
|
|
800
940
|
monkeypatch.setattr('builtins.input', mock_input)
|
|
801
941
|
|
|
802
942
|
mock_config = get_default_config()
|
|
803
943
|
with patch('ara_cli.prompt_handler.ConfigManager.get_config', return_value=mock_config):
|
|
804
944
|
chat = Chat(temp_chat_file.name, reset=False)
|
|
805
|
-
|
|
945
|
+
|
|
806
946
|
with patch.object(Chat, '__init__', return_value=None) as mock_init:
|
|
807
947
|
chat.do_NEW(input_chat_name)
|
|
808
948
|
if input_chat_name == "":
|
|
@@ -1057,10 +1197,9 @@ def test_do_SEND(temp_chat_file):
|
|
|
1057
1197
|
("AnotherTemplate", MagicMock(serialize=MagicMock(return_value="other_content")), "other_content", "Loaded AnotherTemplate artefact template\n"),
|
|
1058
1198
|
])
|
|
1059
1199
|
def test_do_LOAD_TEMPLATE_success(temp_chat_file, template_name, artefact_obj, expected_write, expected_print, capsys):
|
|
1060
|
-
mock_config = MagicMock()
|
|
1200
|
+
mock_config = MagicMock()
|
|
1061
1201
|
with patch('ara_cli.prompt_handler.ConfigManager.get_config', return_value=mock_config):
|
|
1062
1202
|
chat = Chat(temp_chat_file.name, reset=False)
|
|
1063
|
-
# Patch the artefact loader to return artefact_obj
|
|
1064
1203
|
with patch('ara_cli.artefact_models.artefact_templates.template_artefact_of_type', return_value=artefact_obj) as mock_template_loader, \
|
|
1065
1204
|
patch.object(chat, 'add_prompt_tag_if_needed') as mock_add_prompt_tag, \
|
|
1066
1205
|
patch("builtins.open", mock_open()) as mock_file:
|
|
@@ -1087,4 +1226,4 @@ def test_do_LOAD_TEMPLATE_missing_artefact(temp_chat_file, template_name):
|
|
|
1087
1226
|
chat.do_LOAD_TEMPLATE(template_name)
|
|
1088
1227
|
mock_template_loader.assert_called_once_with(template_name)
|
|
1089
1228
|
mock_add_prompt_tag.assert_not_called()
|
|
1090
|
-
mock_file.assert_not_called()
|
|
1229
|
+
mock_file.assert_not_called()
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: ara_cli
|
|
3
|
-
Version: 0.1.9.76
|
|
4
|
-
Requires-Dist: litellm
|
|
5
|
-
Requires-Dist: llama-index
|
|
6
|
-
Requires-Dist: llama-index-llms-openai
|
|
7
|
-
Requires-Dist: llama-index-retrievers-bm25
|
|
8
|
-
Requires-Dist: openai
|
|
9
|
-
Requires-Dist: markdown-it-py
|
|
10
|
-
Requires-Dist: json-repair
|
|
11
|
-
Requires-Dist: argparse
|
|
12
|
-
Requires-Dist: argcomplete
|
|
13
|
-
Requires-Dist: cmd2>=2.5
|
|
14
|
-
Requires-Dist: pydantic
|
|
15
|
-
Requires-Dist: pydantic_ai
|
|
16
|
-
Dynamic: requires-dist
|
|
File without changes
|
|
File without changes
|
|
File without changes
|