Added first tests #191
Some checks failed
Test before pr merge / test-lint (pull_request) Failing after 7s

This commit is contained in:
2025-12-10 23:20:25 +01:00
parent cc76227199
commit 17408d5cd2
76 changed files with 338 additions and 3334 deletions

View File

@@ -0,0 +1,9 @@
from cpl.core.console import Console
def main():
Console.write_line("Hello, World!")
if __name__ == "__main__":
main()

View File

@@ -5,6 +5,7 @@ from pathlib import Path
import click
from cpl.cli.cli import cli
from cpl.cli.model.project import Project
from cpl.cli.utils.structure import Structure
from cpl.cli.utils.venv import get_venv_python, ensure_venv
from cpl.core.configuration import Configuration
@@ -21,35 +22,42 @@ def run(project: str, args: list[str], dev: bool, verbose: bool):
if project is not None:
project_path = (Path("./") / project).resolve().absolute()
project = Structure.get_project_by_name_or_path(str(project_path))
if project.main is None:
project = Structure.get_project_by_name_or_path(project_path)
is_unittest = project.type == "unittest"
if not is_unittest and project.main is None:
Console.error(f"Project {project.name} has no executable")
return
path = str(Path(project.path).parent.resolve().absolute())
executable = project.main
if not dev:
dist_path = Path(project.path).parent / "dist"
if Configuration.get("workspace") is not None:
dist_path = Path(Configuration.get("workspace").path).parent / "dist"
dist_path = Path(dist_path).resolve().absolute()
if verbose:
Console.write_line(f"Creating dist folder at {dist_path}...")
os.makedirs(dist_path, exist_ok=True)
project.do_build(dist_path, verbose)
path = dist_path / project.name
main = project.main.replace(project.directory, "").lstrip("/\\")
executable = path / main
python = str(get_venv_python(ensure_venv()).absolute())
Console.write_line(f"\nStarting project {project.name}...")
if verbose:
Console.write_line(f" with args {args}...")
Console.write_line("\n\n")
subprocess.run([python, executable, *args], cwd=path)
path = str(Path(project.path).parent.resolve().absolute())
python = str(get_venv_python(ensure_venv()).absolute())
if is_unittest:
subprocess.run([python, "-m", "pytest", path], cwd=path)
return
subprocess.run([python, _get_executable(project, dev, verbose), *args], cwd=path)
def _get_executable(project: Project, dev: bool, verbose: bool) -> str:
if dev:
return project.main
dist_path = Path(project.path).parent / "dist"
if Configuration.get("workspace") is not None:
dist_path = Path(Configuration.get("workspace").path).parent / "dist"
dist_path = Path(dist_path).resolve().absolute()
if verbose:
Console.write_line(f"Creating dist folder at {dist_path}...")
os.makedirs(dist_path, exist_ok=True)
project.do_build(dist_path, verbose)
path = dist_path / project.name
main = project.main.replace(project.directory, "").lstrip("/\\")
return str(path / main)

View File

@@ -1,4 +1,4 @@
PROJECT_TYPES = ["console", "web", "graphql", "library", "service"]
PROJECT_TYPES = ["console", "web", "graphql", "library", "service", "unittest"]
PROJECT_TYPES_SHORT = [x[0] for x in PROJECT_TYPES]
PIP_URL = "https://git.sh-edraft.de/api/packages/sh-edraft.de/pypi/simple/"

View File

@@ -33,10 +33,11 @@ class Workspace(CPLStructureModel):
self._actual_projects = []
self._project_names = []
for project in projects:
if Path(project).is_dir() or not Path(project).exists():
p_path = (Path(path).parent / Path(project)).resolve().absolute()
if p_path.is_dir() or not p_path.exists():
raise ValueError(f"Project path '{project}' does not exist or is a directory.")
p = Project.from_file(project)
p = Project.from_file(p_path)
self._actual_projects.append(p)
self._project_names.append(p.name)

View File

@@ -68,7 +68,7 @@ class Structure:
pyproject_path.write_text(content)
@staticmethod
def get_project_by_name_or_path(project: str) -> Project:
def get_project_by_name_or_path(project: str | Path) -> Project:
if project is None:
raise ValueError("Project name or path must be provided.")
@@ -86,9 +86,10 @@ class Structure:
if workspace is None:
raise RuntimeError("No workspace found. Please run 'cpl init workspace' first.")
project_name = project.name if isinstance(project, Path) else project
for p in workspace.actual_projects:
if p.name == project:
return Project.from_file(Path(p.path))
if p.name == project_name:
return Project.from_file((Path(workspace.path).parent / Path(p.path)).resolve())
if not path.is_dir() and not path.is_file():
raise ValueError(f"Unknown project {project}")

View File

@@ -1,3 +1,4 @@
from types import NoneType
from typing import Any
@@ -6,7 +7,17 @@ class Number:
@staticmethod
def is_number(value: Any) -> bool:
"""Check if the value is a number (int or float)."""
return isinstance(value, (int, float, complex))
if isinstance(value, (bool, NoneType)):
return False
if isinstance(value, (int, float, complex)):
return True
try:
Number.to_number(value)
return True
except (ValueError, TypeError):
return False
@staticmethod
def to_number(value: Any) -> int | float | complex:

View File

@@ -18,14 +18,15 @@ class String:
String converted to CamelCase
"""
parts = re.split(r"[^a-zA-Z0-9]+", s.strip())
if re.search(r'[_\-\s]', s):
words = re.split(r'[_\-\s]+', s)
else:
words = re.findall(r'[A-Z]?[a-z]+|[A-Z]+(?=[A-Z]|$)', s)
parts = [p for p in parts if p]
if not parts:
return ""
return parts[0].lower() + "".join(word.capitalize() for word in parts[1:])
words = [w.lower() for w in words if w]
if not words:
return ''
return words[0] + ''.join(w.capitalize() for w in words[1:])
@staticmethod
def to_pascal_case(s: str) -> str:
@@ -39,14 +40,12 @@ class String:
String converted to PascalCase
"""
parts = re.split(r"[^a-zA-Z0-9]+", s.strip())
if re.search(r'[_\-\s]', s):
words = re.split(r'[_\-\s]+', s)
else:
words = re.findall(r'[A-Z]?[a-z]+|[A-Z]+(?=[A-Z]|$)', s)
parts = [p for p in parts if p]
if not parts:
return ""
return "".join(word.capitalize() for word in parts)
return ''.join(word.capitalize() for word in words if word)
@staticmethod
def to_snake_case(chars: str) -> str: