From 500d7469db68fe45b3611fb226bc3c28c93b252e Mon Sep 17 00:00:00 2001 From: S4NKALP Date: Mon, 11 May 2026 00:17:40 +0545 Subject: [PATCH] feat(src/djinit): add pytest integration support New Features: - Generate pytest configuration files (pytest.ini, conftest.py) when `use_pytest` is enabled. - Introduce UI prompt to optionally include pytest. Enhancements: - Update metadata and context dictionaries to propagate `use_pytest`. - Register pytest file creation in the project setup pipeline. - Reflect pytest inclusion in UI success messages. Bug Fixes: None. --- src/djinit/core/types.py | 2 ++ src/djinit/creators/files.py | 27 ++++++++++++++++++++++++++- src/djinit/creators/setup.py | 6 ++++++ src/djinit/ui/input.py | 13 +++++++++++++ 4 files changed, 47 insertions(+), 1 deletion(-) diff --git a/src/djinit/core/types.py b/src/djinit/core/types.py index 68aa347..b472e9a 100644 --- a/src/djinit/core/types.py +++ b/src/djinit/core/types.py @@ -19,6 +19,7 @@ class ProjectMetadata: use_htmx: bool = False use_docker: bool = False use_vite: bool = False + use_pytest: bool = False predefined_structure: bool = False unified_structure: bool = False single_structure: bool = False @@ -37,6 +38,7 @@ class ProjectMetadata: "use_htmx": self.use_htmx, "use_docker": self.use_docker, "use_vite": self.use_vite, + "use_pytest": self.use_pytest, "predefined_structure": self.predefined_structure, "unified_structure": self.unified_structure, "single_structure": self.single_structure, diff --git a/src/djinit/creators/files.py b/src/djinit/creators/files.py index 1448032..e2e7bf8 100644 --- a/src/djinit/creators/files.py +++ b/src/djinit/creators/files.py @@ -88,10 +88,11 @@ class FileCreator(BaseService): for name in base_settings_context["app_names"] ] - # Add Tailwind, HTMX, and Vite to context + # Add Tailwind, HTMX, Vite, and pytest to context base_settings_context["use_tailwind"] = self.metadata.get("use_tailwind", False) base_settings_context["use_htmx"] = self.metadata.get("use_htmx", False) base_settings_context["use_vite"] = self.metadata.get("use_vite", False) + base_settings_context["use_pytest"] = self.metadata.get("use_pytest", False) for filename, context in [ ("base.py", base_settings_context), @@ -142,6 +143,9 @@ class FileCreator(BaseService): "use_tailwind": self.metadata.get("use_tailwind", False), "use_htmx": self.metadata.get("use_htmx", False), "use_vite": self.metadata.get("use_vite", False), + "use_pytest": self.metadata.get("use_pytest", False), + "module_name": self.module_name, + "app_names": self.app_names, } self._render_and_create_file( "requirements.txt", @@ -425,6 +429,7 @@ class FileCreator(BaseService): "use_htmx": self.metadata.get("use_htmx", False), "use_docker": self.metadata.get("use_docker", False), "use_vite": self.metadata.get("use_vite", False), + "use_pytest": self.metadata.get("use_pytest", False), }, "cicd": { "github": self.metadata.get("use_github_actions", False), @@ -513,3 +518,23 @@ class FileCreator(BaseService): CommonUtils.create_file_from_template( index_css_path, "project/frontend/src/index.css-tpl", context, "Created frontend/src/index.css" ) + + def create_pytest_files(self) -> None: + """Create pytest configuration files.""" + context = { + "project_name": self.project_name, + "module_name": self.module_name, + "app_names": self.app_names or [], + } + self._render_and_create_file( + "pytest.ini", + "project/pytest.ini-tpl", + context, + "Created pytest.ini configuration", + ) + self._render_and_create_file( + "conftest.py", + "project/conftest.py-tpl", + context, + "Created conftest.py with pytest fixtures", + ) diff --git a/src/djinit/creators/setup.py b/src/djinit/creators/setup.py index 01010d9..42cced2 100644 --- a/src/djinit/creators/setup.py +++ b/src/djinit/creators/setup.py @@ -79,6 +79,7 @@ class SetupCreator: ("Creating CI/CD pipelines", self._create_cicd_pipelines), ("Creating Docker files", self._create_docker_files), ("Creating Vite/React files", self._create_vite_files), + ("Creating pytest files", self._create_pytest_files), ] ) @@ -130,3 +131,8 @@ class SetupCreator: if self.metadata.get("use_vite", False): self.file_creator.create_vite_files() UIFormatter.print_success("Created Vite/React files successfully!") + + def _create_pytest_files(self) -> None: + if self.metadata.get("use_pytest", False): + self.file_creator.create_pytest_files() + UIFormatter.print_success("Created pytest files successfully!") diff --git a/src/djinit/ui/input.py b/src/djinit/ui/input.py index 2d38686..76cc968 100644 --- a/src/djinit/ui/input.py +++ b/src/djinit/ui/input.py @@ -27,6 +27,7 @@ class StructureOptions(TypedDict): use_htmx: bool use_docker: bool use_vite: bool + use_pytest: bool use_github: bool use_gitlab: bool @@ -187,6 +188,9 @@ class InputCollector: def get_vite_choice(self) -> bool: return UIFormatter.confirm("Include Vite/React? (via django-vite)", default=True) + def get_pytest_choice(self) -> bool: + return UIFormatter.confirm("Include pytest testing framework? (pytest, coverage)", default=True) + def _get_structure_metadata(self, options: StructureOptions) -> Tuple[str, str, list[str], dict]: """Helper method to generate metadata dictionary.""" project_dir = options["project_dir"] @@ -213,6 +217,7 @@ class InputCollector: use_htmx=options.get("use_htmx", False), use_docker=options.get("use_docker", False), use_vite=options.get("use_vite", False), + use_pytest=options.get("use_pytest", False), predefined_structure=options["predefined"], unified_structure=options["unified"], single_structure=options["single"], @@ -280,6 +285,9 @@ def get_user_input() -> Tuple[str, str, str, list, dict]: # Step 5: Vite/React use_vite = collector.get_vite_choice() + # Step 6: pytest + use_pytest = collector.get_pytest_choice() + # Step 3: Django Apps (Standard only) nested = False nested_dir = None @@ -307,6 +315,7 @@ def get_user_input() -> Tuple[str, str, str, list, dict]: use_htmx=use_htmx, use_docker=use_docker, use_vite=use_vite, + use_pytest=use_pytest, ) return project_dir, project_name, app_names[0], app_names, metadata.to_dict() else: @@ -322,6 +331,7 @@ def get_user_input() -> Tuple[str, str, str, list, dict]: use_htmx=use_htmx, use_docker=use_docker, use_vite=use_vite, + use_pytest=use_pytest, use_github=use_github, use_gitlab=use_gitlab, ) @@ -366,6 +376,9 @@ def confirm_setup(project_dir: str, project_name: str, app_names: list, metadata use_vite = "Yes" if metadata.get("use_vite", False) else "No" console.print(f"[{UIColors.HIGHLIGHT}]Vite/React:[/{UIColors.HIGHLIGHT}] {use_vite}") + use_pytest = "Yes" if metadata.get("use_pytest", False) else "No" + console.print(f"[{UIColors.HIGHLIGHT}]pytest:[/{UIColors.HIGHLIGHT}] {use_pytest}") + console.print() UIFormatter.print_separator() console.print()