Skip to content

Commit

Permalink
Fixed tests, avoided formatting issue in input box
Browse files Browse the repository at this point in the history
  • Loading branch information
dougollerenshaw committed Sep 19, 2024
1 parent af06a42 commit a9e7ccc
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 49 deletions.
12 changes: 10 additions & 2 deletions codeaide/ui/chat_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import traceback

from PyQt5.QtCore import Qt, QTimer
from PyQt5.QtGui import QColor
from PyQt5.QtWidgets import (
QApplication,
QHBoxLayout,
Expand Down Expand Up @@ -46,6 +47,8 @@ def __init__(self, chat_handler):
self.add_to_chat("AI", INITIAL_MESSAGE)
self.check_api_key()

self.input_text.setTextColor(QColor(CHAT_WINDOW_FG))

signal.signal(signal.SIGINT, self.sigint_handler)
self.timer = QTimer()
self.timer.start(500)
Expand All @@ -67,9 +70,14 @@ def setup_ui(self):

self.input_text = QTextEdit(self)
self.input_text.setStyleSheet(
f"background-color: {CHAT_WINDOW_BG}; color: {USER_MESSAGE_COLOR}; border: 1px solid #ccc; padding: 5px;"
f"""
background-color: {CHAT_WINDOW_BG};
color: {CHAT_WINDOW_FG};
border: 1px solid #ccc;
padding: 5px;
"""
)
self.input_text.setAcceptRichText(True)
self.input_text.setAcceptRichText(False) # Add this line
self.input_text.setFont(general_utils.set_font(USER_FONT))
self.input_text.setFixedHeight(100)
self.input_text.textChanged.connect(self.on_modify)
Expand Down
48 changes: 14 additions & 34 deletions codeaide/utils/api_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,13 @@ def get_api_client(service="anthropic"):
)
)
api_key = auto_config(f"{service.upper()}_API_KEY", default=None)
if api_key is None:
raise MissingAPIKeyException(service)
if api_key is None or api_key.strip() == "":
return None # Return None if API key is missing or empty

if service == "anthropic":
if service.lower() == "anthropic":
return anthropic.Anthropic(api_key=api_key)
# Add more elif blocks here for other API services
else:
raise ValueError(f"Unsupported service: {service}")
except MissingAPIKeyException:
# If the API key is missing, return None instead of raising the exception
return None
except Exception as e:
print(f"Error initializing {service.capitalize()} API client: {str(e)}")
return None
Expand Down Expand Up @@ -77,29 +73,15 @@ def save_api_key(service, api_key):
def send_api_request(client, conversation_history, max_tokens=MAX_TOKENS):
system_prompt = SYSTEM_PROMPT
try:
print(f"\n\n{'='*50}\n")
print(
f"Sending API request. The max tokens is {max_tokens}. Here's the conversation history:"
)
for message in conversation_history:
print(f"{message['role']}: {message['content']}")
print("\n")

response = client.messages.create(
model=AI_MODEL,
max_tokens=max_tokens,
messages=conversation_history,
system=system_prompt,
)

content = response.content[0].text if response.content else ""

if not content:
print("Warning: Received empty response from API")
if not response.content:
return None

return response

except Exception as e:
print(f"Error in API request: {str(e)}")
return None
Expand All @@ -125,19 +107,17 @@ def parse_response(response):
return None, None, None, None, None, None


def check_api_connection(service="anthropic"):
client = get_api_client(service)
def check_api_connection():
client = get_api_client()
if client is None:
return False, "API key is missing or invalid"
try:
if service == "anthropic":
response = client.messages.create(
model=AI_MODEL,
max_tokens=100,
messages=[{"role": "user", "content": "Hi, are we communicating?"}],
)
return True, response.content[0].text.strip()
# Add more elif blocks here for other API services
else:
raise ValueError(f"Unsupported service: {service}")
response = client.messages.create(
model=AI_MODEL,
max_tokens=100,
messages=[{"role": "user", "content": "Hi Claude, are we communicating?"}],
)
return True, response.content[0].text.strip()
except Exception as e:
return False, str(e)

Expand Down
91 changes: 78 additions & 13 deletions tests/utils/test_api_utils.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import json
from collections import namedtuple
from unittest.mock import Mock
from unittest.mock import Mock, patch

import pytest
import anthropic
from anthropic import APIError

from codeaide.utils.api_utils import (
check_api_connection,
parse_response,
send_api_request,
get_api_client,
MissingAPIKeyException,
)
from codeaide.utils.constants import AI_MODEL, MAX_TOKENS, SYSTEM_PROMPT

Expand All @@ -23,14 +26,57 @@
]


