Observed since 20 Oct, 17:01 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
Internal Partenamut library for PostgreSQL access using Psycopg 3
Internal Partenamut library for PostgreSQL access using Psycopg 3.
Provides a simple and efficient interface for interacting with PostgreSQL using:
PostgreSQLConnection)PostgreSQLPool)Supports query execution (SELECT, INSERT, UPDATE, DELETE), transactions, schema caching, and query runtime statistics.
If you want to install only psycopg functionality (see: Usage of Psycopg for Direct Connection or Pooling)
pip install aa-psycopg
If you also want to install features for validating query configuration with pydantic (see Usage of QueryConfig for Query Management)
pip install aa-psycopg[pydantic]
read_in_chunks) to avoid loading large datasets into memory.ping(retries=0, timeout=60, query_name="ping") -> boolread(query, params=None, query_name=None) -> list[dict]query_name to track query runtime statistics.read_in_chunks(query, params=None, chunk_size=500000, query_name=None) -> Iterator[list[dict]]write(query, params=None, returning=False, query_name=None) -> list[dict] | Nonequery_name to track query runtime statistics.get_stats() -> dictquery_name).get_schema(query) -> list[psycopg.Column]connection -> psycopg.Connectionexecute_transaction(queries_params, query_name=None)
Run multiple queries inside a transaction. Set query_name to track query runtime statistics.
connection() -> ContextManager[psycopg.Connection]
Acquire a temporary connection from the pool.
⚠️ Warning: Query statistics will not be tracked when using PostgreSQLPool connection() or PostrgeSQLConnectionconnection.
It is recommended to use the other execute methods (ping, read, read_in_chunks, write or execute_transaction) instead.
import logging
import json
from aa_psycopg.connection import PostgreSQLConnection
# Configure logging (can adjust level or handlers as needed)
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
logger = logging.getLogger(__name__)
with PostgreSQLConnection(
user="myuser",
password="mypassword",
host="localhost",
port=5432,
db="mydatabase"
) as client:
# Check if database is alive
client.ping()
# Fetch results
results = client.read("SELECT * FROM my_table", query_name="fetch_all")
logger.info("Fetched results: %s", results[:5])
# Stream rows in chunks (efficient for very large result sets)
for i, chunk in enumerate(
client.read_in_chunks(
"SELECT * FROM big_table",
chunk_size=5000, # how many rows to fetch per chunk
query_name="stream_big_table",
)
):
logger.info("Fetched results of chunk %s: %s", i + 1, chunk[:5])
# Write data
client.write(
"INSERT INTO my_table (name) VALUES (%(name)s)",
params={"name": "example"},
query_name="insert_row"
)
logger.info("Inserted row into my_table")
# Transaction
client.execute_transaction([
("INSERT INTO my_table (name) VALUES (%(name)s)", {"name": "row1"}),
("INSERT INTO my_table (name) VALUES (%(name)s)", {"name": "row2"}),
], query_name="bulk_insert")
logger.info("Executed bulk insert transaction")
# Get current active connection for specific usage (e.g. use pandas to query)
df = pd.read_sql("SELECT * FROM users", con=client.connection)
logger.info("Pandas DataFrame: %s", df.head(5))
# Query stats
stats = client.get_stats()
logger.info("Query stats: %s", json.dumps(stats, indent=4))
⚠️ Warning
Only stay in thewithblock as long as you need your connection to be open!
Keep in mind that the connection will remain open as long as the code is running in the with block!
import logging
import json
import pandas as pd
from aa_psycopg.pool import PostgreSQLPool
# Configure logging (can be redirected to CloudWatch or file)
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
logger = logging.getLogger(__name__)
with PostgreSQLPool(
user="myuser",
password="mypassword",
host="localhost",
port=5432,
db="mydatabase",
min_size=0, # pool starts with 0 connections, only creating connection with first query
max_size=1 # pool will not exceed 1 connection
) as client:
# Check connectivity
client.ping()
# Fetch results
results = client.read("SELECT * FROM users WHERE active = true", query_name="active_users")
logger.info("Fetched results: %s", results[:5])
# Stream results in chunks (efficient for very large result sets)
for i, chunk in enumerate(
client.read_in_chunks(
"SELECT * FROM big_table",
chunk_size=5000, # how many rows to fetch per chunk
query_name="stream_big_table",
)
):
logger.info("Fetched results of chunk %s: %s", i + 1, chunk[:5])
# Insert with RETURNING
new_ids = client.write(
"INSERT INTO users (name) VALUES (%(name)s) RETURNING id",
params={"name": "Alice"},
returning=True,
query_name="insert_user"
)
logger.info("Inserted new user IDs: %s", new_ids)
# Bulk transaction
client.execute_transaction([
("UPDATE users SET active=false WHERE id=%(id)s", {"id": 1}),
("DELETE FROM users WHERE active=false", None),
], query_name="cleanup")
logger.info("Executed cleanup transaction")
# Acquiring temporary connection from the pool for specific usage (e.g. use pandas to query)
with client.connection() as conn:
df = pd.read_sql("SELECT * FROM users", con=conn)
# Stats (queries + pool) (dump as JSON)
stats = client.get_stats()
logger.info("Query stats + Pool stats: %s", json.dumps(stats, indent=4))
⚠️ Warning
Only stay in thewithblock as long as you need your connection pool to be open!
Keep in mind that the pool will remain open as long as the code is running in the with block!
QueryConfig for Query ManagementQueryConfig is a Pydantic-based configuration class that allows you to manage SQL queries
and their parameters from either a .sql file or a raw query string.
It can also load configurations from YAML files for easier organization.
QueryConfig is optional. To enable it, install the extra dependencies:
uv pip install aa-psycopg[pydantic]
This will pull in pydantic.
.sql filefrom pathlib import Path
from aa_psycopg.query_config import QueryConfig
cfg = QueryConfig(path_query=Path("queries/get_users.sql"), params={"user_id": 123})
print(cfg.query) # Contents of the SQL file
print(cfg.params) # {"user_id": 123}
from aa_psycopg.query_config import QueryConfig
cfg = QueryConfig(query="SELECT * FROM users WHERE id = %(user_id)s", params={"user_id": 123})
print(cfg.query) # The query string
You can define a query configuration in a .yaml file:
# query_config.yaml
path_query: queries/get_users.sql
params:
user_id: 123
OR
# query_config.yaml
query: |
SELECT * FROM users
WHERE id = %(user_id)s
params:
user_id: 123
Load it using from_yaml:
from aa_psycopg.query_config import QueryConfig
cfg = QueryConfig.from_yaml("query_config.yaml")
print(cfg.query) # SQL contents from the file
print(cfg.params) # {"user_id": 123}
query or path_query..sql file is given, it must exist and have a .sql extension.%(param)s style) must match the keys in params.
If they don’t, a ValueError is raised with details. -->
"""# Example query with a parameter mismatch (SQL expects "id", params gives "user_id")
from aa_psycopg.query_config import QueryConfig
try:
cfg = QueryConfig(
query="SELECT * FROM users WHERE id = %(id)s",
params={"user_id": 123}, # This will cause a validation error
)
except ValueError as e:
print("Validation failed, mismatch detected!")
print(e)
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
Please make sure to update tests as appropriate.
pypistats · 59 observations shown. Missing days are unknown. Source category: overall: without mirrors.
| Date / source period | Value | Observed at |
|---|---|---|
| 2026-10-19 – 2026-10-19 | 2 | 2026-10-20T17:10:47.5082137Z |
| 2026-10-18 – 2026-10-18 | 3 | 2026-10-20T17:10:47.5082137Z |
| 2026-10-17 – 2026-10-17 | 1 | 2026-10-20T17:10:47.5082137Z |
| 2026-10-16 – 2026-10-16 | 7 | 2026-10-20T17:10:47.5082137Z |
| 2026-10-14 – 2026-10-14 | 4 | 2026-10-20T17:10:47.5082137Z |
| 2026-10-13 – 2026-10-13 | 2 | 2026-10-20T17:10:47.5082137Z |
| 2026-10-12 – 2026-10-12 | 1 | 2026-10-20T17:10:47.5082137Z |
| 2026-10-11 – 2026-10-11 | 1 | 2026-10-20T17:10:47.5082137Z |
| 2026-10-10 – 2026-10-10 | 13 | 2026-10-20T17:10:47.5082137Z |
| 2026-10-09 – 2026-10-09 | 9 | 2026-10-20T17:10:47.5082137Z |
| 2026-10-08 – 2026-10-08 | 6 | 2026-10-20T17:10:47.5082137Z |
| 2026-10-07 – 2026-10-07 | 3 | 2026-10-20T17:10:47.5082137Z |
| 2026-10-06 – 2026-10-06 | 6 | 2026-10-20T17:10:47.5082137Z |
| 2026-10-05 – 2026-10-05 | 3 | 2026-10-20T17:10:47.5082137Z |
| 2026-10-02 – 2026-10-02 | 1 | 2026-10-20T17:10:47.5082137Z |
| 2026-10-01 – 2026-10-01 | 1 | 2026-10-20T17:10:47.5082137Z |
| 2026-09-30 – 2026-09-30 | 12 | 2026-10-20T17:10:47.5082137Z |
| 2026-09-29 – 2026-09-29 | 15 | 2026-10-20T17:10:47.5082137Z |
| 2026-09-28 – 2026-09-28 | 10 | 2026-10-20T17:10:47.5082137Z |
| 2026-09-27 – 2026-09-27 | 9 | 2026-10-20T17:10:47.5082137Z |
| 2026-09-26 – 2026-09-26 | 3 | 2026-10-20T17:10:47.5082137Z |
| 2026-09-25 – 2026-09-25 | 2 | 2026-10-20T17:10:47.5082137Z |
| 2026-09-24 – 2026-09-24 | 24 | 2026-10-20T17:10:47.5082137Z |
| 2026-09-21 – 2026-09-21 | 8 | 2026-10-20T17:10:47.5082137Z |
| 2026-09-19 – 2026-09-19 | 1 | 2026-10-20T17:10:47.5082137Z |
| 2026-09-18 – 2026-09-18 | 24 | 2026-10-20T17:10:47.5082137Z |
| 2026-09-17 – 2026-09-17 | 1 | 2026-10-20T17:10:47.5082137Z |
| 2026-09-12 – 2026-09-12 | 1 | 2026-10-20T17:10:47.5082137Z |
| 2026-09-11 – 2026-09-11 | 2 | 2026-10-20T17:10:47.5082137Z |
| 2026-09-07 – 2026-09-07 | 4 | 2026-10-20T17:10:47.5082137Z |
| 2026-09-06 – 2026-09-06 | 2 | 2026-10-20T17:10:47.5082137Z |
| 2026-09-05 – 2026-09-05 | 6 | 2026-10-20T17:10:47.5082137Z |
| 2026-09-03 – 2026-09-03 | 1 | 2026-10-20T17:10:47.5082137Z |
| 2026-09-02 – 2026-09-02 | 1 | 2026-10-20T17:10:47.5082137Z |
| 2026-09-01 – 2026-09-01 | 1 | 2026-10-20T17:10:47.5082137Z |
| 2026-08-31 – 2026-08-31 | 3 | 2026-10-20T17:10:47.5082137Z |
| 2026-08-26 – 2026-08-26 | 1 | 2026-10-20T17:10:47.5082137Z |
| 2026-08-24 – 2026-08-24 | 16 | 2026-10-20T17:10:47.5082137Z |
| 2026-08-23 – 2026-08-23 | 3 | 2026-10-20T17:10:47.5082137Z |
| 2026-08-20 – 2026-08-20 | 1 | 2026-10-20T17:10:47.5082137Z |
| 2026-08-18 – 2026-08-18 | 54 | 2026-10-20T17:10:47.5082137Z |
| 2026-08-17 – 2026-08-17 | 9 | 2026-10-20T17:10:47.5082137Z |
| 2026-08-15 – 2026-08-15 | 1 | 2026-10-20T17:10:47.5082137Z |
| 2026-08-14 – 2026-08-14 | 5 | 2026-10-20T17:10:47.5082137Z |
| 2026-08-13 – 2026-08-13 | 2 | 2026-10-20T17:10:47.5082137Z |
| 2026-08-11 – 2026-08-11 | 1 | 2026-10-20T17:10:47.5082137Z |
| 2026-08-09 – 2026-08-09 | 8 | 2026-10-20T17:10:47.5082137Z |
| 2026-08-07 – 2026-08-07 | 2 | 2026-10-20T17:10:47.5082137Z |
| 2026-08-06 – 2026-08-06 | 1 | 2026-10-20T17:10:47.5082137Z |
| 2026-08-04 – 2026-08-04 | 7 | 2026-10-20T17:10:47.5082137Z |
| 2026-08-03 – 2026-08-03 | 16 | 2026-10-20T17:10:47.5082137Z |
| 2026-08-02 – 2026-08-02 | 1 | 2026-10-20T17:10:47.5082137Z |
| 2026-08-01 – 2026-08-01 | 2 | 2026-10-20T17:10:47.5082137Z |
| 2026-07-29 – 2026-07-29 | 15 | 2026-10-20T17:10:47.5082137Z |
| 2026-07-27 – 2026-07-27 | 2 | 2026-10-20T17:10:47.5082137Z |
| 2026-07-26 – 2026-07-26 | 24 | 2026-10-20T17:10:47.5082137Z |
| 2026-07-24 – 2026-07-24 | 1 | 2026-10-20T17:10:47.5082137Z |
| 2026-07-23 – 2026-07-23 | 2 | 2026-10-20T17:10:47.5082137Z |
| 2026-07-22 – 2026-07-22 | 2 | 2026-10-20T17:10:47.5082137Z |
| Version | Published | Direct dependencies | Open version |
|---|---|---|---|
| 0.1.10 | 30 Jul 2025 | 7 |
This describes our collected data; it is not a security assessment.
Observed since 20 Oct, 17:01 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package:19d21ff5c559ac74bd768bc9f422ca2b479db31498b4cba6d37b0b026a2b4430