Beim Versuch, ein DataFrame in mehrere YAML-Dateien pro Zeile zu konvertieren, bin ich auf die folgende Ausgabe gestoßen:
? !!python/object/apply:sqlalchemy.sql.elements.quoted_name
- read_connection_id
- null
: oracle_orbis
Wobei hier read_connection_id
der Spaltenname ist und oracle_orbis
der dazugehörige Wert.
Kontext
Ich arbeitete mit einer PostgreSQL-Tabelle und musste deren Inhalt in YAML-Dateien umwandeln. Der allgemeine Prozess sah wie folgt aus:

Während des YAML-Konvertierungsschritts trat jedoch eine merkwürdige Meldung auf, welche im Zusammenhang mit quoted_name
stand. Das Problem stammte scheinbar von SQLAlchemy, wo Spaltennamen nicht als regulären String, sondern als sqlalchemy.sql.elements.quoted_name
-Objekte hinterlegt wurden.
Reproduktion des Problems
Um eine PostgreSQL-Tabelle zu lesen und in YAML zu konvertieren könnte ein Code Snippet wie folgt aussehen:
from sqlalchemy import create_engine
import pandas as pd
import yaml
engine = create_engine(db_uri)
df = pd.read_sql_table(table_name, con=engine, schema=schema_name)
for index, row in df.iterrows():
row_dict = row.to_dict()
yaml_data = yaml.dump(row_dict, default_flow_style=False, sort_keys=False)
Dies führte zu YAML-Dumps mit der oben genannten Ausgabe. Jede Zeile begann so mit python/object/apply:sqlalchemy.sql.elements.quoted_name
.
Was ist hier los?
In speziellen Fällen stellt SQLAlchemy Spaltennamen als quoted_name
-Objekten anstelle von einfachen Strings dar (siehe Dokumentation), um Änderungen während des ‘Namen-Normalisierungsprozesses’ zu verhindern. Die Datentypen der Spaltennamen können theorethisch mit df.columns = df.columns.astype(str)
in Strings umgewandelt werden. Allerdings, wenn mit df.iterrows()
durch die Zeilen iteriert und jede Zeile mit .to_dict()
in ein dictionary umgewandelt wird, scheint das quoted_name
-Objekt trotzdem immer noch als Datentyp für die Spaltenname erhalten zu bleiben. Während der YAML-Serialisierung können diese Objekte nicht automatisch in Strings umgewandelt werden, was zu der obigen Ausgabe führt.
Lösung
Um dieses Problem zu beheben, müssen wir sicherstellen, dass alle dictionary Schlüssel in einfache Strings umgewandelt werden. Hier ist eine entsprechende Hilfsfunktion:
from sqlalchemy.sql.elements import quoted_name
def convert_keys_to_strings(d):
"""Recursively convert dictionary keys to plain strings, fixing quoted_name issues."""
if isinstance(d, dict):
return {str(k) if isinstance(k, quoted_name) else k: convert_keys_to_strings(v) for k, v in d.items()}
return d
Der Finale Code
Die Verwendung der Hilfsfunktion vor der YAML-Serialisierung stellt dann eine saubere Umwandlung sicher:
for index, row in df.iterrows():
row_dict = row.to_dict()
filtered_dict = remove_none_values(convert_keys_to_strings(row_dict))
yaml_data = yaml.dump(row_dict, default_flow_style=False, sort_keys=False)
Zusammenfassung
Die ungewöhnliche Ausgabe tritt auf, weil SQLAlchemy quoted_name
-Objekte für Spaltennamen anstelle regulärer Strings verwendet. Die Lösung besteht darin, ditionary Schlüssel rekursiv in einfache Strings umzuwandeln, bevor die Serialisierung zum YAML Format erfolgt.