-
-
Notifications
You must be signed in to change notification settings - Fork 260
Open
Description
Describe the bug
I tired to use openapi-python-client to generate API wrapper for some Norwegian time tracking system (api.tidsbanken.net/developer.tidsbanken.net).
Some api call https://api.tidsbanken.net/ansatt/ansatt?%24select=Id&%24top=3 (ansatt = worker) returns:
b'{"@odata.context":"https://api.tidsbanken.net/ansatt/$metadata#Ansatt(Id)","value":[{"Id":1},{"Id":4},{"Id":5}]}'
But that results in error:
Traceback (most recent call last):
File "/home/vincas/code/python/tidsbanken_test/tidsbanken_test.py", line 82, in <module>
main()
File "/home/vincas/code/python/tidsbanken_test/tidsbanken_test.py", line 77, in main
emp = get_all_employees(client)
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/vincas/code/python/tidsbanken_test/tidsbanken_test.py", line 21, in get_all_employees
return getansatt.sync(
^^^^^^^^^^^^^^^
File "/home/vincas/code/python/tidsbanken_test/ansatt-client/ansatt_client/api/ansatt/getansatt.py", line 184, in sync
return sync_detailed(
^^^^^^^^^^^^^^
File "/home/vincas/code/python/tidsbanken_test/ansatt-client/ansatt_client/api/ansatt/getansatt.py", line 141, in sync_detailed
return _build_response(client=client, response=response)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/vincas/code/python/tidsbanken_test/ansatt-client/ansatt_client/api/ansatt/getansatt.py", line 82, in _build_response
parsed=_parse_response(client=client, response=response),
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/vincas/code/python/tidsbanken_test/ansatt-client/ansatt_client/api/ansatt/getansatt.py", line 61, in _parse_response
componentsschemas_get_ansatt_model_item = GetAnsattModelItem.from_dict(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/vincas/code/python/tidsbanken_test/ansatt-client/ansatt_client/models/get_ansatt_model_item.py", line 295, in from_dict
d = dict(src_dict)
^^^^^^^^^^^^^^
ValueError: dictionary update sequence element #0 has length 1; 2 is required
OpenAPI Spec File
https://gist.github.com/Talkless/6199fbb4b0b4f62d0b2da6d4c78ec344
Desktop (please complete the following information):
- OS: Debian 12 amd64
- Python Version: 3.11
- openapi-python-client version 0.27.1
Additional context
ChatGPT suggested to patch def _parse_response in ansatt-client/ansatt_client/api/ansatt/getansatt.py into:
def _parse_response(
*, client: AuthenticatedClient | Client, response: httpx.Response
) -> list[GetAnsattModelItem] | None:
if response.status_code == 200:
data = response.json()
# OData always wraps results inside "value"
if isinstance(data, dict) and "value" in data:
items = data["value"]
else:
items = data
result = []
for raw in items:
# raw is a dict like {"Id": 1}
result.append(GetAnsattModelItem.from_dict(raw))
return result
if client.raise_on_unexpected_status:
raise errors.UnexpectedStatus(response.status_code, response.content)
return NoneAnd then it starts working.
Now I get list of GetAnsattModelItem (with just Id as requested):
[GetAnsattModelItem(id=1, fornavn=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, etternavn=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, adresse=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, postnummer=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, poststed=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, tlf_privat=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, mobil=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, epost=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, fodt=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, tittel=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, lonnskonto=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, ansatt_dato=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, personnummer=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, sluttet=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, sluttet_dato=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, avdeling_id=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, aktiv=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, identifikator=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, antall_ferie_dager=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, notat=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, prosjekt_id=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, stillingsprosent=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, element_1_id=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, element_2_id=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, kjonn=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, kommune=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, ansatt_gruppe_id=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, innleie=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, fastlonn=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, ice_navn=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, ice_nr=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, personalia_bekreftet=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, antall_halve_ferie_dager=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, utelat_rapporter=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, utelat_status_rapporter=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, utelat_fra_lonn=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, filnavn=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, ekstern_id=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, timelonn=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, sist_endret_dato=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, sist_endret_av_id=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, opprettet_dato=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, opprettet_av_id=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, additional_properties={}), GetAnsattModelItem(id=4, fornavn=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, etternavn=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, adresse=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, postnummer=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, poststed=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, tlf_privat=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, mobil=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, epost=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, fodt=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, tittel=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, lonnskonto=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, ansatt_dato=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, personnummer=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, sluttet=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, sluttet_dato=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, avdeling_id=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, aktiv=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, identifikator=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, antall_ferie_dager=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, notat=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, prosjekt_id=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, stillingsprosent=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, element_1_id=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, element_2_id=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, kjonn=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, kommune=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, ansatt_gruppe_id=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, innleie=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, fastlonn=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, ice_navn=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, ice_nr=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, personalia_bekreftet=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, antall_halve_ferie_dager=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, utelat_rapporter=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, utelat_status_rapporter=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, utelat_fra_lonn=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, filnavn=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, ekstern_id=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, timelonn=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, sist_endret_dato=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, sist_endret_av_id=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, opprettet_dato=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, opprettet_av_id=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, additional_properties={}), GetAnsattModelItem(id=5, fornavn=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, etternavn=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, adresse=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, postnummer=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, poststed=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, tlf_privat=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, mobil=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, epost=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, fodt=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, tittel=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, lonnskonto=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, ansatt_dato=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, personnummer=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, sluttet=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, sluttet_dato=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, avdeling_id=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, aktiv=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, identifikator=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, antall_ferie_dager=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, notat=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, prosjekt_id=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, stillingsprosent=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, element_1_id=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, element_2_id=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, kjonn=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, kommune=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, ansatt_gruppe_id=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, innleie=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, fastlonn=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, ice_navn=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, ice_nr=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, personalia_bekreftet=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, antall_halve_ferie_dager=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, utelat_rapporter=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, utelat_status_rapporter=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, utelat_fra_lonn=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, filnavn=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, ekstern_id=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, timelonn=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, sist_endret_dato=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, sist_endret_av_id=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, opprettet_dato=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, opprettet_av_id=<ansatt_client.types.Unset object at 0x7f33deffe0d0>, additional_properties={})]
So in the end I am not sure what to make of it:
- Does tidsbanken api returns result in non-conforming format?
- Is .yaml specification wrong so that
openapi-python-clientgenerates sub-optimal code? - Or it's just some bug in
openapi-python-client?
Thanks!
My example application:
from pathlib import Path
from typeguard import typechecked
import httpx
import sys
# Add the folder that contains ansatt_client/
sys.path.append(str(Path(__file__).parent / "ansatt-client"))
from ansatt_client import Client
from ansatt_client.api.ansatt import getansatt
class Consts:
TB_KEY = "redacted" # "API key"
SUBSCRIPTION_KEY = "redacted"
@typechecked
def get_all_employees(client: Client):
return getansatt.sync(
client=client,
select="Id",
top=3,
tb_key = Consts.TB_KEY)
def log_request(request):
print(f"Request event hook: {request.method} {request.url} - Waiting for response")
def log_response(response: httpx.Response):
request = response.request
print(f"Response event hook: {request.method} {request.url} - Status {response.status_code}")
print("---- HEADERS ----")
for k, v in response.headers.items():
print(f"{k}: {v}")
print("---- END HEADERS ----")
try:
response.read()
except Exception as e:
print("ERROR during response.read():", e)
print("---- RAW RESPONSE BODY ----")
try:
# Show raw for debugging JSON truncation
print(response.content)
except Exception as e:
print("ERROR reading .content:", e)
print("---- END RAW RESPONSE BODY ----")
def main():
client = Client(
base_url="https://api.tidsbanken.net/ansatt",
timeout=30,
headers={
"tb-key": Consts.TB_KEY,
"Ocp-Apim-Subscription-Key": Consts.SUBSCRIPTION_KEY,
"x-api-version": "3.0",
"Cache-Control": "no-cache",
},
httpx_args={
"event_hooks": {
"request": [log_request],
"response": [log_response]
}
})
emp = get_all_employees(client)
print(emp)
if __name__ == "__main__":
main()
Metadata
Metadata
Assignees
Labels
No labels