diff --git a/pyproject.toml b/pyproject.toml index 4029a97..6190bdd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,13 +7,13 @@ dependencies = [] [project.optional-dependencies] dev = [ - "pytest>=9.0", - "pytest-cov>=7.0", - "pytest-mock>=3.0", - "cookiecutter>=2.7", - "tox>=4.0", - "pyyaml>=6.0", - "ruff>=0.9", + "pytest>=9.1.1", + "pytest-cov>=7.1.0", + "pytest-mock>=3.15.1", + "cookiecutter>=2.7.1", + "tox>=4.56.1", + "pyyaml>=6.0.3", + "ruff>=0.15.20", ] [tool.uv] diff --git a/test-requirements.txt b/test-requirements.txt index b62e382..eb47949 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -1,7 +1,7 @@ # Test dependencies for cookiecutter template -pytest>=9.0.3 +pytest>=9.1.1 cookiecutter>=2.7.1 pytest-cov>=7.1.0 pytest-mock>=3.15.1 -tox>=4.53.0 -pyyaml>=6.0 +tox>=4.56.1 +pyyaml>=6.0.3 diff --git a/tests/quick_test.py b/tests/quick_test.py index 3d5aa0b..7194487 100644 --- a/tests/quick_test.py +++ b/tests/quick_test.py @@ -97,9 +97,7 @@ def main(): python_files = [] template_files = 0 - for root, dirs, files in os.walk( - os.path.join(template_dir, "{{ cookiecutter.project_slug }}") - ): + for root, dirs, files in os.walk(os.path.join(template_dir, "{{ cookiecutter.project_slug }}")): for file in files: if file.endswith(".py"): python_files.append(file) @@ -109,9 +107,7 @@ def main(): if "{{ cookiecutter." in content: template_files += 1 - print( - f" ✓ Found {len(python_files)} Python files ({template_files} with template variables)" - ) + print(f" ✓ Found {len(python_files)} Python files ({template_files} with template variables)") # Summary print("\n" + "=" * 60) diff --git a/tests/run_tests.py b/tests/run_tests.py index f03f7d2..2dd4891 100755 --- a/tests/run_tests.py +++ b/tests/run_tests.py @@ -39,9 +39,7 @@ def run_basic_validation(): result = subprocess.run( [ python_exe, - os.path.join( - os.path.dirname(os.path.dirname(__file__)), "validate_template.py" - ), + os.path.join(os.path.dirname(os.path.dirname(__file__)), "validate_template.py"), ], capture_output=True, text=True, diff --git a/tests/test_cookiecutter.py b/tests/test_cookiecutter.py index 1ea468f..95ad535 100644 --- a/tests/test_cookiecutter.py +++ b/tests/test_cookiecutter.py @@ -93,9 +93,7 @@ def test_cookiecutter_json_structure(self, template_dir): ] for field in required_fields: - assert field in config, ( - f"Required field '{field}' missing from cookiecutter.json" - ) + assert field in config, f"Required field '{field}' missing from cookiecutter.json" # Check that project_slug uses proper template logic assert "{{" in config["project_slug"], ( @@ -171,9 +169,7 @@ def test_accounts_module_structure(self, template_dir): for file_path in expected_files: full_path = os.path.join(accounts_dir, file_path) - assert os.path.exists(full_path), ( - f"Expected accounts file missing: {file_path}" - ) + assert os.path.exists(full_path), f"Expected accounts file missing: {file_path}" def test_post_gen_hook_exists(self, template_dir): """Test that post-generation hook exists and is executable.""" @@ -219,9 +215,7 @@ def test_django_settings_structure(self, template_dir): content = f.read() # Check for Django-specific settings if settings_file == "base.py": - assert "INSTALLED_APPS" in content, ( - "base.py should contain INSTALLED_APPS" - ) + assert "INSTALLED_APPS" in content, "base.py should contain INSTALLED_APPS" assert "MIDDLEWARE" in content, "base.py should contain MIDDLEWARE" assert "DATABASES" in content, "base.py should contain DATABASES" @@ -246,9 +240,7 @@ def test_oauth2_package_structure(self, template_dir): with open(file_path, "r") as f: content = f.read() - assert content.strip(), ( - f"OAuth2 file should not be empty: {oauth2_file}" - ) + assert content.strip(), f"OAuth2 file should not be empty: {oauth2_file}" # Check for specific content based on file if oauth2_file == "providers.py": @@ -262,9 +254,7 @@ def test_oauth2_package_structure(self, template_dir): "providers.py should contain Facebook provider" ) elif oauth2_file == "api.py": - assert "@router" in content, ( - "api.py should contain router decorators" - ) + assert "@router" in content, "api.py should contain router decorators" assert "Router" in content, "api.py should import Router" def test_api_package_structure(self, template_dir): @@ -289,9 +279,7 @@ def test_api_package_structure(self, template_dir): assert "register" in content.lower(), ( "auth.py should contain register functionality" ) - assert "login" in content.lower(), ( - "auth.py should contain login functionality" - ) + assert "login" in content.lower(), "auth.py should contain login functionality" elif api_file == "users.py": assert "router" in content.lower(), "users.py should define router" elif api_file == "__init__.py": @@ -333,12 +321,8 @@ def test_docker_configuration(self, template_dir): # Check Dockerfile content with open(dockerfile_path, "r") as f: dockerfile_content = f.read() - assert "FROM python" in dockerfile_content, ( - "Dockerfile should use Python base image" - ) - assert "uv sync" in dockerfile_content, ( - "Dockerfile should use uv sync" - ) + assert "FROM python" in dockerfile_content, "Dockerfile should use Python base image" + assert "uv sync" in dockerfile_content, "Dockerfile should use uv sync" assert "COPY pyproject.toml" in dockerfile_content, ( "Dockerfile should copy pyproject.toml" ) @@ -346,27 +330,19 @@ def test_docker_configuration(self, template_dir): # Check docker-compose content with open(compose_path, "r") as f: compose_content = f.read() - assert "version:" in compose_content, ( - "docker-compose.yml should have version" - ) - assert "services:" in compose_content, ( - "docker-compose.yml should have services" - ) + assert "version:" in compose_content, "docker-compose.yml should have version" + assert "services:" in compose_content, "docker-compose.yml should have services" def test_manage_py_exists(self, template_dir): """Test that manage.py exists and has correct content.""" - manage_path = os.path.join( - template_dir, "{{ cookiecutter.project_slug }}/manage.py" - ) + manage_path = os.path.join(template_dir, "{{ cookiecutter.project_slug }}/manage.py") assert os.path.exists(manage_path), "manage.py should exist" with open(manage_path, "r") as f: content = f.read() assert "#!/usr/bin/env python" in content, "manage.py should have shebang" - assert "django.core.management" in content, ( - "manage.py should import Django management" - ) + assert "django.core.management" in content, "manage.py should import Django management" assert "execute_from_command_line" in content, ( "manage.py should use execute_from_command_line" ) @@ -378,9 +354,7 @@ def test_manage_py_exists(self, template_dir): class TestCookiecutterGeneration: """Test the actual cookiecutter generation process.""" - def test_cookiecutter_generation_process( - self, temp_dir, template_dir, test_context - ): + def test_cookiecutter_generation_process(self, temp_dir, template_dir, test_context): """Test that cookiecutter can generate a project successfully.""" pytest.importorskip("cookiecutter") from cookiecutter.main import cookiecutter diff --git a/tox.ini b/tox.ini index 0a9bcaf..9719c96 100644 --- a/tox.ini +++ b/tox.ini @@ -29,14 +29,14 @@ commands = [testenv:lint] deps = - ruff>=0.9.0 + ruff>=0.15.20 commands = ruff check . ruff format --check . [testenv:format] deps = - ruff>=0.9.0 + ruff>=0.15.20 commands = ruff check --fix . ruff format . @@ -44,7 +44,7 @@ commands = [testenv:coverage] deps = -r{toxinidir}/test-requirements.txt - coverage>=7.0.0 + coverage>=7.14.3 commands = coverage run -m pytest tests/test_cookiecutter.py coverage report -m diff --git a/validate_template.py b/validate_template.py index 57296f9..b5900e0 100644 --- a/validate_template.py +++ b/validate_template.py @@ -166,17 +166,13 @@ def test_python_files_syntax(self): if syntax_errors: assert False, f"Syntax errors found in non-template files: {syntax_errors}" - print( - f"✓ All {len(python_files)} Python files have valid syntax (template files skipped)" - ) + print(f"✓ All {len(python_files)} Python files have valid syntax (template files skipped)") return True def test_requirements_files_content(self): """Test that requirements or pyproject.toml files have valid content.""" # Check pyproject.toml exists (primary dependency file) - project_dir = os.path.join( - self.template_dir, "{{ cookiecutter.project_slug }}" - ) + project_dir = os.path.join(self.template_dir, "{{ cookiecutter.project_slug }}") pyproject_path = os.path.join(project_dir, "pyproject.toml") assert os.path.exists(pyproject_path), "pyproject.toml should exist" with open(pyproject_path, "r") as f: @@ -198,12 +194,8 @@ def test_docker_files_content(self): assert os.path.exists(dockerfile_path), "Dockerfile should exist" with open(dockerfile_path, "r") as f: dockerfile_content = f.read() - assert "FROM python" in dockerfile_content, ( - "Dockerfile should use Python base image" - ) - assert "uv sync" in dockerfile_content, ( - "Dockerfile should use uv sync" - ) + assert "FROM python" in dockerfile_content, "Dockerfile should use Python base image" + assert "uv sync" in dockerfile_content, "Dockerfile should use uv sync" assert "RUN pip install" not in dockerfile_content, ( "uv migration complete - should not use pip install" ) @@ -212,15 +204,9 @@ def test_docker_files_content(self): assert os.path.exists(compose_path), "docker-compose.yml should exist" with open(compose_path, "r") as f: compose_content = f.read() - assert "version:" in compose_content, ( - "docker-compose.yml should have version" - ) - assert "services:" in compose_content, ( - "docker-compose.yml should have services" - ) - assert "web:" in compose_content, ( - "docker-compose.yml should have web service" - ) + assert "version:" in compose_content, "docker-compose.yml should have version" + assert "services:" in compose_content, "docker-compose.yml should have services" + assert "web:" in compose_content, "docker-compose.yml should have web service" print("✓ Docker files have valid content") @@ -303,9 +289,7 @@ def test_comprehensive_tests_exist(self): "OAuth2APITestCase", ] - missing_classes = [ - cls for cls in required_test_classes if cls not in content - ] + missing_classes = [cls for cls in required_test_classes if cls not in content] assert not missing_classes, f"Missing test classes: {missing_classes}" # Check for test methods diff --git a/{{ cookiecutter.project_slug }}/pyproject.toml b/{{ cookiecutter.project_slug }}/pyproject.toml index 03f3c92..e371fe4 100644 --- a/{{ cookiecutter.project_slug }}/pyproject.toml +++ b/{{ cookiecutter.project_slug }}/pyproject.toml @@ -9,21 +9,21 @@ dependencies = [ "psycopg[binary]>=3.2,<4.0", "python-decouple>=3.8,<4.0", "dj-database-url>=3.1,<4.0", - "gunicorn>=25.3,<26.0", + "gunicorn>=26.0,<27.0", "django-guardian>=3.3,<4.0", "djangorestframework-simplejwt>=5.5,<6.0", - "django-redis>=6.0,<7.0", + "django-redis>=7.0,<8.0", "whitenoise[brotli]>=6.12,<7.0", {% if cookiecutter.use_celery == 'y' %} "celery>=5.6,<6.0", - "redis>=7.4,<8.0", + "redis>=8.0,<9.0", "django-celery-beat>=2.9,<3.0", "django-celery-results>=2.6,<3.0", {% endif %} {% if cookiecutter.include_oauth2 == 'y' %} "django-oauth-toolkit>=3.2,<4.0", "requests-oauthlib>=2.0,<3.0", - "social-auth-app-django>=5.7,<6.0", + "social-auth-app-django>=6.0,<7.0", {% endif %} {% if cookiecutter.include_sentry == 'y' %} "sentry-sdk[django]>=2.58,<3.0", @@ -33,14 +33,14 @@ dependencies = [ [project.optional-dependencies] dev = [ "django-extensions>=4.1,<5.0", - "django-debug-toolbar>=6.3,<7.0", + "django-debug-toolbar>=7.0,<8.0", "Werkzeug>=3.1,<4.0", - "pytest>=9.0,<10.0", + "pytest>=9.1.1,<10.0", "pytest-django>=4.12,<5.0", "pytest-cov>=7.1,<8.0", - "ruff>=0.9,<1.0", - "pre-commit>=4.0,<5.0", - "coverage>=7.0,<8.0", + "ruff>=0.15.20,<1.0", + "pre-commit>=4.6,<5.0", + "coverage>=7.14.3,<8.0", ] prod = [ "whitenoise[brotli]>=6.12,<7.0",