Political

Political data primitives: DDL and entities (Seat, OfficeTerm, RedistrictingPlan). Building blocks for downstream analysis.

siege_utilities.political — generic political-infrastructure primitives.

Provides the DDL-layer entities for things shared across political data projects (LegiNation, socialwarehouse, electinfo, future clients):

  • Seat — political identity that persists across redistricting cycles.

  • OfficeTerm / CongressionalTerm — service periods.

  • RedistrictingPlan / PlanDistrictAssignment — plan-scoped Seat→polygon mapping.

  • StateElectionCalendar — per-state election dates per cycle.

Schema lives in a PostgreSQL schema named political — consumer projects apply these migrations via siege_utilities.schema.MigrationRunner pointed at siege_utilities.political.schema_migrations_dir() BEFORE running their own enterprise-specific migrations that FK into political.*.

Django models that wrap these tables (for downstream ORM / API access) live under siege_utilities/political/models/ as managed = False Django models — per the project principle “ontology → DB → Django last.”

siege_utilities.political.schema_migrations_dir()[source]

Return the path to the raw-SQL migrations directory for this module.

Consumer projects hand this to siege_utilities.schema.MigrationRunner so the political tables can be created / evolved alongside the consumer’s own schema migrations.

Typical consumer usage:

from siege_utilities.schema import MigrationRunner
from siege_utilities.political import schema_migrations_dir

political_runner = MigrationRunner(
    dsn=DSN,
    migrations_dir=schema_migrations_dir(),
    tracking_schema="political",
    tracking_table="_schema_migrations",
)
political_runner.apply_all()

# Then run the consumer's own migrations.
Return type:

Path

Submodules

Cross-backend readers for siege_utilities.political tables.

PostgreSQL is the canonical write/DDL home for political schema (raw SQL migrations under migrations/). READ access is available through any DataFrameEngine backend by routing the query through engine.query(sql):

  • PostGISEngine — direct psycopg/SQLAlchemy query against the PG DB

  • SparkEngine — JDBC read via PostgreSQL JDBC driver; Sedona for spatial ops on PG-sourced rows

  • DuckDBEnginepostgres_scanner extension (ATTACH plus query)

  • PandasEngine — falls back to SQLAlchemy + pandas.read_sql

Parameter binding: Readers pass params= to engine.query(). This works correctly on PostGISEngine (psycopg) and PandasEngine (SQLAlchemy). SparkEngine and DuckDBEngine currently ignore the params kwarg — callers targeting those backends must apply filters through the engine’s own mechanisms rather than relying on these helpers.

Callers hand an already-configured engine to these readers; engine construction (connection strings, Spark sessions, DuckDB ATTACH) stays the caller’s responsibility.

See siege_utilities/political/__init__.py for the companion write- side helper schema_migrations_dir().

siege_utilities.political.readers.seats(engine, *, office_code=None, state_code=None, senate_class=None, jurisdiction_code=None)[source]

Read political.seats via the given engine.

Optional filters build a parameterized WHERE clause. Returns whatever the engine’s query method returns (pandas/geopandas DataFrame, Spark DataFrame, DuckDB relation).

Parameters:
  • engine (Any)

  • office_code (str | None)

  • state_code (str | None)

  • senate_class (int | None)

  • jurisdiction_code (str | None)

Return type:

Any

siege_utilities.political.readers.office_terms(engine, *, seat_id=None, incumbent_agent_id=None, current_only=False, as_of_date=None)[source]

Read political.office_terms.

Parameters:
  • engine (Any) – DataFrameEngine instance.

  • seat_id (str | None) – Filter to a specific Seat.

  • incumbent_agent_id (str | None) – Filter to a specific incumbent.

  • current_only (bool) – Only rows where term_end IS NULL.

  • as_of_date (str | None) – ISO date string; returns rows where term was in effect on that date (term_start <= as_of AND (term_end IS NULL OR term_end > as_of)).

Return type:

Any

siege_utilities.political.readers.congressional_terms(engine, *, congress_number=None, election_year=None, is_presidential=None)[source]

Read political.congressional_terms.

Parameters:
  • engine (Any)

  • congress_number (int | None)

  • election_year (int | None)

  • is_presidential (bool | None)

Return type:

Any

siege_utilities.political.readers.redistricting_plans(engine, *, jurisdiction_code=None, plan_type=None, active_only=False)[source]

Read political.redistricting_plans.

Parameters:
  • engine (Any)

  • jurisdiction_code (str | None)

  • plan_type (str | None)

  • active_only (bool)

Return type:

Any

siege_utilities.political.readers.plan_district_assignments(engine, *, plan_id=None, seat_id=None)[source]

Read political.plan_district_assignments.

Parameters:
  • engine (Any)

  • plan_id (str | None)

  • seat_id (str | None)

Return type:

Any

siege_utilities.political.readers.state_election_calendars(engine, *, state_code=None, congress_number=None, election_year=None)[source]

Read political.state_election_calendars.

Parameters:
  • engine (Any)

  • state_code (str | None)

  • congress_number (int | None)

  • election_year (int | None)

Return type:

Any