Autodetect test dir and test framework, also fix black target version

This commit is contained in:
afik.cohen 2024-01-24 15:51:17 -08:00
parent 7b343b4ed6
commit dd7240775a
3 changed files with 67 additions and 18 deletions

View file

@ -1,3 +1,4 @@
import ast
import click
import os
import re
@ -118,24 +119,17 @@ def collect_setup_info(setup_info: dict[str, str]):
curdir = os.getcwd()
subdirs = [d for d in next(os.walk("."))[1] if not d.startswith(".")]
subdir_options = (
f' ({", ".join([dir for dir in subdirs if dir != "tests"])})' if subdirs else ""
)
source_dir = click.prompt(
"What's your project's source directory? I'll only optimize code in this directory.",
type=click.Choice(
[dir for dir in subdirs if dir != "tests"],
),
show_choices=True,
f"What's your project's source directory? I'll only optimize code in this directory.{subdir_options}",
default=project_name if project_name in subdirs else subdirs[0] if subdirs else ".",
)
setup_info["project_root"] = source_dir
ph("cli-project-root-provided")
setup_info["test_framework"] = click.prompt(
"Which test framework do you use?",
type=click.Choice(["pytest", "unittest"]),
show_choices=True,
)
ph("cli-test-framework-provided", {"test_framework": setup_info["test_framework"]})
# Discover test directory
default_tests_subdir = "tests"
if default_tests_subdir in subdirs:
@ -153,16 +147,30 @@ def collect_setup_info(setup_info: dict[str, str]):
if tests_root == "":
tests_root = os.path.join(curdir, default_tests_subdir)
os.mkdir(tests_root)
click.echo(f"✅ Created directory {tests_root}/")
else:
if not os.path.isdir(os.path.join(curdir, default_tests_subdir)):
tests_root = os.path.join(curdir, default_tests_subdir)
if not os.path.isdir(tests_root):
click.echo(
f"No directory exists at {os.path.join(curdir, default_tests_subdir)}, please enter a valid directory path."
f"{tests_root} doesn't exist, please enter a valid tests directory."
)
continue
break
setup_info["tests_root"] = os.path.relpath(tests_root, curdir)
ph("cli-tests-root-provided")
# Autodiscover test framework
test_framework = detect_test_framework(curdir, tests_root)
autodetected = f" (autodetected: {test_framework})" if test_framework else ""
setup_info["test_framework"] = click.prompt(
f"Which test framework do you use?" + autodetected,
type=click.Choice(["pytest", "unittest"]),
show_choices=True,
default=test_framework,
)
ph("cli-test-framework-provided", {"test_framework": setup_info["test_framework"]})
# Ask for paths to ignore and update the setup_info dictionary
# ignore_paths_input = click.prompt("Are there any paths CodeFlash should ignore? (comma-separated, no spaces)",
# default='', show_default=False)
@ -171,6 +179,47 @@ def collect_setup_info(setup_info: dict[str, str]):
setup_info["ignore_paths"] = ignore_paths
def detect_test_framework(curdir, tests_root) -> Optional[str]:
test_framework = None
pytest_files = ["pytest.ini", "pyproject.toml", "tox.ini", "setup.cfg"]
pytest_config_patterns = {
"pytest.ini": r"\[pytest\]",
"pyproject.toml": r"\[tool\.pytest\.ini_options\]",
"tox.ini": r"\[pytest\]",
"setup.cfg": r"\[tool:pytest\]",
}
for pytest_file in pytest_files:
file_path = os.path.join(curdir, pytest_file)
if os.path.exists(file_path):
with open(file_path, "r") as file:
contents = file.read()
if re.search(pytest_config_patterns[pytest_file], contents):
test_framework = "pytest"
break
test_framework = "pytest"
else:
# Check if any python files contain a class that inherits from unittest.TestCase
for filename in os.listdir(tests_root):
if filename.endswith(".py"):
with open(os.path.join(tests_root, filename), "r") as file:
contents = file.read()
node = ast.parse(contents)
if any(
isinstance(item, ast.ClassDef)
and any(
isinstance(base, ast.Attribute)
and base.attr == "TestCase"
or isinstance(base, ast.Name)
and base.id == "TestCase"
for base in item.bases
)
for item in node.body
):
test_framework = "unittest"
break
return test_framework
def check_for_toml_or_setup_file() -> Optional[str]:
curdir = os.getcwd()
pyproject_toml_path = os.path.join(curdir, "pyproject.toml")
@ -222,7 +271,7 @@ def check_for_toml_or_setup_file() -> Optional[str]:
else:
click.echo(
f"❌ I couldn't find a pyproject.toml or a setup.py in the current directory ({curdir}).\n"
"Please make sure you're running codeflash init from your project root directory.\n"
"Please make sure you're running codeflash init from your project's root directory.\n"
"See https://app.codeflash.ai/app/getting-started for more details!"
)
ph("cli-no-pyproject-toml-or-setup-py")

View file

@ -1,3 +1,3 @@
# These version placeholders will be replaced by poetry-dynamic-versioning during `poetry build`.
__version__ = "0.1.2"
__version_tuple__ = (0, 1, 2)
__version__ = "0.1.3"
__version_tuple__ = (0, 1, 3)

View file

@ -57,7 +57,7 @@ warn_required_dynamic_aliases = true
[tool.black]
line-length = 100
target-version = ['py311']
target-version = ['py312']
[build-system]
requires = ["poetry-core>=1.0.0", "poetry-dynamic-versioning>=1.2.0,<2.0.0"]