Created
July 19, 2025 20:35
-
-
Save kavdev/404282614d66b449a94ad849ccdc79dc to your computer and use it in GitHub Desktop.
Django 5.2 Postgres Library Version Checker
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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