AClimate V3 ORM is an Object-Relational Mapping package designed for the AClimate platform. It facilitates interaction with relational databases for climate data models, forecast systems, agricultural zones, and administrative boundaries. The package provides a structured interface for accessing and manipulating climate historical data at different temporal resolutions.
This is an ORM (Object-Relational Mapping) built with the SQLAlchemy library for interfacing with relational databases.
For complete documentation, visit the
- Modular structure organized by domain (climate, forecast, catalog, administrative, etc.)
- Built using SQLAlchemy for efficient relational mapping
- Compatible with Python > 3.10
- Designed for integration into larger AClimate infrastructure
- Python > 3.10
- Relational database (PostgreSQL recommended, also compatible with MySQL and SQLite)
- Dependencies: SQLAlchemy, psycopg2, python-dotenv, typing_extensions, pydantic
Install directly from GitHub:
pip install git+https://github.com/CIAT-DAPA/aclimate_v3_ormTo install a specific version:
pip install git+https://github.com/CIAT-DAPA/aclimate_v3_orm@v0.0.9You can configure the database connection either by:
- Creating a
.envfile in your project root, OR - Setting environment variables directly in your system
Create a file named .env with these configurations:
DATABASE_URL=postgresql://username:password@localhost:5432/database- Windows (CMD/PowerShell)
set DATABASE_URL=postgresql://username:password@localhost:5432/database- Linux/Ubuntu (Terminal)
export DATABASE_URL="postgresql://username:password@localhost:5432/database"Note
Replace username, password and localhost with your actual credentials
This package includes built-in database migration support using Alembic. Migrations allow you to version control your database schema changes and safely apply them across different environments.
Centralized Approach: All migrations are maintained within the ORM package and distributed to consuming services (API, Admin, Workers, etc.).
aclimate_v3_orm/
βββ src/
βββ aclimate_v3_orm/
βββ migrations/
βββ alembic.ini # Alembic configuration
βββ env.py # Migration environment setup
βββ versions/ # Migration scripts (versioned)
βββ xxxxx_description.py
Benefits:
- β Single source of truth for schema changes
- β Migrations versioned with the package
- β Consistent schema across all services
- β
Automatic conflict prevention via
alembic_versiontable
After modifying SQLAlchemy models, generate a migration:
# Navigate to migrations directory
cd src/aclimate_v3_orm
# Generate migration automatically (detects model changes)
alembic revision --autogenerate -m "Add new table or modify existing"
# Review generated migration in migrations/versions/
# Edit if needed to ensure correctness# Apply all pending migrations
alembic upgrade head
# View current migration status
alembic current
# View migration history
alembic history
# Rollback last migration (if needed)
alembic downgrade -1
# Rollback all migrations
alembic downgrade base# Preview SQL without executing
alembic upgrade head --sql
# Create empty migration (for data migrations)
alembic revision -m "Seed initial data"
# Upgrade to specific revision
alembic upgrade <revision_id>When consuming this ORM package in your services:
from aclimate_v3_orm.migrations import upgrade, current, downgrade
# Apply all pending migrations
upgrade() # Equivalent to: alembic upgrade head
# Check current migration version
current()
# Rollback one migration
downgrade("-1")# From your service directory
python -m alembic upgrade head
python -m alembic current# In your FastAPI/Flask app startup
from aclimate_v3_orm.migrations import upgrade
from aclimate_v3_orm.database import engine
@app.on_event("startup")
async def run_migrations():
"""Apply database migrations on application startup"""
try:
upgrade()
print("β
Database migrations applied successfully")
except Exception as e:
print(f"β Migration failed: {e}")
raiseScenario: Multiple services (API, Admin) sharing the same database.
How it works:
- Alembic creates a table
alembic_versionin your database - This table tracks which migrations have been applied
- When any service runs
upgrade():- β
First service: Acquires lock, applies migrations, updates
alembic_version - β Second service: Sees migrations already applied, skips execution
- β
First service: Acquires lock, applies migrations, updates
- No duplicate migrations or conflicts occur
Important: Always use the same package version across all services:
# β
GOOD - Same version everywhere
API: pip install aclimate_v3_orm==3.0.1
Admin: pip install aclimate_v3_orm==3.0.1
# β BAD - Different versions
API: pip install aclimate_v3_orm==3.0.0
Admin: pip install aclimate_v3_orm==3.0.1βββββββββββββββββββββββββββββββββββββββ
β 1. Developer modifies models β
β in aclimate_v3_orm β
ββββββββββββββββ¬βββββββββββββββββββββββ
β
βββββββββββββββββββββββββββββββββββββββ
β 2. Generate migration β
β alembic revision --autogenerate β
ββββββββββββββββ¬βββββββββββββββββββββββ
β
βββββββββββββββββββββββββββββββββββββββ
β 3. Test migration locally β
β alembic upgrade head β
ββββββββββββββββ¬βββββββββββββββββββββββ
β
βββββββββββββββββββββββββββββββββββββββ
β 4. Commit migration to Git β
β + Publish new package version β
ββββββββββββββββ¬βββββββββββββββββββββββ
β
βββββββββββββββββββββββββββββββββββββββ
β 5. Services upgrade package β
β pip install --upgrade ... β
ββββββββββββββββ¬βββββββββββββββββββββββ
β
βββββββββββββββββββββββββββββββββββββββ
β 6. Services run migrations β
β upgrade() or alembic upgrade β
βββββββββββββββββββββββββββββββββββββββ
Problem: Migration says already applied but table doesn't exist
# Reset migration state
alembic downgrade base
alembic upgrade headProblem: Need to mark database as current without running migrations
# Useful for existing databases
alembic stamp headProblem: Want to see what SQL will be executed
alembic upgrade head --sql > migration.sqlExamples
# Models
from aclimate_v3_orm.models import (
ClimateHistoricalMonthly,
MngCountry,
MngLocation
)
#Services
from aclimate_v3_orm.services import (
ClimateHistoricalMonthlyService,
MngCountryService,
MngLocationService
)
#Schemas
from aclimate_v3_orm.schemas import (
LocationCreate, LocationRead, LocationUpdate,
CountryCreate, CountryRead, CountryUpdate,
ClimateHistoricalClimatologyCreate, ClimateHistoricalClimatologyRead, ClimateHistoricalClimatologyUpdate
)#Init service
country_service = MngCountryService()
#Create new register
new_country = CountryCreate(
name= "Colombia",
iso2= "CL",
enable= True
)
country = country_service.create(obj_in=new_country)
print(country)
#Get register
countries = country_service.get_all()
print(countries)The test suite is organized to validate all service components:
tests/
βββ conftest.py #test config
βββ test_climate_historical_climatology_service.py
βββ test_climate_historical_daily_service.py
βββ test_climate_historical_monthly_service.py
βββ test_mng_admin_1_service.py
βββ test_mng_admin_2_service.py
βββ test_mng_climate_measure_service.py
βββ test_mng_country_service.py
βββ test_mng_location_service.py-
Service-Centric Testing:
- Each production service has a dedicated test file
- Tests validate both business logic and database interactions
-
Test Categories:
- Climate Services: Focus on temporal data operations
- Management Services: Validate CRUD operations for reference data
-
Configuration:
conftest.pycontains:- Database fixtures (in-memory SQLite)
- Mock configurations
- Shared test utilities
-
Testing Approach:
- 100% service layer coverage
- Integration-style tests with real database operations
- Mocking only for external dependencies
# Set up environment
python -m venv env
source env/bin/activate
# Install test dependencies
pip install pytest pytest-mock pytest-cov
# Run all tests
PYTHONPATH=$PYTHONPATH:./src pytest tests/
# Specific test examples:
pytest tests/test_climate_historical_daily_service.py -v # Run specific test file
pytest -k "test_get_daily_data" # Run tests matching patternNote
All tests use an isolated SQLite in-memory database configured in conftest.py, ensuring test independence and execution speed.
Our GitHub Actions pipeline implements a three-stage deployment process:
Code Push β Test Stage β Merge Stage β Release StagePurpose: Quality assurance
Trigger:
- Pushes to
stagebranch - New version tags (
v*)
Key Actions: - Creates isolated Python 3.10 environment
- Installs dependencies + test packages
- Executes complete test suite against in-memory SQLite
- Generates coverage reports
- Enforces 100% service layer test coverage
Exit Criteria: All tests must pass before progression
Purpose: Stable code promotion
Dependencies: Requires Test Phase success
Automation:
- Auto-merges
stageβmainusing branch protection rules - Validates no merge conflicts exist
- Maintains linear commit history
Purpose: Versioned artifact delivery
Key Processes:
-
Semantic Versioning:
- Analyzes commit history for version bump type
- Generates new
vX.Y.Ztag - Updates
setup.pyversion automatically
-
Artifact Packaging:
- Creates production-ready ZIP bundle
- Includes all runtime dependencies
-
Release Management:
- Publishes GitHub Release with changelog
- Attaches versioned binary asset
- Notifies stakeholders
Key Benefits:
- Zero-touch deployment from commit to production
- Enforced quality standards
- Traceable version history
- Automated semantic versioning
aclimate_v3_orm/
β
βββ .github/
β βββ workflows/ # CI/CD pipeline configurations
β
βββ src/
β βββ aclimate_v3_orm/
β βββ models/ # SQLAlchemy ORM models
β βββ schemas/ # Pydantic schemas for validation
β βββ services/ # Service layer for database operations
β βββ validations/ # Validation logic
β βββ enums/ # Application enumerations for type-safe fixed value sets
β βββ database/ # Database connection management
β
βββ tests/ # Test suite organized by service
βββ pyproject.toml # Package configuration
βββ requirements.txt # Package dependencies