# Changelog ## 2.0.0 Released 2026-09-18. Built on psycopg 3, for Python 3.11 and later and AgensGraph 2.17 and later. ### Reading - Vertices, edges and paths come back as `Vertex`, `Edge` and `Path`, from either of the server's renderings: the text one by default, and the composite one per statement with `binary_=True`. - `GraphId` identities, hashable values compared on identity, with metadata and user properties in separate namespaces. - A property map is decoded the first time it is read, so a row whose properties are never read never pays for them. - `read_numbers_exactly()` for property maps whose numbers must keep every digit. - `stream()` reads a large result a chunk at a time through a server-side cursor. - `agensgraph.columnar` exports to Arrow, pandas and polars. - `to_json()`, `to_builtins()` and `json_default` hand graph values to anything that wants JSON. ### Writing - `load_vertices()` and `load_edges()` copy elements in with binary `COPY`, and `load_vertex_frame()` and `load_edge_frame()` copy them from a DataFrame. - `upsert_vertices()` and `upsert_edges()` write only what is not already there, keyed on a property or on the pair of vertices an edge joins, and refuse a key nothing keeps unique. - `identity_map()` reads the identities edges need. - Dense and sparse embedding vectors, `nearest()`, and vector indexes built the way a Cypher search matches them. - A Python `str` parameter is sent as `text`, so a string means a string in Cypher and in SQL. - Write counters per statement, `counts_=True`. ### Connections - `AsyncConnection` and the awaiting pools, generated from the same code as the blocking ones. - A pool with a generation counter, so one call retires every connection after a server restart; `drain()`; and `NullConnectionPool`, which keeps nothing. - `Deadline` bounds the wait for a connection and the statements on it together; `conn.deadline()` does it on a connection with no pool. - `RetryPolicy`: six recoveries rather than a yes or no, full jitter under a cap, and a process-wide allowance that time refills. - `transaction_id()` and `resolve_commit()` find out what became of a commit whose answer was lost. - TCP keepalive is asked for by default. - A connection whose statement was interrupted is closed by its pool rather than lent out again. - From AgensGraph 2.18.6 the session's graph is read from what the server reports. ### Catalogs - `graphs()`, `labels()`, `declared_properties()`, `indexes()`, `constraints()`, `vector_indexes()` and `element_counts()`. - `describe()` builds a graph's shape from the catalogs, installing nothing in the database. - `ensure_labels()`, `ensure_indexes()` and `ensure_constraints()` work out what is missing and create it, or return the statements for a caller with no connection. ### Everything else - `read_only_transaction()` for a statement you did not write, which refuses a role that can run programs on the server's host, and `check_single_statement()`. - Query logging, OpenTelemetry spans, and the server's notices as values. - `LISTEN` and `NOTIFY`, with a handler or an iterator. - `pipeline_query()` reads a burst of statements in one round trip, and `pipeline_batch()` writes one. - Failures keep row data out of what they print as; `safe_message()` gives the one line to hand on. - `ReadOnlyGraphWrite`, `ConfigurationError` and `CapabilityError` for refusals the server's codes do not tell apart. - The PEP 249 surface, `agensgraph.dbapi`, which SQLAlchemy's psycopg dialect can use. - Every version string a release has reported parses. - Ships `py.typed`.