From a2528f1f5327093e4d2951718675b8da5a72f897 Mon Sep 17 00:00:00 2001 From: Wiktor <42137698+overspend1@users.noreply.github.com> Date: Sat, 1 Nov 2025 19:20:30 +0100 Subject: [PATCH 1/2] fix: repair docker setup for telegram bot --- .dockerignore | 37 ++++++----------------------------- Dockerfile | 32 ++++++++++++++++++------------- bot.py | 48 ++++++++++++++++++++++++++++------------------ docker-compose.yml | 13 ++++++++++++- 4 files changed, 66 insertions(+), 64 deletions(-) diff --git a/.dockerignore b/.dockerignore index 6bc9356..fd80693 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,32 +1,7 @@ -# Python -__pycache__/ -*.py[cod] -*$py.class -*.so -.Python -.venv/ -venv/ -ENV/ - -# Database -*.db -*.db-journal - -# Environment variables +.git +.gitignore +__pycache__ +*.pyc +backups .env - -# IDEs -.vscode/ -.idea/ -*.swp -*.swo - -# OS -.DS_Store -Thumbs.db - -# Logs -*.log - -# Docker -data/ +.env.* diff --git a/Dockerfile b/Dockerfile index 6ddea87..0c59710 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,32 +1,38 @@ # Use Python 3.12 slim image FROM python:3.12-slim +# Configure Python environment +ENV PYTHONDONTWRITEBYTECODE=1 \ + PYTHONUNBUFFERED=1 + # Set working directory WORKDIR /app -# Install system dependencies (if needed) -RUN apt-get update && apt-get install -y \ +# Install system dependencies required for asyncpg build +RUN apt-get update && apt-get install -y --no-install-recommends \ + build-essential \ + libpq-dev \ && rm -rf /var/lib/apt/lists/* # Copy requirements first (for better caching) -COPY requirements.txt . +COPY requirements.txt ./ # Install Python dependencies -RUN pip install --no-cache-dir -r requirements.txt -RUN pip install --no-cache-dir python-telegram-bot==20.7 +RUN pip install --no-cache-dir --upgrade pip \ + && pip install --no-cache-dir -r requirements.txt -# Copy the bot code -COPY bot.py . +# Copy application source +COPY . . -# Create directory for backups +# Ensure backups directory exists inside the container RUN mkdir -p /app/backups # Set environment variables (will be overridden by docker-compose or run command) -ENV TELEGRAM_BOT_TOKEN="" -ENV OWNER_ID="" -ENV CHANNEL_ID="" -ENV DATABASE_URL="" -ENV MEMEBOT_BACKUP_DIR="/app/backups" +ENV TELEGRAM_BOT_TOKEN="" \ + OWNER_ID="" \ + CHANNEL_ID="" \ + DATABASE_URL="" \ + MEMEBOT_BACKUP_DIR="/app/backups" # Run the bot CMD ["python", "bot.py"] diff --git a/bot.py b/bot.py index 487a5cc..2979afd 100644 --- a/bot.py +++ b/bot.py @@ -30,31 +30,41 @@ if TYPE_CHECKING: from telegram import Update, Message, InputFile from telegram.ext import ApplicationBuilder, ContextTypes, CommandHandler, MessageHandler, filters else: - Update = Message = InputFile = Any # type: ignore - ContextTypes = SimpleNamespace(DEFAULT_TYPE=Any) # type: ignore + try: + from telegram import Update, Message, InputFile # type: ignore + from telegram.ext import ( # type: ignore + ApplicationBuilder, + ContextTypes, + CommandHandler, + MessageHandler, + filters, + ) + except ModuleNotFoundError: + Update = Message = InputFile = Any # type: ignore + ContextTypes = SimpleNamespace(DEFAULT_TYPE=Any) # type: ignore - class _MissingTelegramModule: - """Lazily raise when Telegram features are used without dependency.""" + class _MissingTelegramModule: + """Lazily raise when Telegram features are used without dependency.""" - def __getattr__(self, item): - raise RuntimeError( - "python-telegram-bot must be installed to use the Meme Wrangler bot (missing telegram module)." - ) + def __getattr__(self, item): + raise RuntimeError( + "python-telegram-bot must be installed to use the Meme Wrangler bot (missing telegram module)." + ) - def __call__(self, *args, **kwargs): - raise RuntimeError( - "python-telegram-bot must be installed to use the Meme Wrangler bot (missing telegram module)." - ) + def __call__(self, *args, **kwargs): + raise RuntimeError( + "python-telegram-bot must be installed to use the Meme Wrangler bot (missing telegram module)." + ) - ApplicationBuilder = CommandHandler = MessageHandler = _MissingTelegramModule() # type: ignore + ApplicationBuilder = CommandHandler = MessageHandler = _MissingTelegramModule() # type: ignore - class _MissingFilters(SimpleNamespace): - def __getattr__(self, item): - raise RuntimeError( - "python-telegram-bot must be installed to use the Meme Wrangler bot (missing telegram filters)." - ) + class _MissingFilters(SimpleNamespace): + def __getattr__(self, item): + raise RuntimeError( + "python-telegram-bot must be installed to use the Meme Wrangler bot (missing telegram filters)." + ) - filters = _MissingFilters() # type: ignore + filters = _MissingFilters() # type: ignore logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) diff --git a/docker-compose.yml b/docker-compose.yml index 6c7c5df..77925c7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,19 +3,30 @@ services: image: postgres:15 container_name: meme-wrangler-db restart: unless-stopped + env_file: + - .env environment: - POSTGRES_DB=${POSTGRES_DB} - POSTGRES_USER=${POSTGRES_USER} - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} volumes: - pgdata:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-meme} -d ${POSTGRES_DB:-meme_wrangler}"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 5s meme-wrangler: build: . container_name: meme-wrangler restart: unless-stopped depends_on: - - postgres + postgres: + condition: service_healthy + env_file: + - .env environment: - TELEGRAM_BOT_TOKEN=${TELEGRAM_BOT_TOKEN} - OWNER_ID=${OWNER_ID} From 0739de20942edd2965643884147ed6d2a0712bc4 Mon Sep 17 00:00:00 2001 From: Wiktor <42137698+overspend1@users.noreply.github.com> Date: Sat, 1 Nov 2025 19:25:46 +0100 Subject: [PATCH 2/2] fix: make compose env file optional --- .dockerignore | 37 ++++++----------------------------- Dockerfile | 32 ++++++++++++++++++------------- bot.py | 48 ++++++++++++++++++++++++++++------------------ docker-compose.yml | 26 +++++++++++++++++-------- 4 files changed, 72 insertions(+), 71 deletions(-) diff --git a/.dockerignore b/.dockerignore index 6bc9356..fd80693 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,32 +1,7 @@ -# Python -__pycache__/ -*.py[cod] -*$py.class -*.so -.Python -.venv/ -venv/ -ENV/ - -# Database -*.db -*.db-journal - -# Environment variables +.git +.gitignore +__pycache__ +*.pyc +backups .env - -# IDEs -.vscode/ -.idea/ -*.swp -*.swo - -# OS -.DS_Store -Thumbs.db - -# Logs -*.log - -# Docker -data/ +.env.* diff --git a/Dockerfile b/Dockerfile index 6ddea87..0c59710 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,32 +1,38 @@ # Use Python 3.12 slim image FROM python:3.12-slim +# Configure Python environment +ENV PYTHONDONTWRITEBYTECODE=1 \ + PYTHONUNBUFFERED=1 + # Set working directory WORKDIR /app -# Install system dependencies (if needed) -RUN apt-get update && apt-get install -y \ +# Install system dependencies required for asyncpg build +RUN apt-get update && apt-get install -y --no-install-recommends \ + build-essential \ + libpq-dev \ && rm -rf /var/lib/apt/lists/* # Copy requirements first (for better caching) -COPY requirements.txt . +COPY requirements.txt ./ # Install Python dependencies -RUN pip install --no-cache-dir -r requirements.txt -RUN pip install --no-cache-dir python-telegram-bot==20.7 +RUN pip install --no-cache-dir --upgrade pip \ + && pip install --no-cache-dir -r requirements.txt -# Copy the bot code -COPY bot.py . +# Copy application source +COPY . . -# Create directory for backups +# Ensure backups directory exists inside the container RUN mkdir -p /app/backups # Set environment variables (will be overridden by docker-compose or run command) -ENV TELEGRAM_BOT_TOKEN="" -ENV OWNER_ID="" -ENV CHANNEL_ID="" -ENV DATABASE_URL="" -ENV MEMEBOT_BACKUP_DIR="/app/backups" +ENV TELEGRAM_BOT_TOKEN="" \ + OWNER_ID="" \ + CHANNEL_ID="" \ + DATABASE_URL="" \ + MEMEBOT_BACKUP_DIR="/app/backups" # Run the bot CMD ["python", "bot.py"] diff --git a/bot.py b/bot.py index 487a5cc..2979afd 100644 --- a/bot.py +++ b/bot.py @@ -30,31 +30,41 @@ if TYPE_CHECKING: from telegram import Update, Message, InputFile from telegram.ext import ApplicationBuilder, ContextTypes, CommandHandler, MessageHandler, filters else: - Update = Message = InputFile = Any # type: ignore - ContextTypes = SimpleNamespace(DEFAULT_TYPE=Any) # type: ignore + try: + from telegram import Update, Message, InputFile # type: ignore + from telegram.ext import ( # type: ignore + ApplicationBuilder, + ContextTypes, + CommandHandler, + MessageHandler, + filters, + ) + except ModuleNotFoundError: + Update = Message = InputFile = Any # type: ignore + ContextTypes = SimpleNamespace(DEFAULT_TYPE=Any) # type: ignore - class _MissingTelegramModule: - """Lazily raise when Telegram features are used without dependency.""" + class _MissingTelegramModule: + """Lazily raise when Telegram features are used without dependency.""" - def __getattr__(self, item): - raise RuntimeError( - "python-telegram-bot must be installed to use the Meme Wrangler bot (missing telegram module)." - ) + def __getattr__(self, item): + raise RuntimeError( + "python-telegram-bot must be installed to use the Meme Wrangler bot (missing telegram module)." + ) - def __call__(self, *args, **kwargs): - raise RuntimeError( - "python-telegram-bot must be installed to use the Meme Wrangler bot (missing telegram module)." - ) + def __call__(self, *args, **kwargs): + raise RuntimeError( + "python-telegram-bot must be installed to use the Meme Wrangler bot (missing telegram module)." + ) - ApplicationBuilder = CommandHandler = MessageHandler = _MissingTelegramModule() # type: ignore + ApplicationBuilder = CommandHandler = MessageHandler = _MissingTelegramModule() # type: ignore - class _MissingFilters(SimpleNamespace): - def __getattr__(self, item): - raise RuntimeError( - "python-telegram-bot must be installed to use the Meme Wrangler bot (missing telegram filters)." - ) + class _MissingFilters(SimpleNamespace): + def __getattr__(self, item): + raise RuntimeError( + "python-telegram-bot must be installed to use the Meme Wrangler bot (missing telegram filters)." + ) - filters = _MissingFilters() # type: ignore + filters = _MissingFilters() # type: ignore logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) diff --git a/docker-compose.yml b/docker-compose.yml index 6c7c5df..d96f63a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,23 +4,33 @@ services: container_name: meme-wrangler-db restart: unless-stopped environment: - - POSTGRES_DB=${POSTGRES_DB} - - POSTGRES_USER=${POSTGRES_USER} - - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} + - POSTGRES_DB=${POSTGRES_DB:-meme_wrangler} + - POSTGRES_USER=${POSTGRES_USER:-meme} + - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-meme} volumes: - pgdata:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-meme} -d ${POSTGRES_DB:-meme_wrangler}"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 5s meme-wrangler: build: . container_name: meme-wrangler restart: unless-stopped depends_on: - - postgres + postgres: + condition: service_healthy environment: - - TELEGRAM_BOT_TOKEN=${TELEGRAM_BOT_TOKEN} - - OWNER_ID=${OWNER_ID} - - CHANNEL_ID=${CHANNEL_ID} - - DATABASE_URL=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB} + - TELEGRAM_BOT_TOKEN=${TELEGRAM_BOT_TOKEN:-} + - OWNER_ID=${OWNER_ID:-} + - CHANNEL_ID=${CHANNEL_ID:-} + - POSTGRES_DB=${POSTGRES_DB:-meme_wrangler} + - POSTGRES_USER=${POSTGRES_USER:-meme} + - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-meme} + - DATABASE_URL=postgresql://${POSTGRES_USER:-meme}:${POSTGRES_PASSWORD:-meme}@postgres:5432/${POSTGRES_DB:-meme_wrangler} - MEMEBOT_BACKUP_DIR=/app/backups volumes: - ./backups:/app/backups