Kovertierung Daten

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
theBeginnerScripter
User
Beiträge: 4
Registriert: Samstag 2. Juli 2022, 10:51

HI prinzipiell bin ich schon mit Datentypen und impl und expl Casts dazwischen vertraut, dennoch habe ich ein kleines Problem wo ich nicht weiter weiß.
Hier zur einfachen Aufgabe. Ich bekomme als Antwort von einer API einen Json formatierten String. Dieser soll in ein Excel File konviertiert werden. Unten wird data (list) konvertiert und alles funktioniert perfekt.

Code: Alles auswählen

data = [
    {'a': [1], 'b': 'hello'},
    {'a': [1, 2, 3], 'b': 'world'}
]
conv.convert(data, Writer(file='./apipull.xlsx'))
Nun bekomme ich folgenden String zurück, welchen ich statt data verwenden möchte.

Code: Alles auswählen

  "1": {
    "id": 1,
    "address": "037f611f5629",
    "name": "LS1",
    "firmwareVersion": "33.0",
    "position": 0,
    "fixtureId": 5509,
    "groupId": 0,
    "type": "Sensor"
  },
  "2": {.....
{
Mein Plan wäre gewesen diesen mit wie folgt einzulesen und in die convert func passen:

Code: Alles auswählen

y = json.loads(response.text)
die Datentypen von beiden Datenblöcken sind:
Data Type data:<class 'list'>
Data Type Json load<class 'dict'>

Mit dem Json dict bekomme ich folgenden error: 'str' object has no attribute 'keys'
Nun habe ich gelesen, dass ich mit der items() funk auf die attribute zugreifen kann. Nun bekomme ich folgenden Error: 'tuple' object has no attribute 'keys'

Ich denke ich sitzt einfach irgendwie auf der Leitung und die Lösung ist sehr simpel. Danke im Vorraus und lg
Sirius3
User
Beiträge: 18279
Registriert: Sonntag 21. Oktober 2012, 17:20

Bitte den Code zeigen und nicht irgendeine Umschreibung. Dazu den kompletten Traceback. Niemand hier weiß, was conv.convert macht.
`y` ist ein schlechter Variablenname. Es gibt `response.json()` zum Lesen von json-Antworten.
theBeginnerScripter
User
Beiträge: 4
Registriert: Samstag 2. Juli 2022, 10:51

Code: Alles auswählen

import requests
import json
from json_excel_converter import Converter 
from json_excel_converter.xlsx import Writer

networkIDUG = "kGUzZ57nbsFLe2ZxCMB7ybmO0LEaQsXXX"
networkIDOG = "r9rXox4Zn0wzRLLkcsq6bBczsKfaaXXX"
url = "XXXXX"
geturl1_1 = "XXXXX"
geturlDatapoints = "/datapoints"
geturlUnits = "/units"
filter1 = "?dataType=sensors&from=2022" + startdate + "&to=2022" + enddate + "&tzOffset=%2B1"

startdate = input("Enter startdate(MMDD):")
enddate = input("Enter enddate(MMDD):")

headers = {"Key": "2u5NSHLDMFG3WL6sE3GEcB5FFwSunEGXcMASZSdSeKzeWY9xj46xNRym8XXXXXX"}
request_data = {"email": "", "password": ""}
response = requests.post(url, headers = headers, json=request_data)

print(response.status_code)

sessionIDUG = request.json()[networkIDUG]["sessionId"]
sessionIDOG = request.json()[networkIDOG]["sessionId"]

headers = {"Key": "2u5NSHLDMFG3WL6sE3GEcB5FFwSunEGXcMASZSdSeKzeWY9xj46xNRym8XXXXXX",
          "Session": }
response = requests.get(geturl, headers = headers)
print(response.status_code)

data = [
    {'a': [1], 'b': 'hello'},
    {'a': [1, 2, 3], 'b': 'world'}
]

print("Data Type data:" + str(type(data)))
print("Data Type Json load" + str(type(response.json)))


conv = Converter()
conv.convert(response.json(), Writer(file='./apipull.xlsx'))

Code: Alles auswählen

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-8-b5aad1ace16f> in <module>
     67 
     68 conv = Converter()
---> 69 conv.convert(y.items(), Writer(file='./apipull.xlsx'))

/opt/conda/lib/python3.8/site-packages/json_excel_converter/converter.py in convert(self, data, writer)
     12         while True:
     13             try:
---> 14                 self.convert_streaming(data, writer)
     15                 break
     16             except LinearizationError:

/opt/conda/lib/python3.8/site-packages/json_excel_converter/converter.py in convert_streaming(self, data, writer)
     22             self.conv = Columns(options=self.options)
     23         for idx, d in enumerate(data):
---> 24             errors = self.conv.check(d)
     25             if not idx:
     26                 self._write_header(writer, self.conv)

/opt/conda/lib/python3.8/site-packages/json_excel_converter/linearize.py in check(self, value)
    190         else:
    191             key_func = self.options.sort_key
--> 192             for k in value.keys():
    193                 key_func(k)
    194             pairs = [

AttributeError: 'tuple' object has no attribute 'keys'
Die ist nochmal eine komplette Antwort, da die andere zu lange wäre.

Code: Alles auswählen

{
  "1": {
    "name": "Test low",
    "id": 1,
    "position": 0,
    "icon": 0,
    "color": "#FFFFFF",
    "type": "REGULAR",
    "hidden": false,
    "units": {
      "4": {
        "id": 4
      },
      "5": {
        "id": 5
      },
      "6": {
        "id": 6
      },
      "8": {
        "id": 8
      },
      "9": {
        "id": 9
      },
      "11": {
        "id": 11
      },
      "13": {
        "id": 13
      },
      "14": {
        "id": 14
      },
      "16": {
        "id": 16
      }
    }
  },
  "2": {
    "name": "Test",
    "id": 2,
    "position": 1,
    "icon": 0,
    "color": "#FFFFFF",
    "type": "REGULAR",
    "hidden": false,
    "units": {
      "4": {
        "id": 4
      },
      "5": {
        "id": 5
      },
      "6": {
        "id": 6
      },
      "8": {
        "id": 8
      },
      "9": {
        "id": 9
      },
      "11": {
        "id": 11
      },
      "13": {
        "id": 13
      },
      "14": {
        "id": 14
      },
      "16": {
        "id": 16
      }
    }
  },
  "3": {
    "name": "Liquidationsraum",
    "id": 3,
    "position": 2,
    "icon": 0,
    "color": "#FFFFFF",
    "type": "REGULAR",
    "hidden": false,
    "units": {
      "4": {
        "id": 4
      },
      "5": {
        "id": 5
      },
      "6": {
        "id": 6
      },
      "8": {
        "id": 8
      },
      "9": {
        "id": 9
      }
    }
  },
  "4": {
    "name": "Schachtellager",
    "id": 4,
    "position": 3,
    "icon": 0,
    "color": "#FFFFFF",
    "type": "REGULAR",
    "hidden": false,
    "units": {
      "11": {
        "id": 11
      },
      "13": {
        "id": 13
      },
      "14": {
        "id": 14
      },
      "16": {
        "id": 16
      }
    }
  },
  "5": {
    "name": "Büromaterial",
    "id": 5,
    "position": 4,
    "icon": 0,
    "color": "#FFFFFF",
    "type": "REGULAR",
    "hidden": false,
    "units": {
      "11": {
        "id": 11
      }
    }
  },
  "6": {
    "name": "AN",
    "id": 6,
    "position": 5,
    "icon": 0,
    "color": "#FFFFFF",
    "type": "REGULAR",
    "hidden": false,
    "units": {
      "4": {
        "id": 4
      },
      "5": {
        "id": 5
      },
      "6": {
        "id": 6
      },
      "8": {
        "id": 8
      },
      "9": {
        "id": 9
      },
      "11": {
        "id": 11
      },
      "13": {
        "id": 13
      },
      "14": {
        "id": 14
      },
      "16": {
        "id": 16
      }
    }
  },
  "7": {
    "name": "AUS",
    "id": 7,
    "position": 6,
    "icon": 0,
    "color": "#FFFFFF",
    "type": "REGULAR",
    "hidden": false,
    "units": {
      "4": {
        "id": 4
      },
      "5": {
        "id": 5
      },
      "6": {
        "id": 6
      },
      "8": {
        "id": 8
      },
      "9": {
        "id": 9
      },
      "11": {
        "id": 11
      },
      "13": {
        "id": 13
      },
      "14": {
        "id": 14
      },
      "16": {
        "id": 16
      }
    }
  }
}
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Statt der URL solltest du die secrets entfernen. Ohne die ist die URL harmlos. Aber umgekehrt kann man mit den und etwas raten wahrscheinlich die URL bestimmen.
Benutzeravatar
noisefloor
User
Beiträge: 4195
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

der Fehler besagt, dass du irgendwie irgendwo ein Tuple übergibst bzw. drin ist, während der Konverter ein Dict erwartet.

Wo das herkommt sehe ich zumindest beim gezeigten Code bzw. dem JSON nicht. JSON an sich kennt keine Tuple bzw. kein Äquivalent zu Tuplen. Und wenn du das `json` Modul aus der Python Standardbiblithek verwendest können auch keine Tuple entstehen.

Gruß, noisefloor
theBeginnerScripter
User
Beiträge: 4
Registriert: Samstag 2. Juli 2022, 10:51

Danke dir. Sind natürlich nicht die echten secrets.

Wenn ich in den converter eine list gebe (data), funktioniert das ganze, daher sollte ich vllt meine Frage umformulieren. Wie bringe ich die Antwort am einfachsten in dieselbe Form als das Data Beispiel. Habe schon diverse Ansätze verfolgt, bekomme aber immer denselben Fehler. lg
Benutzeravatar
__blackjack__
User
Beiträge: 14078
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@theBeginnerScripter: Das ist a) offensichtlich nicht der Code den Du laufen hast, denn der verwendet einen undefinierten Namen und zwei Namen werden verwendet bevor sie definiert werden, und b) passt der Code nicht zum Traceback, denn in der betroffenen Zeile steht dort wo in dem gezeigten Code ``response.json()``, im Traceback steht aber ``y.items()``. Beides führt zu einer Ausnahme, allerdings zu jeweils einer leicht anderen. Denn weder `str` (Code) noch `tuple` (Traceback) haben ein `keys`-Attribut.

Die Daten in dem JSON liegen halt nicht in dem Format vor, das diese Bibliothek erwartet. Das hättest Du auch alles ohne irgendwelche `requests` zeigen können, denn das ganze läuft ja darauf hinaus, dass der Konverter ein JSON-Array/eine Python-Liste als Argument erwartet und kein JSON-Objekt/Python-Wörterbuch. Da ist egal wo die Daten herkommen. Jetzt ist die Frage wie Du damit umgehen willst. Reicht es einfach nur die Werte zu nehmen?

Allgemeinere Anmerkungen: Wirf mal einen Blick in den Style Guide for Python Code.

Namen werden in Python klein_mit_unterstrichen geschrieben. Ausnahmen sind Konstanten (KOMPLETT_GROSS) und Klassen (PascalCase). An Namen gehören keine Nummern angehängt. Dann sind die Namen entweder zu generisch und sollten besser gewählt werden, oder man möchte gar keine Einzelnamen, sondern eine Datenstruktur. Oft eine Liste. Bei `filter1` ist es aber einfach nur ein schlechter Name wenn es auch ein `filter2` geben sollte. Der Leser will ja nicht wissen der wievielte Filter das ist, sondern was der bedeutet.

Statt einfach nur `response.status_code` auszugeben und einfach weiter zu machen als wäre alles in Ordnung auch wenn der Status-Code was anderes sagt, ist keine gute Idee. Die Response-Objekte haben eine `raise_for_status()`-Methode, die man an der Stelle wohl besser verwenden würde.

Code und Daten sollten nicht wiederholt werden. Wenn Du etwas kopierst, einfügst, und leicht abänderst, sollte das in der Regel ein Alarmzeichen sein, dass Du da etwas falsches machst.

Das was da für `filter1` als Zeichenkette zusammengebastelt wird, würde ich `requests` überlassen und die Daten als Wörterbuch als `params`-Argument übergeben.

Falls bestimmte Header mit *jeder* Anfrage gesendet werden sollen, macht man sich das Leben mit einer `requests.Session` einfacher.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
theBeginnerScripter
User
Beiträge: 4
Registriert: Samstag 2. Juli 2022, 10:51

Hi,
a.) danke für die ausführliche Antwort
b.) danke für die konstruktiven Tipps
c.) mit dem Konverter hast du richtig getippt
Hätte es einfach von einem dict in einen Liste konvertieren müssen. Problem somit gelöst. danke und lg

Code: Alles auswählen

for k, v in response.items():
	result.append({'key': k, 'value': v})
Antworten