@pytest.fixture
def mock_anthropic_client():
with patch("anthropic.Anthropic") as mock_anthropic:
mock_client = Mock()
mock_messages = Mock()
mock_client.messages = mock_messages
mock_anthropic.return_value = mock_client
yield mock_client


class TestGetApiClient:
def test_get_api_client_success(self, monkeypatch):
monkeypatch.setenv("ANTHROPIC_API_KEY", "test_key")
client = get_api_client()
assert client is not None
assert hasattr(
client, "messages"
) # Check for a common attribute of Anthropic client

@patch("codeaide.utils.api_utils.AutoConfig")
def test_get_api_client_missing_key(self, mock_auto_config, monkeypatch):
mock_config = Mock()
mock_config.return_value = None
mock_auto_config.return_value = mock_config
monkeypatch.delenv("ANTHROPIC_API_KEY", raising=False)
client = get_api_client()
assert client is None

def test_get_api_client_empty_key(self, monkeypatch):
monkeypatch.setenv("ANTHROPIC_API_KEY", "")
client = get_api_client()
assert client is None

@patch("codeaide.utils.api_utils.AutoConfig")
def test_get_api_client_unsupported_service(self, mock_auto_config):
mock_config = Mock()
mock_config.return_value = "dummy_key"
mock_auto_config.return_value = mock_config

result = get_api_client("unsupported_service")
assert result is None


class TestSendAPIRequest:
def test_send_api_request_success(self, mock_anthropic_client):
conversation_history = [{"role": "user", "content": "Hello, Claude!"}]
mock_response = Mock()
mock_response.content = [Mock(text="Hello! How can I assist you today?")]
mock_anthropic_client.messages.create.return_value = mock_response

result = send_api_request(conversation_history)
result = send_api_request(mock_anthropic_client, conversation_history)

mock_anthropic_client.messages.create.assert_called_once_with(
model=AI_MODEL,
Expand All @@ -46,9 +92,9 @@ def test_send_api_request_empty_response(self, mock_anthropic_client):
mock_response.content = []
mock_anthropic_client.messages.create.return_value = mock_response

result = send_api_request(conversation_history)
result = send_api_request(mock_anthropic_client, conversation_history)

assert result == (None, True)
assert result is None

def test_send_api_request_api_error(self, mock_anthropic_client):
conversation_history = [{"role": "user", "content": "Hello, Claude!"}]
Expand All @@ -59,9 +105,9 @@ def test_send_api_request_api_error(self, mock_anthropic_client):
body={"error": {"message": "API Error"}},
)

result = send_api_request(conversation_history)
result = send_api_request(mock_anthropic_client, conversation_history)

assert result == (None, True)
assert result is None

def test_send_api_request_custom_max_tokens(self, mock_anthropic_client):
conversation_history = [{"role": "user", "content": "Hello, Claude!"}]
Expand All @@ -70,7 +116,9 @@ def test_send_api_request_custom_max_tokens(self, mock_anthropic_client):
mock_response.content = [Mock(text="Hello! How can I assist you today?")]
mock_anthropic_client.messages.create.return_value = mock_response

result = send_api_request(conversation_history, max_tokens=custom_max_tokens)
result = send_api_request(
mock_anthropic_client, conversation_history, max_tokens=custom_max_tokens
)

mock_anthropic_client.messages.create.assert_called_once_with(
model=AI_MODEL,
Expand Down Expand Up @@ -191,18 +239,35 @@ def test_parse_response_malformed_json(self):


class TestAPIConnection:
def check_api_connection_success(self, mock_anthropic_client):
@patch("codeaide.utils.api_utils.get_api_client")
def test_check_api_connection_success(self, mock_get_api_client):
mock_client = Mock()
mock_response = Mock()
mock_response.content = [Mock(text="Yes, we are communicating.")]
mock_anthropic_client.messages.create.return_value = mock_response
mock_client.messages.create.return_value = mock_response
mock_get_api_client.return_value = mock_client

result = check_api_connection()

assert result[0] == True
assert result[1] == "Yes, we are communicating."

def check_api_connection_failure(self, mock_anthropic_client):
mock_anthropic_client.messages.create.side_effect = Exception(
"Connection failed"
)
@patch("codeaide.utils.api_utils.get_api_client")
def test_check_api_connection_failure(self, mock_get_api_client):
mock_client = Mock()
mock_client.messages.create.side_effect = Exception("Connection failed")
mock_get_api_client.return_value = mock_client

result = check_api_connection()

assert result[0] == False
assert "Connection failed" in result[1]

@patch("codeaide.utils.api_utils.get_api_client")
def test_check_api_connection_missing_key(self, mock_get_api_client):
mock_get_api_client.return_value = None

result = check_api_connection()

assert result[0] == False
assert "API key is missing or invalid" in result[1]

0 comments on commit a9e7ccc

Please sign in to comment.