digi21.io.postgis

Módulo: digi21.io

Lee las capas de una base de datos PostGIS y les añade geometrías. La ruta que reciben open y create es el archivo de conexión .pg, no un dibujo. El exportador no crea tablas.

import digi21.io.postgis as postgis

open

open(path, digitab=None) -> DrawingFile
Argumento Tipo Descripción
path str Ruta del archivo de conexión .pg.
digitab DigiTab Tabla de códigos (opcional) con el ioPostGis:transform de cada código. Si no se indica, se usa una vacía.

Se conecta a la base de datos del archivo de conexión y devuelve un DrawingFile con las geometrías de sus capas: las tablas con una columna de geometría. Si path no existe, lanza FileNotFoundError; si no puede conectarse, RuntimeError con el mensaje del servidor.

create

create(path, digitab=None, crs="", *, server="localhost", port=5432, user="", password="",
       database="") -> DrawingWriter
Parámetro Tipo Por defecto Descripción
path str — Ruta del archivo de conexión .pg. Si se indica database, create lo escribe; si no, tiene que existir.
digitab DigiTab None Tabla de códigos. Imprescindible: cada código necesita su elemento ioPostGis:transform con su tabla.
crs str "" Opcional. El sistema es el de las capas; si crs no coincide, warnings lo avisa.
server str "localhost" Servidor de PostgreSQL.
port int 5432 Puerto, de 1 a 65535. Fuera de rango, ValueError.
user str "" Usuario.
password str "" Contraseña.
database str "" Base de datos. Si no está vacía, create escribe path con estos cinco valores.

Los parámetros a partir de server son los de la orden PARAMETROS_IMPORTACION para PostGIS, en el mismo orden, y se pasan solo por nombre.

Restricciones de server, user, password y database (cada una lanza ValueError):

  • no pueden tener saltos de línea;
  • no pueden tener a la vez comillas simples y dobles, porque el archivo de conexión delimita cada valor con la comilla que el valor no contiene;
  • no pueden tener caracteres fuera de la página de códigos ANSI de Windows, porque el archivo de conexión se escribe en ella.

El archivo de conexión guarda la contraseña en texto, igual que la aplicación.

Requisito de la tabla de códigos: cada código que se escribe necesita un elemento ioPostGis:transform cuya tabla (table) existe en la base de datos con una columna de geometría:

<code name="020402" description="Texto cotas" type="1" …>
  <io>
    <ioPostGis:transform table="COTA" textHeight="1.000000" />

Excepciones de create: ValueError por un parámetro de conexión no válido; FileNotFoundError si no se indica database y path no existe; RuntimeError con el mensaje del exportador si no puede conectarse.

Ejemplos

Los tres primeros ejemplos no se han ejecutado: no había un servidor PostGIS disponible. Los dos últimos, que no necesitan servidor, se han ejecutado con Python 3.12; su salida es la real. modelo.tab.xml representa una tabla de códigos con el ioPostGis:transform de cada código.

Crear el archivo de conexión y añadir geometrías

import digi21.io.postgis as postgis
from digi21.base import DigiTab, Line, Point

digitab = DigiTab.load("modelo.tab.xml")
with postgis.create("conexion.pg", digitab, server="servidor", port=5432,
                    user="usuario", password="contraseña", database="cartografia") as writer:
    writer.add(Point((500010.0, 4400010.0, 650.0), ["010123"]))
    writer.add(Line(["040645"], [(500000, 4400000, 650), (500100, 4400000, 652), (500100, 4400080, 655)]))

print(writer.written, "escritas,", writer.rejected, "rechazadas")
for aviso in writer.warnings:
    print(aviso)

Las siguientes llamadas pueden usar el conexion.pg sin repetir los datos de conexión: postgis.create("conexion.pg", digitab).

Leer y contar por código

import collections

import digi21.io.postgis as postgis
from digi21.base import DigiTab

digitab = DigiTab.load("modelo.tab.xml")
conteo = collections.Counter()
for geometry in postgis.open("conexion.pg", digitab):
    conteo[geometry.codes[0].code] += 1

for codigo, n in conteo.most_common():
    print(codigo, n)

Convertir un archivo BinDouble a PostGIS

import digi21.io.bindouble as bind
import digi21.io.postgis as postgis
from digi21.base import DigiTab

digitab = DigiTab.load("modelo.tab.xml")
origen = bind.open("parcelas.bind", digitab)
with postgis.create("conexion.pg", digitab) as writer:
    for geometry in origen:
        if not writer.add(geometry):
            print("No se ha escrito:", type(geometry).__name__, [c.code for c in geometry.codes])

print(writer.written, "escritas,", writer.rejected, "rechazadas")

parcelas.bind es el archivo que crea el primer ejemplo de digi21.io.bindouble. Las geometrías tienen que estar en el sistema de coordenadas de las capas.

Errores de los parámetros de conexión

import digi21.io.postgis as postgis

try:
    postgis.create("no-existe.pg")
except FileNotFoundError as error:
    print("FileNotFoundError:", error)

try:
    postgis.create("conexion.pg", server="servidor", port=70000, database="cartografia")
except ValueError as error:
    print("ValueError:", error)
FileNotFoundError: No such file: 'no-existe.pg'. Pass database (and the rest of the connection) to write the .pg connection file.
ValueError: port must be between 1 and 65535.

Sin servidor: el archivo de conexión y el error

import digi21.io.postgis as postgis

try:
    postgis.create("local.pg", server="localhost", port=5432, user="usuario", password="clave",
                   database="cartografia")
except RuntimeError as error:
    print("RuntimeError:", str(error).splitlines()[0][:60])

with open("local.pg", encoding="mbcs") as archivo:
    print(archivo.read())
RuntimeError: Se localizó el siguiente error al conectarse con la base de
host = 'localhost' port = 5432 dbname = 'cartografia' user = 'usuario' password = 'clave'

create escribe el archivo de conexión antes de conectarse, así que el archivo queda escrito aunque la conexión falle. open lanza el mismo RuntimeError si no puede conectarse.

Véase también