Python – python/object/apply:sqlalchemy.sql.elements.quoted_name

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.

Kommentar verfassen

Your email address will not be published. Required fields are marked *

hungsblog | Nguyen Hung Manh | Dresden
Nach oben scrollen