Added bubble sort implementation and unit tests for it, refactored argument name "--tests-root" to "--test-root", and made some minor code improvements.

This commit is contained in:
afik.cohen 2023-10-23 15:09:27 -07:00
parent d9e487ebe9
commit 31d6c562d7
7 changed files with 64 additions and 36 deletions

View file

@ -0,0 +1,3 @@
def sorter(arr):
arr.sort()
return arr

View file

@ -0,0 +1,18 @@
import unittest
from code_to_optimize.bubble_sort import sorter
class TestPigLatin(unittest.TestCase):
def test_sort(self):
input = [5, 4, 3, 2, 1, 0]
output = sorter(input)
self.assertEqual(output, [0, 1, 2, 3, 4, 5])
input = [5.0, 4.0, 3.0, 2.0, 1.0, 0.0]
output = sorter(input)
self.assertEqual(output, [0.0, 1.0, 2.0, 3.0, 4.0, 5.0])
input = list(reversed(range(5000)))
output = sorter(input)
self.assertEqual(output, list(range(5000)))

View file

@ -51,14 +51,12 @@ def discover_tests_unittest(test_directory, project_root_path):
print("Didn't find tests for ", test_suite_2)
continue
for test in test_suite_2._tests:
m = re.search("(.*)\s\((.*)\.(.*)\)", str(test))
if not m:
continue
test_function, test_module, test_suite_name = (
m.group(1),
m.group(2),
m.group(3),
test._testMethodName,
test.__class__.__module__,
test.__class__.__qualname__,
)
test_module_path = test_module.replace(".", os.sep)
test_module_path = os.path.join(str(test_directory), test_module_path) + ".py"
if not os.path.exists(test_module_path):

View file

@ -50,7 +50,7 @@ def parse_args():
help="Path to the root of the project, from where your python modules are imported",
)
parser.add_argument(
"--tests-root",
"--test-root",
type=str,
)
parser.add_argument("--test-framework", choices=["pytest", "unittest"])
@ -59,14 +59,14 @@ def parse_args():
raise ValueError("If you specify a --function, you must specify the --file it is in")
pyproject_config = parse_config_file(args.config_file)
supported_keys = ["root", "tests_root", "test_framework"]
supported_keys = ["root", "test_root", "test_framework"]
for key in supported_keys:
if key in pyproject_config and getattr(args, key.replace("-", "_")) is None:
setattr(args, key.replace("-", "_"), pyproject_config[key])
args.root = os.path.realpath(args.root)
args.tests_root = os.path.realpath(args.tests_root)
args.test_root = os.path.realpath(args.test_root)
assert os.path.isdir(args.root), "--root must be a valid directory"
assert os.path.isdir(args.tests_root), "--tests_root must be a valid directory"
assert os.path.isdir(args.test_root), "--test_root must be a valid directory"
return args
@ -90,10 +90,10 @@ def main() -> None:
os.remove("/tmp/pr_comment_temp.txt")
try:
functions_to_tests_map = discover_unit_tests(
args.tests_root, args.root, test_framework=args.test_framework
args.test_root, args.root, test_framework=args.test_framework
)
for path in modified_functions:
if path.startswith(args.tests_root + os.sep):
if path.startswith(args.test_root + os.sep):
print("SKIPPING OPTIMIZING TEST FILE")
continue
# TODO: Sequence the functions one goes through intelligently. If we are optimizing f(g(x)), then we might want to first
@ -120,25 +120,31 @@ def main() -> None:
print("CODE TO OPTIMIZE", code_to_optimize)
module_path = get_module_name_from_file(path, args.root)
unique_original_test_files = set()
for i, tests_in_file in enumerate(
functions_to_tests_map[module_path + "." + function_name]
):
if tests_in_file.test_file in unique_original_test_files:
continue
new_test_path = (
os.path.splitext(tests_in_file.test_file)[0]
+ "__perfinstrumented"
+ os.path.splitext(tests_in_file.test_file)[1]
if not module_path + "." + function_name in functions_to_tests_map:
print(
f"Could not find any pre-existing tests for '{module_path + '.' + function_name}', "
f"will only use generated tests."
)
injected_test = inject_profiling_into_existing_test(
tests_in_file.test_file,
function_name,
args.root,
)
with open(new_test_path, "w") as f:
f.write(injected_test)
instrumented_unittests_created.add(new_test_path)
unique_original_test_files.add(tests_in_file.test_file)
else:
for i, tests_in_file in enumerate(
functions_to_tests_map.get(module_path + "." + function_name)
):
if tests_in_file.test_file in unique_original_test_files:
continue
new_test_path = (
os.path.splitext(tests_in_file.test_file)[0]
+ "__perfinstrumented"
+ os.path.splitext(tests_in_file.test_file)[1]
)
injected_test = inject_profiling_into_existing_test(
tests_in_file.test_file,
function_name,
args.root,
)
with open(new_test_path, "w") as f:
f.write(injected_test)
instrumented_unittests_created.add(new_test_path)
unique_original_test_files.add(tests_in_file.test_file)
new_tests = generate_tests(
source_code_being_tested=code_to_optimize,
function_name=function_name,
@ -149,7 +155,7 @@ def main() -> None:
)
if new_tests is None:
continue
generated_tests_path = get_test_file_path(args.tests_root, function_name, 0)
generated_tests_path = get_test_file_path(args.test_root, function_name, 0)
test_files_created.add(generated_tests_path)
with open(generated_tests_path, "w") as file:
file.write(new_tests)

View file

@ -1,4 +1,6 @@
import re
import os
import pickle
def filter_out_failed_test_timing(test_result, timing_result):

View file

@ -21,6 +21,7 @@ def generate_tests(
):
# TODO: Sometimes this recreates the original Class definition. This overrides and messes up the original
# class import. Remove the recreation of the class definition
print("Generating new tests...")
generated_test_source = regression_tests_from_function(
function_to_test=source_code_being_tested,
function_name=function_name,
@ -45,10 +46,10 @@ def generate_tests(
)
print("INSPIRED TESTS GENERATED\n", inspired_unit_tests)
unified_test_file = merge_unit_tests(unit_test_source, inspired_unit_tests, test_framework)
unified_test_file = merge_unit_tests(generated_test_source, inspired_unit_tests, test_framework)
module_node = ast.parse(generated_test_source)
print("REGRESSION TESTS SOURCE GENERATED", generated_test_source)
module_node = ast.parse(unified_test_file)
print("REGRESSION TESTS SOURCE GENERATED", unified_test_file)
auxiliary_function_names = [definition[0] for definition in function_dependencies]
new_module_node = InjectPerfAndLogging(
function_name,

View file

@ -6,7 +6,7 @@ authors = ["afik.cohen <afik@tacit.plus>", "Saurabh Misra <saurabh@tacit.plus>"]
readme = "README.md"
[tool.poetry.dependencies]
python = "^3.11"
python = ">=3.8, < 3.12"
openai = "^0.28.1"
unidiff = "^0.7.5"
pytest = "^7.3.1"
@ -15,9 +15,9 @@ libcst = "^1.1.0"
jedi = "^0.19.0"
tiktoken = "^0.5.1"
timeout-decorator = "^0.5.0"
pytest-timeout = "^2.1.0"
astunparse-fixed = {version = "^1.7.0", optional = true, python = ">=3.8.0,<3.9"}
tomli = {version = "^2.0.1" , optional = true, python = "<3.11"}
numpy = "1.26.1"
[tool.poetry.group.dev.dependencies]
ipython = "^8.12.0"