feat(app_generator): support nested Django app structures and custom app module paths

This commit is contained in:
sankalp committed 2025-10-29 11:14:09 +05:45
1 parent b78ba6d308
commit 0df1bf1224
30 files changed
+109 -765

No files matched your search

+108 -9
View File
@@ -5,11 +5,12 @@ Handles creation of Django apps and updating settings.
import os
import subprocess
import sys
from typing import Optional
from src.scripts.console_ui import UIFormatter
from src.scripts.template_engine import template_engine
from src.utils import create_file_with_content
from src.utils import change_cwd, create_file_with_content
class AppManager:
@@ -45,13 +46,42 @@ class AppManager:
return os.path.exists(self.manage_py_path)
def _app_exists(self) -> bool:
app_path = os.path.join(self.current_dir, self.app_name)
# Detect project structure to check in correct location
is_nested, nested_dir, apps_base_dir = self._detect_project_structure()
app_path = os.path.join(apps_base_dir, self.app_name)
return os.path.exists(app_path)
def _create_django_app(self) -> bool:
result = subprocess.run(["django-admin", "startapp", self.app_name], capture_output=True, text=True, check=True)
# Detect project structure
is_nested, nested_dir, apps_base_dir = self._detect_project_structure()
# manage.py is always in the project root (current_dir), not in the project directory
manage_py_path = os.path.join(self.current_dir, "manage.py")
if not os.path.exists(manage_py_path):
UIFormatter.print_error("Could not find manage.py file in project root")
return False
# Create app in the correct location
with change_cwd(apps_base_dir):
UIFormatter.print_info(f"Creating app '{self.app_name}' in directory: {os.getcwd()}")
try:
# Use django-admin instead of manage.py to avoid dependency issues
result = subprocess.run(
["django-admin", "startapp", self.app_name],
capture_output=True,
text=True,
check=True
)
except subprocess.CalledProcessError as e:
UIFormatter.print_error(f"Failed to create app '{self.app_name}': {e}")
if e.stderr:
UIFormatter.print_error(f"Error details: {e.stderr}")
if e.stdout:
UIFormatter.print_info(f"Output: {e.stdout}")
return False
UIFormatter.print_success(f"Created Django app '{self.app_name}'")
UIFormatter.print_success(f"Created Django app '{self.app_name}' in {apps_base_dir}")
return True
def _add_to_installed_apps(self) -> bool:
@@ -65,11 +95,38 @@ class AppManager:
UIFormatter.print_error("Could not find base.py settings file")
return False
UIFormatter.print_info(f"Found base.py at: {base_settings_path}")
with open(base_settings_path) as f:
content = f.read()
if f'"{self.app_name}"' in content or f"'{self.app_name}'" in content:
UIFormatter.print_info(f"App '{self.app_name}' is already in INSTALLED_APPS")
# Detect project structure to determine the correct app module path
is_nested, nested_dir, apps_base_dir = self._detect_project_structure()
# Determine the correct module path for the app
if is_nested and nested_dir:
app_module_path = f"{nested_dir}.{self.app_name}"
else:
app_module_path = self.app_name
UIFormatter.print_info(f"App module path: {app_module_path}")
# Check if app is already in USER_DEFINED_APPS section specifically
lines = content.split("\n")
in_user_apps = False
app_already_exists = False
for line in lines:
if "USER_DEFINED_APPS" in line and "=" in line:
in_user_apps = True
elif in_user_apps and line.strip() == "]":
in_user_apps = False
elif in_user_apps and (f'"{app_module_path}"' in line or f"'{app_module_path}'" in line):
app_already_exists = True
break
if app_already_exists:
UIFormatter.print_info(f"App '{app_module_path}' is already in USER_DEFINED_APPS")
return True
if "USER_DEFINED_APPS" not in content:
@@ -86,7 +143,7 @@ class AppManager:
in_user_apps = True
new_lines.append(line)
elif in_user_apps and line.strip() == "]":
new_lines.append(f' "{self.app_name}",')
new_lines.append(f' "{app_module_path}",')
new_lines.append(line)
in_user_apps = False
apps_added = True
@@ -100,7 +157,7 @@ class AppManager:
with open(base_settings_path, "w") as f:
f.write("\n".join(new_lines))
UIFormatter.print_success(f"Added '{self.app_name}' to USER_DEFINED_APPS in base.py")
UIFormatter.print_success(f"Added '{app_module_path}' to USER_DEFINED_APPS in base.py")
return True
def _find_settings_path(self) -> Optional[str]:
@@ -122,9 +179,51 @@ class AppManager:
return None
def _detect_project_structure(self) -> tuple[bool, Optional[str], str]:
"""
Detect if the project uses nested apps and return the structure info.
Returns:
tuple: (is_nested, nested_dir, apps_base_dir)
"""
# Look for project directories that contain settings
for item in os.listdir(self.current_dir):
if os.path.isdir(item) and not item.startswith(".") and item != "__pycache__":
# Check if this directory contains Django project files
project_path = os.path.join(self.current_dir, item)
settings_path = os.path.join(project_path, "settings")
# Check if settings directory exists with base.py
if os.path.exists(settings_path) and os.path.exists(os.path.join(settings_path, "base.py")):
# Found the project directory, now check for nested apps
project_name = item
# Look for common nested app directories
for nested_dir in ["apps", "modules", "packages"]:
nested_path = os.path.join(self.current_dir, nested_dir)
if os.path.exists(nested_path) and os.path.isdir(nested_path):
# Check if there are any Django apps in this directory
for app_item in os.listdir(nested_path):
app_path = os.path.join(nested_path, app_item)
if os.path.isdir(app_path) and os.path.exists(os.path.join(app_path, "apps.py")):
# Found nested apps structure
return True, nested_dir, nested_path
# No nested structure found
return False, None, self.current_dir
# Fallback: check current directory
settings_path = os.path.join(self.current_dir, "settings")
if os.path.exists(settings_path) and os.path.exists(os.path.join(settings_path, "base.py")):
return False, None, self.current_dir
return False, None, self.current_dir
def _create_additional_files(self) -> bool:
"""Create additional files for the app (serializers.py, routes.py)."""
app_path = os.path.join(self.current_dir, self.app_name)
# Detect project structure to get correct app path
is_nested, nested_dir, apps_base_dir = self._detect_project_structure()
app_path = os.path.join(apps_base_dir, self.app_name)
# Create serializers.py
context = {"app_name": self.app_name}
+1 -1
View File
@@ -98,7 +98,7 @@ def handle_app_command(args: argparse.Namespace) -> None:
instructions.append("2. Create your models in the app's models.py\n")
instructions.append("3. Run migrations: python manage.py makemigrations\n")
instructions.append("4. Apply migrations: python manage.py migrate\n")
instructions.append("5. Create views and URLs for your app\n")
instructions.append("5. Create views, serializers and routes(URLs) for your app\n")
console.print(Panel(instructions, title="💡 What's Next", border_style="green"))
else:
-18
View File
@@ -1,18 +0,0 @@
# Django settings
DJANGO_SETTINGS_MODULE=core.settings.development
SECRET_KEY= your-secret-key
ALLOWED_HOSTS=api.your-domain.com,www.your-domain.com
# Database (individual parameters)
DB_NAME=
DB_USER=
DB_PASSWORD=
DB_HOST=
DB_PORT=
# Email settings
EMAIL_HOST=
EMAIL_PORT=
EMAIL_USE_TLS=
EMAIL_HOST_USER=
EMAIL_HOST_PASSWORD=
-89
View File
@@ -1,89 +0,0 @@
# Python
*.py[cod]
*$py.class
*.so
__pycache__/
*.egg-info/
dist/
build/
.eggs/
*.egg
# Django
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
*.sqlite3
# Environment
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# IDEs
.vscode/
.idea/
*.swp
*.swo
*~
.project
.pydevproject
.settings/
.ropeproject/
# OS
.DS_Store
*.DS_Store
Thumbs.db
desktop.ini
# Django specific
media/
staticfiles/
staticfiles/
static_root/
/static/
# Testing
.coverage
htmlcov/
.pytest_cache/
.tox/
coverage.xml
*.cover
.hypothesis/
.cache
# Logs
logs/
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Node modules (if using frontend tools)
node_modules/
# Secret keys
secret.txt
secrets.json
# Jupyter Notebook
.ipynb_checkpoints
# Backup files
*.bak
*.tmp
*~
# Database
*.db
*.sql
# Cloud
.cloud
-20
View File
@@ -1,20 +0,0 @@
# Procfile for core
# Used for deploying to PaaS platforms like Heroku, Railway, Render, etc.
# Web server process (using Gunicorn)
# Adjust workers based on your needs: (2 x CPU cores) + 1
web: gunicorn core.wsgi:application --bind 0.0.0.0:$PORT --workers 2 --timeout 120 --access-logfile - --error-logfile - --log-level info
# Alternative web server configurations (uncomment to use):
# web: gunicorn core.wsgi:application --bind 0.0.0.0:$PORT --workers 4 --threads 2 --timeout 120
# web: gunicorn core.wsgi:application --bind 0.0.0.0:$PORT --workers 2 --worker-class gevent --worker-connections 1000 --timeout 120
# Release task (runs migrations before deployment)
release: python manage.py migrate --noinput && python manage.py collectstatic --noinput
# Uncomment below to run scheduled tasks (if using Celery)
# worker: celery -A core worker --loglevel=info
# beat: celery -A core beat --loglevel=info
# Development server (for local testing with Foreman/Overmind)
# web: python manage.py runserver 0.0.0.0:$PORT
-60
View File
@@ -1,60 +0,0 @@
# core
A Django project created with django-setup.
## Features
- Modern project structure with environment-specific settings
- Pre-configured REST API with JWT authentication
- Essential dependencies and utilities
- Production-ready configuration
## Setup
1. Install dependencies:
```bash
pip install -r requirements.txt
```
2. Set environment variables in `.env` file
3. Run migrations:
```bash
python manage.py migrate
```
4. Create superuser:
```bash
python manage.py createsuperuser
```
5. Start development server:
```bash
python manage.py runserver
```
## Project Structure
```
core/
├── core/
│ ├── settings/
│ │ ├── base.py
│ │ ├── development.py
│ │ └── production.py
│ ├── urls.py
│ ├── wsgi.py
│ └── asgi.py
├── store/
├── manage.py
├── requirements.txt
├── pyproject.toml
├── .env.sample
└── README.md
```
## API Documentation
When running in development mode, API documentation is available at:
- Swagger UI: http://localhost:8000/docs/
- Schema: http://localhost:8000/schema/
View File
Whitespace-only changes.
View File
Whitespace-only changes.
-3
View File
@@ -1,3 +0,0 @@
from django.contrib import admin
# Register your models here.
-6
View File
@@ -1,6 +0,0 @@
from django.apps import AppConfig
class StoreConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "store"
Whitespace-only changes.
-3
View File
@@ -1,3 +0,0 @@
from django.db import models
# Create your models here.
-16
View File
@@ -1,16 +0,0 @@
"""
API routes for store app.
"""
from rest_framework.routers import DefaultRouter
from . import views
# Create router instance
router = DefaultRouter()
# Register viewsets with router
# Example:
# router.register(r'store', views.StoreViewSet)
# Get URL patterns
urlpatterns = router.urls
-13
View File
@@ -1,13 +0,0 @@
"""
Serializers for store app.
"""
from rest_framework import serializers
# Add your serializers here
# Example:
# class StoreSerializer(serializers.ModelSerializer):
# class Meta:
# model = YourModel
# fields = '__all__'
-3
View File
@@ -1,3 +0,0 @@
from django.test import TestCase
# Create your tests here.
-9
View File
@@ -1,9 +0,0 @@
from django.urls import path
from . import views
app_name = "store"
urlpatterns = [
# Add your URL patterns here
# path('', views.index, name='index'),
]
-3
View File
@@ -1,3 +0,0 @@
from django.shortcuts import render
# Create your views here.
View File
Whitespace-only changes.
-9
View File
@@ -1,9 +0,0 @@
import os
from dotenv import load_dotenv
from django.core.asgi import get_asgi_application
load_dotenv()
os.environ.setdefault("DJANGO_SETTINGS_MODULE", os.getenv("DJANGO_SETTINGS_MODULE"))
application = get_asgi_application()
View File
Whitespace-only changes.
-163
View File
@@ -1,163 +0,0 @@
"""
Common settings shared between development and production environment
"""
import os
from datetime import timedelta
from pathlib import Path
from dotenv import load_dotenv
load_dotenv()
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/5.2/howto/deployment/checklist/
# Application definition
THIRD_PARTY_APPS = [
"rest_framework",
"rest_framework_simplejwt",
"rest_framework_simplejwt.token_blacklist",
"corsheaders",
"drf_spectacular",
]
USER_DEFINED_APPS = [
"apps.store",
"account",
]
BUILT_IN_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
]
INSTALLED_APPS = BUILT_IN_APPS + THIRD_PARTY_APPS + USER_DEFINED_APPS
INSTALLED_APPS.insert(0, "jazzmin")
MIDDLEWARE = [
"corsheaders.middleware.CorsMiddleware",
"django.middleware.security.SecurityMiddleware",
"whitenoise.middleware.WhiteNoiseMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
"account",
]
ROOT_URLCONF = "core.urls"
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
],
},
},
]
WSGI_APPLICATION = "core.wsgi.application"
# Password validation
# https://docs.djangoproject.com/en/5.2/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
},
{
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
},
{
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
},
{
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
},
]
# Internationalization
# https://docs.djangoproject.com/en/5.2/topics/i18n/
LANGUAGE_CODE = "en-us"
TIME_ZONE = "UTC"
USE_I18N = True
USE_TZ = True
# Static files and media files
STATIC_URL = "static/"
STATIC_ROOT = BASE_DIR / "staticfiles"
MEDIA_URL = "media/"
MEDIA_ROOT = BASE_DIR / "media"
STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage"
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
# REST Framework Settings
REST_FRAMEWORK = {
"DEFAULT_RENDERER_CLASSES": [
"rest_framework.renderers.JSONRenderer",
],
"DEFAULT_PARSER_CLASSES": [
"rest_framework.parsers.JSONParser",
],
"DEFAULT_AUTHENTICATION_CLASSES": (
"rest_framework_simplejwt.authentication.JWTAuthentication",
"rest_framework.authentication.SessionAuthentication",
),
"DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema",
"DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination",
"PAGE_SIZE": 20,
}
# DRF Spectacular settings
SPECTACULAR_SETTINGS = {
"TITLE": "core API",
"DESCRIPTION": "API documentation for core",
"VERSION": "1.0.0",
"SERVE_INCLUDE_SCHEMA": False,
"COMPONENT_SPLIT_REQUEST": True,
"SCHEMA_PATH_PREFIX": "/api/",
}
# JWT Settings
SIMPLE_JWT = {
"ACCESS_TOKEN_LIFETIME": timedelta(days=1),
"REFRESH_TOKEN_LIFETIME": timedelta(days=3),
"ROTATE_REFRESH_TOKENS": True,
"BLACKLIST_AFTER_ROTATION": True,
}
# CORS Settings
CORS_ALLOWED_ORIGINS = [
"http://localhost:3000",
"http://127.0.0.1:3000",
]
CORS_ALLOW_CREDENTIALS = True
# Security Settings
SECURE_BROWSER_XSS_FILTER = True
SECURE_CONTENT_TYPE_NOSNIFF = True
X_FRAME_OPTIONS = "DENY"
-27
View File
@@ -1,27 +0,0 @@
from .base import *
SECRET_KEY = "+#JJBTL^S&N7FOYi8_WM$*(BvxD6VqB7JnLCvgO_4f9yN$FJP8"
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = ["*"]
# Database
# https://docs.djangoproject.com/en/5.2/ref/settings/#databases
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": BASE_DIR / "db.sqlite3",
}
}
# Email backend for development
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
# CORS settings for development
CORS_ALLOW_ALL_ORIGINS = True
# Disable HTTPS redirect in development
SECURE_SSL_REDIRECT = False
-43
View File
@@ -1,43 +0,0 @@
from .base import *
import os
import dj_database_url
DEBUG = False
SECRET_KEY = os.getenv("SECRET_KEY")
ALLOWED_HOSTS = os.getenv("ALLOWED_HOSTS", "").split(",")
# Database
# Using individual database parameters
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"NAME": os.getenv("DB_NAME"),
"USER": os.getenv("DB_USER"),
"PASSWORD": os.getenv("DB_PASSWORD"),
"HOST": os.getenv("DB_HOST"),
"PORT": os.getenv("DB_PORT"),
}
}
# Email settings
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
EMAIL_HOST = os.getenv("EMAIL_HOST")
EMAIL_PORT = int(os.getenv("EMAIL_PORT", 587))
EMAIL_USE_TLS = os.getenv("EMAIL_USE_TLS", "True").lower() == "true"
EMAIL_HOST_USER = os.getenv("EMAIL_HOST_USER")
EMAIL_HOST_PASSWORD = os.getenv("EMAIL_HOST_PASSWORD")
# Security settings for production
SECURE_SSL_REDIRECT = True
SECURE_HSTS_SECONDS = 31536000
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
# Session settings
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
# Static files
STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage"
-29
View File
@@ -1,29 +0,0 @@
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from drf_spectacular.views import (
SpectacularAPIView,
SpectacularSwaggerView,
)
from rest_framework_simplejwt.views import (
TokenObtainPairView,
TokenRefreshView,
TokenBlacklistView,
)
urlpatterns = [
path("admin/", admin.site.urls),
# JWT tokens
path("token/", TokenObtainPairView.as_view(), name="token_obtain_pair"),
path("token/refresh/", TokenRefreshView.as_view(), name="token_refresh"),
path("token/blacklist/", TokenBlacklistView.as_view(), name="token_blacklist"),
# App URLs
path("", include("apps.store.urls")),
]
# Don't show schema in production
if settings.DEBUG:
urlpatterns += [
path("schema/", SpectacularAPIView.as_view(), name="schema"),
path("docs/", SpectacularSwaggerView.as_view(url_name="schema")),
]
-9
View File
@@ -1,9 +0,0 @@
import os
from dotenv import load_dotenv
from django.core.wsgi import get_wsgi_application
load_dotenv()
os.environ.setdefault("DJANGO_SETTINGS_MODULE", os.getenv("DJANGO_SETTINGS_MODULE"))
application = get_wsgi_application()
-154
View File
@@ -1,154 +0,0 @@
# Justfile for core
# Task runner for Django development
# Install just: https://github.com/casey/just
# Default task: show available commands
default:
@just --list
# Run development server
dev:
uv run python manage.py runserver
# Run development server with custom host and port
dev-server HOST="0.0.0.0" PORT="8000":
uv run python manage.py runserver :
# Create migrations for all apps
makemigrations:
uv run python manage.py makemigrations
# Create migrations for specific app
makemigrations-app APP:
uv run python manage.py makemigrations
# Run all migrations
migrate:
uv run python manage.py migrate
# Reset database (delete all migrations)
reset-db:
uv run python manage.py flush --noinput
uv run python manage.py migrate
# Create superuser
createsuperuser:
uv run python manage.py createsuperuser
# Collect static files
collectstatic:
uv run python manage.py collectstatic --noinput
# Run Django shell
shell:
uv run python manage.py shell
# Run Django shell plus (IPython)
shell-plus:
uv run python manage.py shell_plus
# Run tests
test:
uv run python manage.py test
# Run tests with coverage
test-coverage:
uv run pytest --cov=. --cov-report=html --cov-report=term
# Lint code with ruff
lint:
uv run ruff check .
# Format code with ruff
format:
uv run ruff format .
# Lint and format code
style:
uv run ruff check .
uv run ruff format .
# Check security issues
check:
uv run python manage.py check
# Check security issues (production settings)
check-deploy:
uv run python manage.py check --deploy
# Show all database migrations status
showmigrations:
uv run python manage.py showmigrations
# Sync dependencies (uv equivalent of pip freeze)
requirements:
uv pip compile
# Run all linting and checks
ci:
uv run ruff check .
uv run ruff format --check .
uv run python manage.py check
# Start interactive shell
shell-ipython:
uv run python manage.py shell_plus
# Clear all cache
clear-cache:
uv run python manage.py clear_cache
# Show Django version
version:
uv run python manage.py version
# Run database shell
dbshell:
uv run python manage.py dbshell
# Start production server with gunicorn
server:
uv run gunicorn core.wsgi:application --bind 0.0.0.0:8000
# Start production server with gunicorn workers
server-prod WORKERS="4":
uv run gunicorn core.wsgi:application --bind 0.0.0.0:8000 --workers
# Start production server with gunicorn and reload on file changes
server-watch:
uv run gunicorn core.wsgi:application --bind 0.0.0.0:8000 --reload
# Clean Python cache files
clean:
find . -type d -name "__pycache__" -exec rm -rf {} +
find . -type f -name "*.pyc" -delete
find . -type f -name "*.pyo" -delete
find . -type f -name ".coverage" -delete
find . -type d -name "*.egg-info" -exec rm -rf {} +
rm -rf htmlcov/
rm -rf .pytest_cache/
# Setup project for development (using uv)
setup:
uv sync
uv run python manage.py migrate
uv run python manage.py createsuperuser
# Complete setup including static files
setup-complete:
uv sync
uv run python manage.py migrate
uv run python manage.py collectstatic --noinput
uv run python manage.py createsuperuser
# Install a new package
install PACKAGE:
uv add
# Install a dev package
install-dev PACKAGE:
uv add --dev
# Remove a package
remove PACKAGE:
uv remove
-26
View File
@@ -1,26 +0,0 @@
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys
from dotenv import load_dotenv
def main():
"""Run administrative tasks."""
os.environ.setdefault("DJANGO_SETTINGS_MODULE", os.getenv("DJANGO_SETTINGS_MODULE"))
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)
if __name__ == "__main__":
load_dotenv()
main()
-41
View File
@@ -1,41 +0,0 @@
[project]
name = "yoo"
version = "0.1.0"
description = ""
readme = "README.md"
requires-python = ">=3.13"
license = { text = "MIT" }
dependencies = [
"django>=5.2.7",
"python-dotenv>=1.1.1",
"django-jazzmin>=3.0.1",
"djangorestframework>=3.16.1",
"djangorestframework-simplejwt>=5.5.1",
"drf-spectacular>=0.28.0",
"django-cors-headers>=4.9.0",
"whitenoise>=6.8.2",
"psycopg2-binary>=2.9.9",
"gunicorn>=21.2.0",
]
[tool.ruff]
line-length = 88
target-version = "py38"
[tool.ruff.lint]
select = [
"E", # pycodestyle errors
"W", # pycodestyle warnings
"F", # pyflakes
"I", # isort
"B", # flake8-bugbear
"C4", # flake8-comprehensions
"UP", # pyupgrade
]
ignore = [
"E501", # line too long, handled by formatter
"B008", # do not perform function calls in argument defaults
]
[tool.ruff.lint.isort]
known-first-party = ["core"]
-10
View File
@@ -1,10 +0,0 @@
Django
python-dotenv
django-jazzmin>
djangorestframework
djangorestframework_simplejwt
drf-spectacular
django-cors-headers
whitenoise
psycopg2-binary
gunicorn
-1
View File
@@ -1 +0,0 @@
python-3.13