Compare commits
3 Commits
0e00d25ef3
...
bcb3a2d45a
| Author | SHA1 | Date | |
|---|---|---|---|
| bcb3a2d45a | |||
| 84961e5d0d | |||
| e6cf9984e4 |
@ -15,7 +15,7 @@ def hist_cmd(args: argparse.Namespace, config: Config) -> None:
|
||||
tags_not=args.exclude_tags,
|
||||
question_contains=args.question,
|
||||
answer_contains=args.answer)
|
||||
chat = ChatDB.from_dir(Path('.'),
|
||||
chat = ChatDB.from_dir(Path(config.cache),
|
||||
Path(config.db),
|
||||
mfilter=mfilter)
|
||||
chat.print(args.source_code_only,
|
||||
|
||||
@ -112,7 +112,7 @@ def question_cmd(args: argparse.Namespace, config: Config) -> None:
|
||||
mfilter = MessageFilter(tags_or=args.or_tags if args.or_tags is not None else set(),
|
||||
tags_and=args.and_tags if args.and_tags is not None else set(),
|
||||
tags_not=args.exclude_tags if args.exclude_tags is not None else set())
|
||||
chat = ChatDB.from_dir(cache_path=Path('.'),
|
||||
chat = ChatDB.from_dir(cache_path=Path(config.cache),
|
||||
db_path=Path(config.db),
|
||||
mfilter=mfilter)
|
||||
# if it's a new question, create and store it immediately
|
||||
|
||||
@ -8,7 +8,7 @@ def tags_cmd(args: argparse.Namespace, config: Config) -> None:
|
||||
"""
|
||||
Handler for the 'tags' command.
|
||||
"""
|
||||
chat = ChatDB.from_dir(cache_path=Path('.'),
|
||||
chat = ChatDB.from_dir(cache_path=Path(config.cache),
|
||||
db_path=Path(config.db))
|
||||
if args.list:
|
||||
tags_freq = chat.msg_tags_frequency(args.prefix, args.contain)
|
||||
|
||||
@ -116,6 +116,7 @@ class Config:
|
||||
"""
|
||||
# all members have default values, so we can easily create
|
||||
# a default configuration
|
||||
cache: str = '.'
|
||||
db: str = './db/'
|
||||
ais: dict[str, AIConfig] = field(default_factory=create_default_ai_configs)
|
||||
|
||||
@ -132,6 +133,7 @@ class Config:
|
||||
ai_conf = ai_config_instance(conf['name'], conf)
|
||||
ais[ID] = ai_conf
|
||||
return cls(
|
||||
cache=str(source['cache']) if 'cache' in source else '.',
|
||||
db=str(source['db']),
|
||||
ais=ais
|
||||
)
|
||||
|
||||
@ -57,6 +57,7 @@ class TestConfig(unittest.TestCase):
|
||||
|
||||
def test_from_dict_should_create_config_from_dict(self) -> None:
|
||||
source_dict = {
|
||||
'cache': '.',
|
||||
'db': './test_db/',
|
||||
'ais': {
|
||||
'myopenai': {
|
||||
@ -73,6 +74,7 @@ class TestConfig(unittest.TestCase):
|
||||
}
|
||||
}
|
||||
config = Config.from_dict(source_dict)
|
||||
self.assertEqual(config.cache, '.')
|
||||
self.assertEqual(config.db, './test_db/')
|
||||
self.assertEqual(len(config.ais), 1)
|
||||
self.assertEqual(config.ais['myopenai'].name, 'openai')
|
||||
@ -89,6 +91,7 @@ class TestConfig(unittest.TestCase):
|
||||
|
||||
def test_from_file_should_load_config_from_file(self) -> None:
|
||||
source_dict = {
|
||||
'cache': './test_cache/',
|
||||
'db': './test_db/',
|
||||
'ais': {
|
||||
'default': {
|
||||
@ -108,6 +111,7 @@ class TestConfig(unittest.TestCase):
|
||||
yaml.dump(source_dict, f)
|
||||
config = Config.from_file(self.test_file.name)
|
||||
self.assertIsInstance(config, Config)
|
||||
self.assertEqual(config.cache, './test_cache/')
|
||||
self.assertEqual(config.db, './test_db/')
|
||||
self.assertEqual(len(config.ais), 1)
|
||||
self.assertIsInstance(config.ais['default'], AIConfig)
|
||||
@ -115,6 +119,7 @@ class TestConfig(unittest.TestCase):
|
||||
|
||||
def test_to_file_should_save_config_to_file(self) -> None:
|
||||
config = Config(
|
||||
cache='./test_cache/',
|
||||
db='./test_db/',
|
||||
ais={
|
||||
'myopenai': OpenAIConfig(
|
||||
@ -133,12 +138,14 @@ class TestConfig(unittest.TestCase):
|
||||
config.to_file(Path(self.test_file.name))
|
||||
with open(self.test_file.name, 'r') as f:
|
||||
saved_config = yaml.load(f, Loader=yaml.FullLoader)
|
||||
self.assertEqual(saved_config['cache'], './test_cache/')
|
||||
self.assertEqual(saved_config['db'], './test_db/')
|
||||
self.assertEqual(len(saved_config['ais']), 1)
|
||||
self.assertEqual(saved_config['ais']['myopenai']['system'], 'Custom system')
|
||||
|
||||
def test_from_file_error_unknown_ai(self) -> None:
|
||||
source_dict = {
|
||||
'cache': './test_cache/',
|
||||
'db': './test_db/',
|
||||
'ais': {
|
||||
'default': {
|
||||
|
||||
@ -4,11 +4,13 @@ import argparse
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
from unittest import mock
|
||||
from unittest.mock import MagicMock, call
|
||||
from unittest.mock import MagicMock, call, ANY
|
||||
from typing import Optional
|
||||
from chatmastermind.configuration import Config
|
||||
from chatmastermind.commands.question import create_message, question_cmd
|
||||
from chatmastermind.tags import Tag
|
||||
from chatmastermind.message import Message, Question, Answer
|
||||
from chatmastermind.chat import ChatDB
|
||||
from chatmastermind.chat import Chat, ChatDB
|
||||
from chatmastermind.ai import AI, AIResponse, Tokens
|
||||
|
||||
|
||||
@ -19,10 +21,10 @@ class TestMessageCreate(unittest.TestCase):
|
||||
"""
|
||||
def setUp(self) -> None:
|
||||
# create ChatDB structure
|
||||
self.db_path = tempfile.TemporaryDirectory()
|
||||
self.cache_path = tempfile.TemporaryDirectory()
|
||||
self.chat = ChatDB.from_dir(cache_path=Path(self.cache_path.name),
|
||||
db_path=Path(self.db_path.name))
|
||||
self.db_dir = tempfile.TemporaryDirectory()
|
||||
self.cache_dir = tempfile.TemporaryDirectory()
|
||||
self.chat = ChatDB.from_dir(cache_path=Path(self.cache_dir.name),
|
||||
db_path=Path(self.db_dir.name))
|
||||
# create some messages
|
||||
self.message_text = Message(Question("What is this?"),
|
||||
Answer("It is pure text"))
|
||||
@ -85,10 +87,10 @@ Aaaand again some text."""
|
||||
|
||||
def test_message_file_created(self) -> None:
|
||||
self.args.ask = ["What is this?"]
|
||||
cache_dir_files = self.message_list(self.cache_path)
|
||||
cache_dir_files = self.message_list(self.cache_dir)
|
||||
self.assertEqual(len(cache_dir_files), 0)
|
||||
create_message(self.chat, self.args)
|
||||
cache_dir_files = self.message_list(self.cache_path)
|
||||
cache_dir_files = self.message_list(self.cache_dir)
|
||||
self.assertEqual(len(cache_dir_files), 1)
|
||||
message = Message.from_file(cache_dir_files[0])
|
||||
self.assertIsInstance(message, Message)
|
||||
@ -203,10 +205,12 @@ class TestQuestionCmd(unittest.TestCase):
|
||||
|
||||
def setUp(self) -> None:
|
||||
# create DB and cache
|
||||
self.db_path = tempfile.TemporaryDirectory()
|
||||
self.cache_path = tempfile.TemporaryDirectory()
|
||||
self.db_dir = tempfile.TemporaryDirectory()
|
||||
self.cache_dir = tempfile.TemporaryDirectory()
|
||||
# create configuration
|
||||
self.config = Config()
|
||||
self.config.cache = self.cache_dir.name
|
||||
self.config.db = self.db_dir.name
|
||||
# create a mock argparse.Namespace
|
||||
self.args = argparse.Namespace(
|
||||
ask=['What is the meaning of life?'],
|
||||
@ -238,36 +242,79 @@ class TestQuestionCmd(unittest.TestCase):
|
||||
ai=args.AI,
|
||||
model=args.model)
|
||||
|
||||
def response(self, args: argparse.Namespace) -> AIResponse:
|
||||
def mock_request(self,
|
||||
question: Message,
|
||||
chat: Chat,
|
||||
num_answers: int = 1,
|
||||
otags: Optional[set[Tag]] = None) -> AIResponse:
|
||||
"""
|
||||
Create the expected AI response from the give arguments.
|
||||
Mock the 'ai.request()' function
|
||||
"""
|
||||
input_msg = self.input_message(args)
|
||||
response = AIResponse(messages=[], tokens=Tokens(10, 10, 20))
|
||||
for n in range(args.num_answers):
|
||||
response_msg = Message(input_msg.question,
|
||||
Answer(f"Answer {n}"),
|
||||
tags=input_msg.tags,
|
||||
ai=input_msg.ai,
|
||||
model=input_msg.model)
|
||||
response.messages.append(response_msg)
|
||||
return response
|
||||
question.answer = Answer("Answer 0")
|
||||
question.tags = otags
|
||||
question.ai = 'FakeAI'
|
||||
question.model = 'FakeModel'
|
||||
answers: list[Message] = [question]
|
||||
for n in range(1, num_answers):
|
||||
answers.append(Message(question=question.question,
|
||||
answer=Answer(f"Answer {n}"),
|
||||
tags=otags,
|
||||
ai='FakeAI',
|
||||
model='FakeModel'))
|
||||
return AIResponse(answers, Tokens(10, 10, 20))
|
||||
|
||||
def message_list(self, tmp_dir: tempfile.TemporaryDirectory) -> list[Path]:
|
||||
# exclude '.next'
|
||||
return sorted([f for f in Path(tmp_dir.name).glob('*.[ty]*')])
|
||||
|
||||
@mock.patch('chatmastermind.commands.question.create_ai')
|
||||
def test_ask_single_answer(self, mock_create_ai: MagicMock) -> None:
|
||||
"""
|
||||
Test single answer with no errors
|
||||
"""
|
||||
# create a mock AI instance
|
||||
ai = MagicMock(spec=AI)
|
||||
ai.request.side_effect = self.mock_request
|
||||
mock_create_ai.return_value = ai
|
||||
expected_question = self.input_message(self.args)
|
||||
expected_responses = self.mock_request(expected_question,
|
||||
Chat([]),
|
||||
self.args.num_answers,
|
||||
self.args.output_tags).messages
|
||||
|
||||
# execute the command
|
||||
question_cmd(self.args, self.config)
|
||||
|
||||
# check for correct request call
|
||||
ai.request.assert_called_once_with(expected_question,
|
||||
ANY,
|
||||
self.args.num_answers,
|
||||
self.args.output_tags)
|
||||
# check for the expected message files
|
||||
chat = ChatDB.from_dir(Path(self.cache_dir.name),
|
||||
Path(self.db_dir.name))
|
||||
cached_msg = chat.msg_gather(loc='cache')
|
||||
self.assertEqual(len(self.message_list(self.cache_dir)), 1)
|
||||
self.assertSequenceEqual(cached_msg, expected_responses)
|
||||
|
||||
@mock.patch('chatmastermind.commands.question.ChatDB.from_dir')
|
||||
@mock.patch('chatmastermind.commands.question.create_ai')
|
||||
def test_ask_single_answer(self, mock_create_ai: MagicMock, mock_from_dir: MagicMock) -> None:
|
||||
|
||||
# FIXME: this mock is only neccessary because the cache dir is not
|
||||
# configurable in the configuration file
|
||||
def test_ask_single_answer_mocked(self, mock_create_ai: MagicMock, mock_from_dir: MagicMock) -> None:
|
||||
"""
|
||||
Test single answer with no errors (mocked ChatDB version)
|
||||
"""
|
||||
chat = MagicMock(spec=ChatDB)
|
||||
mock_from_dir.return_value = chat
|
||||
|
||||
# create a mock AI instance
|
||||
ai = MagicMock(spec=AI)
|
||||
ai.request.return_value = self.response(self.args)
|
||||
ai.request.side_effect = self.mock_request
|
||||
mock_create_ai.return_value = ai
|
||||
expected_question = self.input_message(self.args)
|
||||
expected_responses = ai.request.return_value.messages
|
||||
expected_responses = self.mock_request(expected_question,
|
||||
Chat([]),
|
||||
self.args.num_answers,
|
||||
self.args.output_tags).messages
|
||||
|
||||
# execute the command
|
||||
question_cmd(self.args, self.config)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user