pgpq
Convert PyArrow RecordBatches to Postgres' native binary format.
Usage
Copying a dataset to PostgreSQL using psycopg
"""Example for README.md"""
from tempfile import mkdtemp
import psycopg
import pyarrow.dataset as ds
import requests
from pgpq import ArrowToPostgresBinaryEncoder
# let's get some example data
tmpdir = mkdtemp()
with open(f"{tmpdir}/yellow_tripdata_2023-01.parquet", mode="wb") as f:
resp = requests.get(
"https://d37ci6vzurychx.cloudfront.net/trip-data/yellow_tripdata_2023-01.parquet"
)
resp.raise_for_status()
f.write(resp.content)
# load an arrow dataset
# arrow can load datasets from partitioned parquet files locally or in S3/GCS
# it handles buffering, matching globs, etc.
dataset = ds.dataset(tmpdir)
# create an encoder object which will do the encoding
# and give us the expected Postgres table schema
encoder = ArrowToPostgresBinaryEncoder(dataset.schema)
# get the expected Postgres destination schema
# note that this is _not_ the same as the incoming arrow schema
# and not necessarily the schema of your permanent table
# instead it's the schema of the data that will be sent over the wire
# which for example does not have timezones on any timestamps
pg_schema = encoder.schema()
# assemble ddl for a temporary table
# it's often a good idea to bulk load into a temp table to:
# (1) Avoid indexes
# (2) Stay in-memory as long as possible
# (3) Be more flexible with types
# (you can't load a SMALLINT into a BIGINT column without casting)
cols = [f'"{col_name}" {col.data_type.ddl()}' for col_name, col in pg_schema.columns]
ddl = f"CREATE TEMP TABLE data ({','.join(cols)})"
with psycopg.connect("postgres://postgres:postgres@localhost:5432/postgres") as conn:
with conn.cursor() as cursor:
cursor.execute(ddl) # type: ignore
with cursor.copy("COPY data FROM STDIN WITH (FORMAT BINARY)") as copy:
copy.write(encoder.write_header())
for batch in dataset.to_batches():
copy.write(encoder.write_batch(batch))
copy.write(encoder.finish())
# load into your actual table, possibly doing type casts
# cursor.execute("INSERT INTO \"table\" SELECT * FROM data")
Defining field encoders
"""Showcase defining encoders for fields."""
import pgpq
import psycopg
import pyarrow as pa
from pgpq import encoders
from pgpq import schema
data = [
pa.array([1, 2, 3, 4]),
pa.array(
['{"age": 33, "name": "alice"}', '{"age": 24, "name": "bob"}', "{}", "null"]
),
]
arrow_schema = pa.schema([("id", pa.int64()), ("properties", pa.string())])
record_batch = pa.RecordBatch.from_arrays(data, schema=arrow_schema)
encoder = pgpq.ArrowToPostgresBinaryEncoder(record_batch.schema)
pg_schema_with_text_properties = encoder.schema()
assert [
(col_name, col.data_type.ddl())
for col_name, col in pg_schema_with_text_properties.columns
] == [("id", "INT8"), ("properties", "TEXT")]
# To support a different PostgreSQL schema, we change the default encoders generated by pgpq:
# * 'id' encoded as INT8 (BIGINT).
# * 'properties' encoded as JSONB.
field_encoders = {
"id": encoders.Int64EncoderBuilder(pa.field("id", pa.int64())),
"properties": encoders.StringEncoderBuilder.new_with_output(
pa.field("properties", pa.string()), schema.Jsonb()
),
}
encoder = pgpq.ArrowToPostgresBinaryEncoder.new_with_encoders(
record_batch.schema, field_encoders
)
pg_schema_with_jsonb_properties = encoder.schema()
assert [
(col_name, col.data_type.ddl())
for col_name, col in pg_schema_with_jsonb_properties.columns
] == [("id", "INT8"), ("properties", "JSONB")]
ddl = """
CREATE TABLE id_properties (
id INT8, -- Alternative: BIGINT
properties JSONB
)
"""
# Without the right encoding, PostgreSQL will report errors in the binary data format when
# executing the following COPY: It expects properties to be encoded as JSONB not TEXT.
with psycopg.connect("postgres://posthog:posthog@localhost:5432/posthog") as conn:
with conn.cursor() as cursor:
cursor.execute(ddl)
with cursor.copy("COPY id_properties FROM STDIN WITH (FORMAT BINARY)") as copy:
copy.write(encoder.write_header())
copy.write(encoder.write_batch(record_batch))
copy.write(encoder.finish())
# The 'id' field matches our schema, so we can use the default encoder for it.
# But, we still need to encode properties as JSONB.
# `infer_encoder` can be used to obtain the default encoder for a field.
field_encoders = {
"id": pgpq.ArrowToPostgresBinaryEncoder.infer_encoder(record_batch.field("id")),
"properties": encoders.StringEncoderBuilder.new_with_output(
pa.field("properties", pa.string()), schema.Jsonb()
),
}
encoder = pgpq.ArrowToPostgresBinaryEncoder.new_with_encoders(
record_batch.schema, field_encoders
)
pg_schema_inferred_id_and_jsonb_properties = encoder.schema()
assert [
(col_name, col.data_type.ddl())
for col_name, col in pg_schema_inferred_id_and_jsonb_properties.columns
] == [("id", "INT8"), ("properties", "JSONB")]
with psycopg.connect("postgres://postgres:postgres@localhost:5432/postgres") as conn:
with conn.cursor() as cursor:
with cursor.copy("COPY id_properties FROM STDIN WITH (FORMAT BINARY)") as copy:
copy.write(encoder.write_header())
copy.write(encoder.write_batch(record_batch))
copy.write(encoder.finish())
Release files for pgpq 0.12.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pgpq-0.12.0.tar.gz | 89.2 kB | Details |
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| pgpq-0.12.0-cp310-abi3-win_amd64.whl | CPython 3.10 | abi3 | Windows x86-64 | Details |
| pgpq-0.12.0-cp310-abi3-win32.whl | CPython 3.10 | abi3 | Windows x86-32 | Details |
| pgpq-0.12.0-cp310-abi3-musllinux_1_2_x86_64.whl | CPython 3.10 | abi3 | Linux musl 1.2+ x86-64 | Details |
| pgpq-0.12.0-cp310-abi3-musllinux_1_2_i686.whl | CPython 3.10 | abi3 | Linux musl 1.2+ x86-32 | Details |
| pgpq-0.12.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl | CPython 3.10 | abi3 | Linux glibc 2.17+ x86-64 | Details |
| pgpq-0.12.0-cp310-abi3-manylinux_2_5_i686.manylinux1_i686.whl | CPython 3.10 | abi3 | Linux glibc 2.5+ x86-32 | Details |
| pgpq-0.12.0-cp310-abi3-macosx_10_12_x86_64.whl | CPython 3.10 | abi3 | macOS 10.12+ x86-64 | Details |
| pgpq-0.12.0-cp310-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl | CPython 3.10 | abi3 | macOS 10.12+ x86-64, macOS 10.12+ universal2 (ARM64, x86-64), macOS 11.0+ ARM64 | Details |
Total release size: 7.2 MB
Release files / pgpq-0.12.0.tar.gz
| Download URL | pgpq-0.12.0.tar.gz |
|---|---|
| Size | 89.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d799fa4dd19f54a2aceb3e01a97cd76b8f55e97b0f4aabc1e3e200542f5b74f3
|
|
BLAKE2b-256 checksum How to use checksums |
7dc9edc2c412ff161eb9b7a01a0511c9780b4efd6cfb277793ae02fad33d6ed7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Release files / pgpq-0.12.0-cp310-abi3-win_amd64.whl
| Download URL | pgpq-0.12.0-cp310-abi3-win_amd64.whl |
|---|---|
| Size | 686.3 kB |
| Tags | CPython 3.10 Windows x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
ca157a3c26cece739268a7e0b432047aa837353ab1e5e0f115a616e101eb645d
|
|
BLAKE2b-256 checksum How to use checksums |
ab78ccb91ebc43857909d33f42e138caffda8fd7479655de1ed0f5f0586380b7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Release files / pgpq-0.12.0-cp310-abi3-win32.whl
| Download URL | pgpq-0.12.0-cp310-abi3-win32.whl |
|---|---|
| Size | 610.0 kB |
| Tags | CPython 3.10 Windows x86-32 abi3 |
|
SHA-256 checksum How to use checksums |
7294393f47ad49ca7df0d37981f223f4297ea1347cea78124455c50344d796fc
|
|
BLAKE2b-256 checksum How to use checksums |
3fe1d2c25235679ddf2ca014ccf5803b5f568643c1d0cd271227cc6167443954
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Release files / pgpq-0.12.0-cp310-abi3-musllinux_1_2_x86_64.whl
| Download URL | pgpq-0.12.0-cp310-abi3-musllinux_1_2_x86_64.whl |
|---|---|
| Size | 986.5 kB |
| Tags | CPython 3.10 Linux musl 1.2+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
83aad3991f25374df934e20c7c16c25eb23c51abac09595724b28449e33d37d0
|
|
BLAKE2b-256 checksum How to use checksums |
4bc90a94915b41322ce78053584b908ae09a1c236787ca4eebf70120156fb710
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Release files / pgpq-0.12.0-cp310-abi3-musllinux_1_2_i686.whl
| Download URL | pgpq-0.12.0-cp310-abi3-musllinux_1_2_i686.whl |
|---|---|
| Size | 1.0 MB |
| Tags | CPython 3.10 Linux musl 1.2+ x86-32 abi3 |
|
SHA-256 checksum How to use checksums |
fcc012e1b9fda2053a5c6005402551218b42cf49e0acc029da584c4fd5a3d95f
|
|
BLAKE2b-256 checksum How to use checksums |
ebf83200bd85cb6c2230bea2305e262998a857e23b9bdd1ff28fa9c733ed881a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Release files / pgpq-0.12.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | pgpq-0.12.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 788.9 kB |
| Tags | CPython 3.10 Linux glibc 2.17+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
3ddba7b3e3c397795b119a064f8124a9592959167fee3204ea61c9a14ab49d12
|
|
BLAKE2b-256 checksum How to use checksums |
433f1c4da1550c3d97de5f6d1906a73125b9ee9faf12004e257fbe61bc017db0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Release files / pgpq-0.12.0-cp310-abi3-manylinux_2_5_i686.manylinux1_i686.whl
| Download URL | pgpq-0.12.0-cp310-abi3-manylinux_2_5_i686.manylinux1_i686.whl |
|---|---|
| Size | 846.0 kB |
| Tags | CPython 3.10 Linux glibc 2.5+ x86-32 abi3 |
|
SHA-256 checksum How to use checksums |
96590bb0d164014a7224f061dbd1c13bbfafe5062ec804b96045ab3d7dfcbdc1
|
|
BLAKE2b-256 checksum How to use checksums |
142461d598892ba7ba224596931bc02c5ea082fae32775391fcac824fcd9a7ed
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Release files / pgpq-0.12.0-cp310-abi3-macosx_10_12_x86_64.whl
| Download URL | pgpq-0.12.0-cp310-abi3-macosx_10_12_x86_64.whl |
|---|---|
| Size | 724.9 kB |
| Tags | CPython 3.10 abi3 macOS 10.12+ x86-64 |
|
SHA-256 checksum How to use checksums |
ac8a4c2c4d4e34a5a4f42c73fd1c02d4a11d063a39fe65f5329028eb2c5697ef
|
|
BLAKE2b-256 checksum How to use checksums |
cd93ba8ce95193108a73dc1c8ef75795679f3d299cb2b557977e947b9070a511
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|
Release files / pgpq-0.12.0-cp310-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl
| Download URL | pgpq-0.12.0-cp310-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl |
|---|---|
| Size | 1.4 MB |
| Tags | CPython 3.10 abi3 macOS 10.12+ universal2 (ARM64, x86-64) macOS 10.12+ x86-64 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
ddb5e242bed813f474adc2d18662644b3014d93e53c9ce92100bb026e5e79a01
|
|
BLAKE2b-256 checksum How to use checksums |
571b494cbe730cc7050364420746b329befd8d577625e4223dd702ccb6e3e65e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.3
|