Spaces:
Running
on
Zero
Running
on
Zero
import dataclasses | |
import functools | |
import inspect | |
import os | |
import shutil | |
import tempfile | |
from argparse import Namespace | |
from unittest.mock import patch | |
import pytest | |
import typer | |
import gpt_engineer.applications.cli.main as main | |
from gpt_engineer.applications.cli.main import load_prompt | |
from gpt_engineer.core.default.disk_memory import DiskMemory | |
from gpt_engineer.core.prompt import Prompt | |
def dcommand(typer_f, **kwargs): | |
required = True | |
def field_desc(name, param): | |
nonlocal required | |
t = param.annotation or "typing.Any" | |
if param.default.default is not ...: | |
required = False | |
return name, t, dataclasses.field(default=param.default.default) | |
if not required: | |
raise ValueError("Required value after optional") | |
return name, t | |
kwargs.setdefault("cls_name", typer_f.__name__) | |
params = inspect.signature(typer_f).parameters | |
kwargs["fields"] = [field_desc(k, v) for k, v in params.items()] | |
def dcommand_decorator(function_or_class): | |
assert callable(function_or_class) | |
ka = dict(kwargs) | |
ns = Namespace(**(ka.pop("namespace", None) or {})) | |
if isinstance(function_or_class, type): | |
ka["bases"] = *ka.get("bases", ()), function_or_class | |
else: | |
ns.__call__ = function_or_class | |
ka["namespace"] = vars(ns) | |
return dataclasses.make_dataclass(**ka) | |
return dcommand_decorator | |
class DefaultArgumentsMain: | |
def __call__(self): | |
attribute_dict = vars(self) | |
main.main(**attribute_dict) | |
def input_generator(): | |
yield "y" # First response | |
while True: | |
yield "n" # Subsequent responses | |
prompt_text = "Make a python program that writes 'hello' to a file called 'output.txt'" | |
class TestMain: | |
# Runs gpt-engineer cli interface for many parameter configurations, BUT DOES NOT CODEGEN! Only testing cli. | |
def test_default_settings_generate_project(self, tmp_path, monkeypatch): | |
p = tmp_path / "projects/example" | |
p.mkdir(parents=True) | |
(p / "prompt").write_text(prompt_text) | |
args = DefaultArgumentsMain(str(p), llm_via_clipboard=True, no_execution=True) | |
args() | |
# Runs gpt-engineer with improve mode and improves an existing project in the specified path. | |
def test_improve_existing_project(self, tmp_path, monkeypatch): | |
p = tmp_path / "projects/example" | |
p.mkdir(parents=True) | |
(p / "prompt").write_text(prompt_text) | |
args = DefaultArgumentsMain( | |
str(p), improve_mode=True, llm_via_clipboard=True, no_execution=True | |
) | |
args() | |
# def improve_generator(): | |
# yield "y" | |
# while True: | |
# yield "n" # Subsequent responses | |
# | |
# gen = improve_generator() | |
# monkeypatch.setattr("builtins.input", lambda _: next(gen)) | |
# p = tmp_path / "projects/example" | |
# p.mkdir(parents=True) | |
# (p / "prompt").write_text(prompt_text) | |
# (p / "main.py").write_text("The program will be written in this file") | |
# meta_p = p / META_DATA_REL_PATH | |
# meta_p.mkdir(parents=True) | |
# (meta_p / "file_selection.toml").write_text( | |
# """ | |
# [files] | |
# "main.py" = "selected" | |
# """ | |
# ) | |
# os.environ["GPTE_TEST_MODE"] = "True" | |
# simplified_main(str(p), "improve") | |
# DiskExecutionEnv(path=p) | |
# del os.environ["GPTE_TEST_MODE"] | |
# Runs gpt-engineer with lite mode and generates a project with only the main prompt. | |
def test_lite_mode_generate_project(self, tmp_path, monkeypatch): | |
p = tmp_path / "projects/example" | |
p.mkdir(parents=True) | |
(p / "prompt").write_text(prompt_text) | |
args = DefaultArgumentsMain( | |
str(p), lite_mode=True, llm_via_clipboard=True, no_execution=True | |
) | |
args() | |
# Runs gpt-engineer with clarify mode and generates a project after discussing the specification with the AI. | |
def test_clarify_mode_generate_project(self, tmp_path, monkeypatch): | |
p = tmp_path / "projects/example" | |
p.mkdir(parents=True) | |
(p / "prompt").write_text(prompt_text) | |
args = DefaultArgumentsMain( | |
str(p), clarify_mode=True, llm_via_clipboard=True, no_execution=True | |
) | |
args() | |
# Runs gpt-engineer with self-heal mode and generates a project after discussing the specification with the AI and self-healing the code. | |
def test_self_heal_mode_generate_project(self, tmp_path, monkeypatch): | |
p = tmp_path / "projects/example" | |
p.mkdir(parents=True) | |
(p / "prompt").write_text(prompt_text) | |
args = DefaultArgumentsMain( | |
str(p), self_heal_mode=True, llm_via_clipboard=True, no_execution=True | |
) | |
args() | |
def test_clarify_lite_improve_mode_generate_project(self, tmp_path, monkeypatch): | |
p = tmp_path / "projects/example" | |
p.mkdir(parents=True) | |
(p / "prompt").write_text(prompt_text) | |
args = DefaultArgumentsMain( | |
str(p), | |
improve_mode=True, | |
lite_mode=True, | |
clarify_mode=True, | |
llm_via_clipboard=True, | |
no_execution=True, | |
) | |
pytest.raises(typer.Exit, args) | |
# Tests the creation of a log file in improve mode. | |
class TestLoadPrompt: | |
# Load prompt from existing file in input_repo | |
def test_load_prompt_existing_file(self): | |
with tempfile.TemporaryDirectory() as tmp_dir: | |
input_repo = DiskMemory(tmp_dir) | |
prompt_file = "prompt.txt" | |
prompt_content = "This is the prompt" | |
input_repo[prompt_file] = prompt_content | |
improve_mode = False | |
image_directory = "" | |
result = load_prompt(input_repo, improve_mode, prompt_file, image_directory) | |
assert isinstance(result, Prompt) | |
assert result.text == prompt_content | |
assert result.image_urls is None | |
# Prompt file does not exist in input_repo, and improve_mode is False | |
def test_load_prompt_no_file_improve_mode_false(self): | |
with tempfile.TemporaryDirectory() as tmp_dir: | |
input_repo = DiskMemory(tmp_dir) | |
prompt_file = "prompt.txt" | |
improve_mode = False | |
image_directory = "" | |
with patch( | |
"builtins.input", | |
return_value="What application do you want gpt-engineer to generate?", | |
): | |
result = load_prompt( | |
input_repo, improve_mode, prompt_file, image_directory | |
) | |
assert isinstance(result, Prompt) | |
assert ( | |
result.text == "What application do you want gpt-engineer to generate?" | |
) | |
assert result.image_urls is None | |
# Prompt file is a directory | |
def test_load_prompt_directory_file(self): | |
with tempfile.TemporaryDirectory() as tmp_dir: | |
input_repo = DiskMemory(tmp_dir) | |
prompt_file = os.path.join(tmp_dir, "prompt") | |
os.makedirs(os.path.join(tmp_dir, prompt_file)) | |
improve_mode = False | |
image_directory = "" | |
with pytest.raises(ValueError): | |
load_prompt(input_repo, improve_mode, prompt_file, image_directory) | |
# Prompt file is empty | |
def test_load_prompt_empty_file(self): | |
with tempfile.TemporaryDirectory() as tmp_dir: | |
input_repo = DiskMemory(tmp_dir) | |
prompt_file = "prompt.txt" | |
input_repo[prompt_file] = "" | |
improve_mode = False | |
image_directory = "" | |
with patch( | |
"builtins.input", | |
return_value="What application do you want gpt-engineer to generate?", | |
): | |
result = load_prompt( | |
input_repo, improve_mode, prompt_file, image_directory | |
) | |
assert isinstance(result, Prompt) | |
assert ( | |
result.text == "What application do you want gpt-engineer to generate?" | |
) | |
assert result.image_urls is None | |
# image_directory does not exist in input_repo | |
def test_load_prompt_no_image_directory(self): | |
with tempfile.TemporaryDirectory() as tmp_dir: | |
input_repo = DiskMemory(tmp_dir) | |
prompt_file = "prompt.txt" | |
prompt_content = "This is the prompt" | |
input_repo[prompt_file] = prompt_content | |
improve_mode = False | |
image_directory = "tests/test_data" | |
shutil.copytree(image_directory, os.path.join(tmp_dir, image_directory)) | |
result = load_prompt(input_repo, improve_mode, prompt_file, image_directory) | |
assert isinstance(result, Prompt) | |
assert result.text == prompt_content | |
assert "mona_lisa.jpg" in result.image_urls | |
# def test_log_creation_in_improve_mode(self, tmp_path, monkeypatch): | |
# def improve_generator(): | |
# yield "y" | |
# while True: | |
# yield "n" # Subsequent responses | |
# | |
# gen = improve_generator() | |
# monkeypatch.setattr("builtins.input", lambda _: next(gen)) | |
# p = tmp_path / "projects/example" | |
# p.mkdir(parents=True) | |
# (p / "prompt").write_text(prompt_text) | |
# (p / "main.py").write_text("The program will be written in this file") | |
# meta_p = p / META_DATA_REL_PATH | |
# meta_p.mkdir(parents=True) | |
# (meta_p / "file_selection.toml").write_text( | |
# """ | |
# [files] | |
# "main.py" = "selected" | |
# """ | |
# ) | |
# os.environ["GPTE_TEST_MODE"] = "True" | |
# simplified_main(str(p), "improve") | |
# DiskExecutionEnv(path=p) | |
# assert ( | |
# (p / f".gpteng/memory/{DEBUG_LOG_FILE}").read_text().strip() | |
# == """UPLOADED FILES: | |
# ``` | |
# File: main.py | |
# 1 The program will be written in this file | |
# | |
# ``` | |
# PROMPT: | |
# Make a python program that writes 'hello' to a file called 'output.txt' | |
# CONSOLE OUTPUT:""" | |
# ) | |
# del os.environ["GPTE_TEST_MODE"] | |
# | |
# def test_log_creation_in_improve_mode_with_failing_diff( | |
# self, tmp_path, monkeypatch | |
# ): | |
# def improve_generator(): | |
# yield "y" | |
# while True: | |
# yield "n" # Subsequent responses | |
# | |
# def mock_salvage_correct_hunks( | |
# messages: List, files_dict: FilesDict, error_message: List | |
# ) -> FilesDict: | |
# # create a falling diff | |
# messages[ | |
# -1 | |
# ].content = """To create a Python program that writes 'hello' to a file called 'output.txt', we will need to perform the following steps: | |
# | |
# 1. Open the file 'output.txt' in write mode. | |
# 2. Write the string 'hello' to the file. | |
# 3. Close the file to ensure the data is written and the file is not left open. | |
# | |
# Here is the implementation of the program in the `main.py` file: | |
# | |
# ```diff | |
# --- main.py | |
# +++ main.py | |
# @@ -0,0 +1,9 @@ | |
# -create falling diff | |
# ``` | |
# | |
# This concludes a fully working implementation.""" | |
# # Call the original function with modified messages or define your own logic | |
# return salvage_correct_hunks(messages, files_dict, error_message) | |
# | |
# gen = improve_generator() | |
# monkeypatch.setattr("builtins.input", lambda _: next(gen)) | |
# monkeypatch.setattr( | |
# "gpt_engineer.core.default.steps.salvage_correct_hunks", | |
# mock_salvage_correct_hunks, | |
# ) | |
# p = tmp_path / "projects/example" | |
# p.mkdir(parents=True) | |
# (p / "prompt").write_text(prompt_text) | |
# (p / "main.py").write_text("The program will be written in this file") | |
# meta_p = p / META_DATA_REL_PATH | |
# meta_p.mkdir(parents=True) | |
# (meta_p / "file_selection.toml").write_text( | |
# """ | |
# [files] | |
# "main.py" = "selected" | |
# """ | |
# ) | |
# os.environ["GPTE_TEST_MODE"] = "True" | |
# simplified_main(str(p), "improve") | |
# DiskExecutionEnv(path=p) | |
# assert ( | |
# (p / f".gpteng/memory/{DEBUG_LOG_FILE}").read_text().strip() | |
# == """UPLOADED FILES: | |
# ``` | |
# File: main.py | |
# 1 The program will be written in this file | |
# | |
# ``` | |
# PROMPT: | |
# Make a python program that writes 'hello' to a file called 'output.txt' | |
# CONSOLE OUTPUT: | |
# Invalid hunk: @@ -0,0 +1,9 @@ | |
# -create falling diff | |
# | |
# Invalid hunk: @@ -0,0 +1,9 @@ | |
# -create falling diff""" | |
# ) | |
# del os.environ["GPTE_TEST_MODE"] | |
# | |
# def test_log_creation_in_improve_mode_with_unexpected_exceptions( | |
# self, tmp_path, monkeypatch | |
# ): | |
# def improve_generator(): | |
# yield "y" | |
# while True: | |
# yield "n" # Subsequent responses | |
# | |
# def mock_salvage_correct_hunks( | |
# messages: List, files_dict: FilesDict, error_message: List | |
# ) -> FilesDict: | |
# raise Exception("Mock exception in salvage_correct_hunks") | |
# | |
# gen = improve_generator() | |
# monkeypatch.setattr("builtins.input", lambda _: next(gen)) | |
# monkeypatch.setattr( | |
# "gpt_engineer.core.default.steps.salvage_correct_hunks", | |
# mock_salvage_correct_hunks, | |
# ) | |
# p = tmp_path / "projects/example" | |
# p.mkdir(parents=True) | |
# (p / "prompt").write_text(prompt_text) | |
# (p / "main.py").write_text("The program will be written in this file") | |
# meta_p = p / META_DATA_REL_PATH | |
# meta_p.mkdir(parents=True) | |
# (meta_p / "file_selection.toml").write_text( | |
# """ | |
# [files] | |
# "main.py" = "selected" | |
# """ | |
# ) | |
# os.environ["GPTE_TEST_MODE"] = "True" | |
# simplified_main(str(p), "improve") | |
# DiskExecutionEnv(path=p) | |
# assert ( | |
# (p / f".gpteng/memory/{DEBUG_LOG_FILE}").read_text().strip() | |
# == """UPLOADED FILES: | |
# ``` | |
# File: main.py | |
# 1 The program will be written in this file | |
# | |
# ``` | |
# PROMPT: | |
# Make a python program that writes 'hello' to a file called 'output.txt' | |
# CONSOLE OUTPUT: | |
# Error while improving the project: Mock exception in salvage_correct_hunks""" | |
# ) | |
# del os.environ["GPTE_TEST_MODE"] | |