Skip to content

Instantly share code, notes, and snippets.

@kavdev
Created July 19, 2025 20:35
Show Gist options
  • Save kavdev/404282614d66b449a94ad849ccdc79dc to your computer and use it in GitHub Desktop.
Save kavdev/404282614d66b449a94ad849ccdc79dc to your computer and use it in GitHub Desktop.
Django 5.2 Postgres Library Version Checker
#!/usr/bin/env python3
"""
Script to check database and geospatial library versions against Django minimum requirements.
Written using Claude Code, with some fixes and adjustments.
"""
import subprocess
from typing import Optional, Tuple
from django import setup
from django.contrib.gis.gdal.libgdal import GDAL_VERSION
from django.contrib.gis.geos.libgeos import geos_version_tuple
from django.db import connection
from dotenv import find_dotenv, load_dotenv
# Set up Django environment
load_dotenv(find_dotenv())
setup()
# Minimum required versions for compatibility
# Set these to the minimum versions you want to check against. Currently set to django 5.2 minimums.
MINIMUM_VERSIONS = {
"PostgreSQL": "14.0",
"PostGIS": "3.1",
"GDAL": "3.2",
"GEOS": "3.8",
"PROJ": "6.0",
}
def run_command(command: str) -> Tuple[bool, str, str]:
"""Run a shell command and return success status and output."""
try:
result = subprocess.run(command.split(), capture_output=True, text=True, check=True)
return True, result.stdout.strip(), result.stderr.strip()
except (subprocess.CalledProcessError, FileNotFoundError) as e:
return False, "", str(e)
def get_postgresql_version() -> Optional[str]:
"""Get PostgreSQL version."""
success, output, _error = run_command("psql --version")
if success:
# Extract version from output like "psql (PostgreSQL) 15.4"
parts = output.split()
for part in parts:
if part.replace(".", "").isdigit():
return part
return None
def get_postgis_version() -> Optional[str]:
"""Get PostGIS version from Django's database connection."""
try:
with connection.cursor() as cursor:
cursor.execute("SELECT PostGIS_version();")
result = cursor.fetchone()[0]
# Extract version number from string like "3.3 USE_GEOS=1 USE_PROJ=1..."
version = result.split()[0]
return version
except Exception as e:
print(f"Error getting PostGIS version: {e}")
return None
def get_gdal_version() -> Optional[str]:
"""Get GDAL version."""
return ".".join([str(component) for component in GDAL_VERSION])
def get_geos_version() -> Optional[str]:
"""Get GEOS version."""
return ".".join([str(component) for component in geos_version_tuple()])
def get_proj_version() -> Optional[str]:
"""Get PROJ version."""
success, _output, error = run_command("proj")
if success and "Rel." in error:
# Extract version from output containing "Rel. 8.2.1, January 1st, 2022"
version_part = error.split(",", 1)[0]
return version_part.split("Rel. ")[1]
return None
def compare_versions(current: str, required: str) -> bool:
"""Compare version strings (simple dot-separated version comparison)."""
if not current or not required:
return False
current_parts = [int(x) for x in current.split(".")]
required_parts = [int(x) for x in required.split(".")]
# Pad shorter version with zeros
max_len = max(len(current_parts), len(required_parts))
current_parts.extend([0] * (max_len - len(current_parts)))
required_parts.extend([0] * (max_len - len(required_parts)))
return current_parts >= required_parts
def main():
"""Main function to check all versions."""
print("=" * 80)
print("πŸ” Checking database and geospatial library versions...")
print()
versions = {}
# Get PostgreSQL version
print("πŸ“Š PostgreSQL:")
pg_version = get_postgresql_version()
versions["PostgreSQL"] = pg_version
if pg_version:
compatible = compare_versions(pg_version, MINIMUM_VERSIONS["PostgreSQL"])
status = "βœ… Compatible" if compatible else "❌ Incompatible"
print(f" Current: {pg_version}")
print(f" Required: {MINIMUM_VERSIONS['PostgreSQL']}+")
print(f" Status: {status}\n")
else:
print(" ❌ Could not determine PostgreSQL version\n")
# Get PostGIS version
print("πŸ—ΊοΈ PostGIS:")
postgis_version = get_postgis_version()
versions["PostGIS"] = postgis_version
if postgis_version:
compatible = compare_versions(postgis_version, MINIMUM_VERSIONS["PostGIS"])
status = "βœ… Compatible" if compatible else "❌ Incompatible"
print(f" Current: {postgis_version}")
print(f" Required: {MINIMUM_VERSIONS['PostGIS']}+")
print(f" Status: {status}\n")
else:
print(" ❌ Could not determine PostGIS version\n")
# Get GDAL version
print("🌍 GDAL:")
gdal_version = get_gdal_version()
versions["GDAL"] = gdal_version
if gdal_version:
compatible = compare_versions(gdal_version, MINIMUM_VERSIONS["GDAL"])
status = "βœ… Compatible" if compatible else "❌ Incompatible"
print(f" Current: {gdal_version}")
print(f" Required: {MINIMUM_VERSIONS['GDAL']}+")
print(f" Status: {status}\n")
else:
print(" ❌ Could not determine GDAL version\n")
# Get GEOS version
print("πŸ“ GEOS:")
geos_version = get_geos_version()
versions["GEOS"] = geos_version
if geos_version:
compatible = compare_versions(geos_version, MINIMUM_VERSIONS["GEOS"])
status = "βœ… Compatible" if compatible else "❌ Incompatible"
print(f" Current: {geos_version}")
print(f" Required: {MINIMUM_VERSIONS['GEOS']}+")
print(f" Status: {status}\n")
else:
print(" ❌ Could not determine GEOS version\n")
# Get PROJ version
print("πŸ—ΊοΈ PROJ:")
proj_version = get_proj_version()
if isinstance(proj_version, tuple):
proj_version = ".".join(map(str, proj_version))
versions["PROJ"] = proj_version
if proj_version:
compatible = compare_versions(proj_version, MINIMUM_VERSIONS["PROJ"])
status = "βœ… Compatible" if compatible else "❌ Incompatible"
print(f" Current: {proj_version}")
print(f" Required: {MINIMUM_VERSIONS['PROJ']}+")
print(f" Status: {status}\n")
else:
print(" ❌ Could not determine PROJ version\n")
# Summary
print("=" * 80)
print("πŸ“‹ SUMMARY")
print("=" * 80)
all_compatible = True
for lib, version in versions.items():
if version:
compatible = compare_versions(version, MINIMUM_VERSIONS[lib])
status_icon = "βœ…" if compatible else "❌"
print(f"{status_icon} {lib}: {version} (required: {MINIMUM_VERSIONS[lib]}+)")
if not compatible:
all_compatible = False
else:
print(f"❓ {lib}: Version could not be determined")
all_compatible = False
print("\n" + "=" * 80)
if all_compatible:
print("πŸŽ‰ All database and geospatial libraries meet minimum versions!")
else:
print("⚠️ Some versions do not meet minimum requirements.")
print(" Please upgrade incompatible libraries before proceeding.")
print("=" * 80)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment