sqlalchemy-postgres-point
Lightweight, pure-Python SQLAlchemy custom type for PostgreSQL POINT columns.
Why
PostgreSQL has a native POINT type (stored internally as a pair of float8 values). SQLAlchemy does not ship a dedicated high-level type wrapper for simple geometric primitives. This package provides a very small PointType you can use immediately without pulling in a full spatial stack (e.g. PostGIS + GeoAlchemy2) when all you need is storing and retrieving (longitude, latitude) pairs.
Features
- Simple
(lng, lat)tuple binding and result conversion. - Safe NULL handling.
- Literal rendering for DDL / SQL emission.
- Custom comparator exposing the PostgreSQL earth-distance
<@>operator (returns aFloat). cache_ok = Truefor SQLAlchemy 2.x compilation caching.
Installation
uv add sqlalchemy-postgres-point
Usage
from sqlalchemy import Column, Integer
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy_postgres_point import PointType
class Base(DeclarativeBase):
pass
class Place(Base):
__tablename__ = "places"
id = Column(Integer, primary_key=True)
# Store as (longitude, latitude)
location = Column(PointType)
# Example query using the custom comparator
from sqlalchemy import select
origin = (0.0, 0.0)
stmt = select(Place.id, Place.location.earth_distance(origin).label("dist"))
The comparator translates Place.location.earth_distance(origin) into SQL using the <@> operator (requires PostgreSQL with the cube / earthdistance extension for meaningful results; without extensions the operator may not exist—adapt as needed for your environment). This library only emits the operator; it does not manage PostgreSQL extensions.
PostgreSQL Extensions Setup
To use the earth distance functionality (earth_distance() comparator), you need to enable the cube and earthdistance PostgreSQL extensions. These extensions provide spatial operations for calculating distances between geographic points on Earth's surface using a spherical model.
Alembic Migration Example
If you're using Alembic for database migrations, you can create a migration to enable these extensions:
"""Add PostgreSQL extensions for earth distance calculations
Revision ID: your_revision_id
Revises: your_previous_revision
Create Date: 2025-01-XX XX:XX:XX.XXXXXX
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision: str = "your_revision_id"
down_revision: Union[str, None] = "your_previous_revision"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
op.execute("""
CREATE EXTENSION IF NOT EXISTS cube;
CREATE EXTENSION IF NOT EXISTS earthdistance;
""")
def downgrade() -> None:
op.execute("""
DROP EXTENSION IF EXISTS earthdistance;
DROP EXTENSION IF EXISTS cube;
""")
Integration Steps
- Generate a new migration:
alembic revision -m "add_postgres_extensions" - Copy the
upgrade()anddowngrade()functions above into your new migration file - Run the migration:
alembic upgrade head
Returned Python Values
Values are loaded as a 2-tuple of floats (lng, lat) or None when NULL.
Alembic Integration
To ensure generated migration files include the correct PointType import, pass the provided render_item hook to context.configure() in your alembic/env.py. This must be added to both run_migrations_online and run_migrations_offline:
from sqlalchemy_postgres_point.alembic_integration import (
render_item as render_point_item,
)
context.configure(
# ... other options ...
render_item=render_point_item,
)
Once wired up, from sqlalchemy_postgres_point import PointType will be automatically included in generated migration files whenever a PointType column is detected.
Chaining render_item
If you need to combine this with other packages that also provide a render_item, chain them:
from sqlalchemy_postgres_point.alembic_integration import (
render_item as render_point_item,
)
def render_item(type_, obj, autogen_context):
return (
render_point_item(type_, obj, autogen_context)
or other_package.render_item(type_, obj, autogen_context)
or False
)
context.configure(
# ... other options ...
render_item=render_item,
)
Or you could use something like some_fn to make this even cleaner.
Limitations / Notes
- Coordinates are validated on both write and read: longitude must be within
[-180, 180], latitude within[-90, 90], and non-finite values (NaN,inf) are rejected with aValueError. - Uses simple textual representation
(lng,lat)accepted by PostgreSQLPOINTinput parser. - If you need advanced spatial indexing / SRID support, look at GeoAlchemy2/PostGIS instead.
This project was created from iloveitaly/python-package-template
Metadata
Release files for sqlalchemy-postgres-point 0.2.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| sqlalchemy_postgres_point-0.2.2.tar.gz | 5.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| sqlalchemy_postgres_point-0.2.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 12.3 kB
Release files / sqlalchemy_postgres_point-0.2.2.tar.gz
| Download URL | sqlalchemy_postgres_point-0.2.2.tar.gz |
|---|---|
| Size | 5.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
dcf28cb09ae5ddd08805d0f9c4c693d1d50e05e26810e658dc1be7fd89e3f85b
|
|
BLAKE2b-256 checksum How to use checksums |
1d59a070cac870584187664fc166d4ccfa6449407a4824200b96fde8a13c571a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.11.19 {"installer":{"name":"uv","version":"0.11.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / sqlalchemy_postgres_point-0.2.2-py3-none-any.whl
| Download URL | sqlalchemy_postgres_point-0.2.2-py3-none-any.whl |
|---|---|
| Size | 6.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
3604f788cb1bc031d549df9151d8a6666488351e4091b9faacc5f771224a3566
|
|
BLAKE2b-256 checksum How to use checksums |
85e052c08c32406418e153e0720740262012d97b82275dbfa22bdda95001dba7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.11.19 {"installer":{"name":"uv","version":"0.11.19","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|