You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
ComplexHelper registers enums/composites connection-globally: later plain SELECTs return Enum members instead of labels #54
Found during the MDMApp rollout (details also in a comment on #51). Affects pgdevkit 0.15.0 (and earlier versions that registered types via ComplexHelper).
pg_retrieve / pg_retrieve_many (and the other pg_* helpers) with a ComplexHelper register every enum/composite type of the table on the connection (load_all_complex_types -> _recurse_register -> register_enum(info, con) / register_composite). The registration is global for that connection and sticks to it in the pool, even though the read path wraps complex columns in to_jsonb(...) and doesn't need any registered type. Afterwards any plainSELECT of that enum type on the same connection returns psycopg's auto-numbered Enum member instead of the label:
con=awaitpsycopg.AsyncConnection.connect(...)
(await (awaitcon.execute("select 'idle'::imp.delta_compute_status")).fetchone()) # ('idle',)awaitpg_retrieve_many(con, M, {}, limit=1, complex_helper=ComplexHelper(con)) # M maps imp.file_import
(await (awaitcon.execute("select 'idle'::imp.delta_compute_status")).fetchone()) # (<Delta_Compute_Status.idle: 1>,)
In MDMApp this made unrelated endpoints/tests return 3 instead of "done" depending on pool order (3 tests failed in the full akeneo_editor suite, all passing in isolation), so MDMApp could not adopt pg_retrieve* and kept its own. Because #52 added complex_helper="auto" (and caches the registration per connection), the blast radius is now every pg_* call on any table with an enum/composite column: other code on the same pooled connection silently sees different values.
Suggested fix (pick one, with a regression test like the snippet above):
Don't register types on the read path that already goes through to_jsonb(...); register only where a Python value must be converted for a write.
Or register enums so they keep returning labels (a str-valued enum via register_enum(info, con, enum=<StrEnum>)), or not at all (the default text loader already returns labels).
Either way, document that register_* is connection-global.
Until fixed: apps using complex_helper= / "auto" on tables with enum columns, on a connection that is also used for plain reads of those enum types, may see enum members instead of strings.
Claude Session: dd3520fe-363b-5088-ab76-5e87fad68be0
PR #55 is ready for review (CI green, version 0.15.1, also fixes an enum[]-inside-composite crash).
ComplexHelper no longer registers anything on the connection: writes register enum/composite adapters on the cursor that runs the statement only (new ComplexHelper.register_on), reads and RETURNING use to_jsonb. A plain SELECT of an enum/composite on the same (pooled) connection behaves exactly as before any pg_* call. Decisions for a human: RETURNING of pg_insert/pg_update_dict/pg_upsert_dict now yields plain values (dict/label) instead of namedtuples/Enum members; direct recursive_convert users must register on their cursor; ComplexHelper.registered kept as a deprecated shim.
Activity
aersam commentedon Oct 9, 2026
PR #55 is ready for review (CI green, version 0.15.1, also fixes an enum[]-inside-composite crash).
ComplexHelper no longer registers anything on the connection: writes register enum/composite adapters on the cursor that runs the statement only (new
ComplexHelper.register_on), reads and RETURNING useto_jsonb. A plain SELECT of an enum/composite on the same (pooled) connection behaves exactly as before anypg_*call. Decisions for a human: RETURNING of pg_insert/pg_update_dict/pg_upsert_dict now yields plain values (dict/label) instead of namedtuples/Enum members; directrecursive_convertusers must register on their cursor;ComplexHelper.registeredkept as a deprecated shim.