fail-fast: false
matrix:
include:
- - {impl: python, python: 3.6, postgres: 10}
- - {impl: python, python: 3.7, postgres: 11}
- - {impl: python, python: 3.8, postgres: 12}
- - {impl: python, python: 3.9, postgres: 13}
- - {impl: c, python: 3.6, postgres: 13}
- - {impl: c, python: 3.7, postgres: 12}
- - {impl: c, python: 3.8, postgres: 11}
- - {impl: c, python: 3.9, postgres: 10}
- - {impl: dns, python: 3.9, postgres: 13}
+ - {impl: python, python: 3.6, image: "postgres:10"}
+ - {impl: python, python: 3.7, image: "postgres:11"}
+ - {impl: python, python: 3.8, image: "postgres:12"}
+ - {impl: python, python: 3.9, image: "postgres:13"}
+ - {impl: c, python: 3.6, image: "postgres:13"}
+ - {impl: c, python: 3.7, image: "postgres:12"}
+ - {impl: c, python: 3.8, image: "postgres:11"}
+ - {impl: c, python: 3.9, image: "postgres:10"}
+ - {impl: dns, python: 3.9, image: "postgres:13"}
+ - {impl: postgis, python: 3.9, image: "postgis/postgis:13-master"}
env:
PSYCOPG_IMPL: ${{ matrix.impl }}
env:
PSYCOPG_IMPL: python
+ - name: Run PostGIS-related tests
+ run: tox -c psycopg -e postgis -- --color yes -m postgis
+ if: ${{ matrix.impl == 'postgis' }}
+ env:
+ PSYCOPG_IMPL: python
+
services:
postgresql:
- image: postgres:${{ matrix.postgres }}
+ image: ${{ matrix.image }}
env:
POSTGRES_PASSWORD: password
ports:
run: tox -c psycopg_c -e ${{ matrix.python }} -- --color yes
if: ${{ matrix.impl == 'c' }}
-
windows:
name: Test on Windows
runs-on: windows-2019
--- /dev/null
+import pytest
+
+from psycopg.pq import Format
+from psycopg.types import TypeInfo
+from psycopg.types.shapely import register_shapely
+from psycopg import ProgrammingError
+from shapely.geometry import Point, Polygon
+
+pytestmark = [pytest.mark.postgis]
+pytest.importorskip("shapely")
+
+# real example, with CRS and "holes"
+MULTIPOLYGON_GEOJSON = """
+{
+ "type":"MultiPolygon",
+ "crs":{
+ "type":"name",
+ "properties":{
+ "name":"EPSG:3857"
+ }
+ },
+ "coordinates":[
+ [
+ [
+ [1489574.61111389, 6894228.638802719],
+ [89576.815239808, 6894208.60747024],
+ [89576.904295401, 6894207.820852726],
+ [89577.99522641, 6894208.022080451],
+ [89577.961830563, 6894209.229446936],
+ [89589.227363031, 6894210.601454523],
+ [89594.615226386, 6894161.849595264],
+ [89600.314784314, 6894111.37846976],
+ [89651.187791607, 6894116.774968589],
+ [89648.49385993, 6894140.226914071],
+ [89642.92788539, 6894193.423936413],
+ [89639.721884055, 6894224.08372821],
+ [89589.283022777, 6894218.431048969],
+ [89588.192091767, 6894230.248628867],
+ [89574.61111389, 6894228.638802719]
+ ],
+ [
+ [1489610.344670435, 6894182.466199101],
+ [89625.985058891, 6894184.258949757],
+ [89629.547282597, 6894153.270030369],
+ [89613.918026089, 6894151.458993318],
+ [89610.344670435, 6894182.466199101]
+ ]
+ ]
+ ]
+}"""
+
+SAMPLE_POINT_GEOJSON = '{"type":"Point","coordinates":[1.2, 3.4]}'
+
+SAMPLE_POINT = Point(1.2, 3.4)
+SAMPLE_POLYGON = Polygon([(0, 0), (1, 1), (1, 0)])
+
+
+@pytest.fixture
+def shapely_conn(conn):
+ info = TypeInfo.fetch(conn, "geometry")
+ register_shapely(info, conn)
+ return conn
+
+
+def test_no_adapter(conn):
+ point = Point(1.2, 3.4)
+ with pytest.raises(ProgrammingError, match="cannot adapt type Point"):
+ conn.execute("SELECT pg_typeof(%s)", [point]).fetchone()[0]
+
+
+def test_with_adapter(shapely_conn):
+ assert (
+ shapely_conn.execute(
+ "SELECT pg_typeof(%s)",
+ [SAMPLE_POINT],
+ ).fetchone()[0]
+ == "geometry"
+ )
+
+ assert (
+ shapely_conn.execute(
+ "SELECT pg_typeof(%s)",
+ [SAMPLE_POLYGON],
+ ).fetchone()[0]
+ == "geometry"
+ )
+
+
+@pytest.mark.parametrize("fmt_out", [Format.TEXT, Format.BINARY])
+def test_write_read_shape(shapely_conn, fmt_out):
+ with shapely_conn.cursor(binary=fmt_out) as cur:
+ cur.execute(
+ """
+ create table sample_geoms(
+ id INTEGER PRIMARY KEY,
+ geom geometry
+ )
+ """
+ )
+ cur.execute(
+ "insert into sample_geoms(id, geom) VALUES(1, %s)", (SAMPLE_POINT,)
+ )
+ cur.execute(
+ "insert into sample_geoms(id, geom) VALUES(2, %s)",
+ (SAMPLE_POLYGON,),
+ )
+
+ cur.execute("select geom from sample_geoms where id=1")
+ result = cur.fetchone()[0]
+ assert result == SAMPLE_POINT
+
+ cur.execute("select geom from sample_geoms where id=2")
+ result = cur.fetchone()[0]
+ assert result == SAMPLE_POLYGON
+
+
+@pytest.mark.parametrize("fmt_out", [Format.TEXT, Format.BINARY])
+def test_match_geojson(shapely_conn, fmt_out):
+ with shapely_conn.cursor(binary=fmt_out) as cur:
+ cur.execute(
+ f"""
+ select ST_GeomFromGeoJSON('{SAMPLE_POINT_GEOJSON}')
+ """
+ )
+ result = cur.fetchone()[0]
+ # clone the coordinates to have a list instead of a shapely wrapper
+ assert result.coords[:] == SAMPLE_POINT.coords[:]