mirror of
https://github.com/smittix/intercept.git
synced 2026-07-29 02:58:11 -07:00
fix: Make psycopg2 optional for Flask/Werkzeug compatibility
- Bump Flask requirement to >=3.0.0 (required for Werkzeug 3.x) - Make psycopg2 import conditional in routes/adsb.py and utils/adsb_history.py - ADS-B history features gracefully disabled when PostgreSQL libs unavailable Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
+1
-1
@@ -26,7 +26,7 @@ classifiers = [
|
|||||||
"Topic :: System :: Networking :: Monitoring",
|
"Topic :: System :: Networking :: Monitoring",
|
||||||
]
|
]
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"flask>=2.0.0",
|
"flask>=3.0.0",
|
||||||
"skyfield>=1.45",
|
"skyfield>=1.45",
|
||||||
"pyserial>=3.5",
|
"pyserial>=3.5",
|
||||||
"Werkzeug>=3.1.5",
|
"Werkzeug>=3.1.5",
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
# Core dependencies
|
# Core dependencies
|
||||||
flask>=2.0.0
|
flask>=3.0.0
|
||||||
flask-limiter>=2.5.4
|
flask-limiter>=2.5.4
|
||||||
requests>=2.28.0
|
requests>=2.28.0
|
||||||
Werkzeug>=3.1.5
|
Werkzeug>=3.1.5
|
||||||
|
|||||||
+19
-10
@@ -15,8 +15,16 @@ from typing import Any, Generator
|
|||||||
|
|
||||||
from flask import Blueprint, jsonify, request, Response, render_template
|
from flask import Blueprint, jsonify, request, Response, render_template
|
||||||
from flask import make_response
|
from flask import make_response
|
||||||
import psycopg2
|
|
||||||
from psycopg2.extras import RealDictCursor
|
# psycopg2 is optional - only needed for PostgreSQL history persistence
|
||||||
|
try:
|
||||||
|
import psycopg2
|
||||||
|
from psycopg2.extras import RealDictCursor
|
||||||
|
PSYCOPG2_AVAILABLE = True
|
||||||
|
except ImportError:
|
||||||
|
psycopg2 = None # type: ignore
|
||||||
|
RealDictCursor = None # type: ignore
|
||||||
|
PSYCOPG2_AVAILABLE = False
|
||||||
|
|
||||||
import app as app_module
|
import app as app_module
|
||||||
from config import (
|
from config import (
|
||||||
@@ -192,7 +200,7 @@ def _parse_int_param(value: str | None, default: int, min_value: int | None = No
|
|||||||
|
|
||||||
|
|
||||||
def _get_active_session() -> dict[str, Any] | None:
|
def _get_active_session() -> dict[str, Any] | None:
|
||||||
if not ADSB_HISTORY_ENABLED:
|
if not ADSB_HISTORY_ENABLED or not PSYCOPG2_AVAILABLE:
|
||||||
return None
|
return None
|
||||||
_ensure_history_schema()
|
_ensure_history_schema()
|
||||||
try:
|
try:
|
||||||
@@ -222,7 +230,7 @@ def _record_session_start(
|
|||||||
start_source: str | None,
|
start_source: str | None,
|
||||||
started_by: str | None,
|
started_by: str | None,
|
||||||
) -> dict[str, Any] | None:
|
) -> dict[str, Any] | None:
|
||||||
if not ADSB_HISTORY_ENABLED:
|
if not ADSB_HISTORY_ENABLED or not PSYCOPG2_AVAILABLE:
|
||||||
return None
|
return None
|
||||||
_ensure_history_schema()
|
_ensure_history_schema()
|
||||||
try:
|
try:
|
||||||
@@ -257,7 +265,7 @@ def _record_session_start(
|
|||||||
|
|
||||||
|
|
||||||
def _record_session_stop(*, stop_source: str | None, stopped_by: str | None) -> dict[str, Any] | None:
|
def _record_session_stop(*, stop_source: str | None, stopped_by: str | None) -> dict[str, Any] | None:
|
||||||
if not ADSB_HISTORY_ENABLED:
|
if not ADSB_HISTORY_ENABLED or not PSYCOPG2_AVAILABLE:
|
||||||
return None
|
return None
|
||||||
_ensure_history_schema()
|
_ensure_history_schema()
|
||||||
try:
|
try:
|
||||||
@@ -810,7 +818,8 @@ def adsb_dashboard():
|
|||||||
@adsb_bp.route('/history')
|
@adsb_bp.route('/history')
|
||||||
def adsb_history():
|
def adsb_history():
|
||||||
"""ADS-B history reporting dashboard."""
|
"""ADS-B history reporting dashboard."""
|
||||||
resp = make_response(render_template('adsb_history.html', history_enabled=ADSB_HISTORY_ENABLED))
|
history_available = ADSB_HISTORY_ENABLED and PSYCOPG2_AVAILABLE
|
||||||
|
resp = make_response(render_template('adsb_history.html', history_enabled=history_available))
|
||||||
resp.headers['Cache-Control'] = 'no-store'
|
resp.headers['Cache-Control'] = 'no-store'
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
@@ -818,7 +827,7 @@ def adsb_history():
|
|||||||
@adsb_bp.route('/history/summary')
|
@adsb_bp.route('/history/summary')
|
||||||
def adsb_history_summary():
|
def adsb_history_summary():
|
||||||
"""Summary stats for ADS-B history window."""
|
"""Summary stats for ADS-B history window."""
|
||||||
if not ADSB_HISTORY_ENABLED:
|
if not ADSB_HISTORY_ENABLED or not PSYCOPG2_AVAILABLE:
|
||||||
return jsonify({'error': 'ADS-B history is disabled'}), 503
|
return jsonify({'error': 'ADS-B history is disabled'}), 503
|
||||||
_ensure_history_schema()
|
_ensure_history_schema()
|
||||||
|
|
||||||
@@ -848,7 +857,7 @@ def adsb_history_summary():
|
|||||||
@adsb_bp.route('/history/aircraft')
|
@adsb_bp.route('/history/aircraft')
|
||||||
def adsb_history_aircraft():
|
def adsb_history_aircraft():
|
||||||
"""List latest aircraft snapshots for a time window."""
|
"""List latest aircraft snapshots for a time window."""
|
||||||
if not ADSB_HISTORY_ENABLED:
|
if not ADSB_HISTORY_ENABLED or not PSYCOPG2_AVAILABLE:
|
||||||
return jsonify({'error': 'ADS-B history is disabled'}), 503
|
return jsonify({'error': 'ADS-B history is disabled'}), 503
|
||||||
_ensure_history_schema()
|
_ensure_history_schema()
|
||||||
|
|
||||||
@@ -898,7 +907,7 @@ def adsb_history_aircraft():
|
|||||||
@adsb_bp.route('/history/timeline')
|
@adsb_bp.route('/history/timeline')
|
||||||
def adsb_history_timeline():
|
def adsb_history_timeline():
|
||||||
"""Timeline snapshots for a specific aircraft."""
|
"""Timeline snapshots for a specific aircraft."""
|
||||||
if not ADSB_HISTORY_ENABLED:
|
if not ADSB_HISTORY_ENABLED or not PSYCOPG2_AVAILABLE:
|
||||||
return jsonify({'error': 'ADS-B history is disabled'}), 503
|
return jsonify({'error': 'ADS-B history is disabled'}), 503
|
||||||
_ensure_history_schema()
|
_ensure_history_schema()
|
||||||
|
|
||||||
@@ -933,7 +942,7 @@ def adsb_history_timeline():
|
|||||||
@adsb_bp.route('/history/messages')
|
@adsb_bp.route('/history/messages')
|
||||||
def adsb_history_messages():
|
def adsb_history_messages():
|
||||||
"""Raw message history for a specific aircraft."""
|
"""Raw message history for a specific aircraft."""
|
||||||
if not ADSB_HISTORY_ENABLED:
|
if not ADSB_HISTORY_ENABLED or not PSYCOPG2_AVAILABLE:
|
||||||
return jsonify({'error': 'ADS-B history is disabled'}), 503
|
return jsonify({'error': 'ADS-B history is disabled'}), 503
|
||||||
_ensure_history_schema()
|
_ensure_history_schema()
|
||||||
|
|
||||||
|
|||||||
+12
-4
@@ -9,8 +9,16 @@ import time
|
|||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from typing import Iterable
|
from typing import Iterable
|
||||||
|
|
||||||
import psycopg2
|
# psycopg2 is optional - only needed for PostgreSQL history persistence
|
||||||
from psycopg2.extras import execute_values, Json
|
try:
|
||||||
|
import psycopg2
|
||||||
|
from psycopg2.extras import execute_values, Json
|
||||||
|
PSYCOPG2_AVAILABLE = True
|
||||||
|
except ImportError:
|
||||||
|
psycopg2 = None # type: ignore
|
||||||
|
execute_values = None # type: ignore
|
||||||
|
Json = None # type: ignore
|
||||||
|
PSYCOPG2_AVAILABLE = False
|
||||||
|
|
||||||
from config import (
|
from config import (
|
||||||
ADSB_DB_HOST,
|
ADSB_DB_HOST,
|
||||||
@@ -199,7 +207,7 @@ class AdsbHistoryWriter:
|
|||||||
"""Background writer for ADS-B history records."""
|
"""Background writer for ADS-B history records."""
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.enabled = ADSB_HISTORY_ENABLED
|
self.enabled = ADSB_HISTORY_ENABLED and PSYCOPG2_AVAILABLE
|
||||||
self._queue: queue.Queue[dict] = queue.Queue(maxsize=ADSB_HISTORY_QUEUE_SIZE)
|
self._queue: queue.Queue[dict] = queue.Queue(maxsize=ADSB_HISTORY_QUEUE_SIZE)
|
||||||
self._thread: threading.Thread | None = None
|
self._thread: threading.Thread | None = None
|
||||||
self._stop_event = threading.Event()
|
self._stop_event = threading.Event()
|
||||||
@@ -297,7 +305,7 @@ class AdsbSnapshotWriter:
|
|||||||
"""Background writer for ADS-B snapshot records."""
|
"""Background writer for ADS-B snapshot records."""
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
self.enabled = ADSB_HISTORY_ENABLED
|
self.enabled = ADSB_HISTORY_ENABLED and PSYCOPG2_AVAILABLE
|
||||||
self._queue: queue.Queue[dict] = queue.Queue(maxsize=ADSB_HISTORY_QUEUE_SIZE)
|
self._queue: queue.Queue[dict] = queue.Queue(maxsize=ADSB_HISTORY_QUEUE_SIZE)
|
||||||
self._thread: threading.Thread | None = None
|
self._thread: threading.Thread | None = None
|
||||||
self._stop_event = threading.Event()
|
self._stop_event = threading.Event()
|
||||||
|
|||||||
Reference in New Issue
Block a user