diff --git a/lean/components/util/name_extraction.py b/lean/components/util/name_extraction.py index 4c058e86..2ccfee31 100644 --- a/lean/components/util/name_extraction.py +++ b/lean/components/util/name_extraction.py @@ -31,4 +31,10 @@ def convert_to_class_name(file_path: Path): :return: returns a valid class name """ from re import sub - return sub(f"[^a-zA-Z0-9]", "", "".join(map(_capitalize, file_path.name.split(" ")))) + class_name = sub(f"[^a-zA-Z0-9]", "", "".join(map(_capitalize, file_path.name.split(" ")))) + + # An identifier cannot be empty or start with a digit + if class_name == "" or class_name[0].isdigit(): + class_name = "_" + class_name + + return class_name diff --git a/tests/commands/test_create_project.py b/tests/commands/test_create_project.py index bc27c93f..a1c42f8a 100644 --- a/tests/commands/test_create_project.py +++ b/tests/commands/test_create_project.py @@ -157,6 +157,22 @@ def test_create_project_preserves_capitals_in_class_name() -> None: assert "class MyFIRSTProject(QCAlgorithm)" in file.read() +@pytest.mark.parametrize("name,class_name", [("2024 momentum", "_2024Momentum"), + ("123", "_123")]) +def test_create_project_creates_valid_class_name_when_name_starts_with_digit(name: str, class_name: str) -> None: + create_fake_lean_cli_directory() + + result = CliRunner().invoke(lean, ["create-project", "--language", "python", name]) + + assert result.exit_code == 0 + + with open(Path.cwd() / name / "main.py") as file: + content = file.read() + + assert f"class {class_name}(QCAlgorithm)" in content + compile(content, "main.py", "exec") + + def test_create_project_aborts_when_path_invalid() -> None: create_fake_lean_cli_directory()