Problem
Every resource-creation method reads the new resource's id straight out of the Location response header, inside the if res.ok: branch:
System.insert_self() — resources/system.py:568
System.add_insert_datastream() — resources/system.py:398
System.add_insert_controlstream() — resources/system.py:446
System.add_and_insert_control_stream() — resources/system.py:530
Datastream.insert_observation_dict() — resources/datastream.py:110
res.ok is true for any 2xx. A server that answers 200 OK or 204 No Content without a Location header — spec-legal, and what some proxies produce after stripping or rewriting headers — makes res.headers['Location'] raise a bare KeyError: 'Location'. The traceback points at a dict lookup, giving no hint that the POST actually succeeded and only the id is missing.
Reproduce
Point any of the above at a server (or proxy) that returns 2xx without Location. In a unit test:
capture_request(monkeypatch, "post", response=MockResponse(status=201)) # no headers
System(label="S", urn="urn:x:1", parent_node=node).insert_self()
# KeyError: 'Location'
Possible fix
Treat a missing Location as its own failure mode, with a message that says the POST succeeded but the id couldn't be recovered:
location = res.headers.get('Location')
if location is None:
raise Exception(
f'System {self.label!r} POST returned HTTP {res.status_code} but no '
f'Location header; cannot determine the server-assigned id.'
)
Same shape at all five sites. Since this is the fifth "the POST path needs a consistent error contract" item, the five bare raise Exception(...) calls are probably worth promoting to a typed exception at the same time.
Related: #42, #43.
Problem
Every resource-creation method reads the new resource's id straight out of the
Locationresponse header, inside theif res.ok:branch:System.insert_self()—resources/system.py:568System.add_insert_datastream()—resources/system.py:398System.add_insert_controlstream()—resources/system.py:446System.add_and_insert_control_stream()—resources/system.py:530Datastream.insert_observation_dict()—resources/datastream.py:110res.okis true for any 2xx. A server that answers200 OKor204 No Contentwithout aLocationheader — spec-legal, and what some proxies produce after stripping or rewriting headers — makesres.headers['Location']raise a bareKeyError: 'Location'. The traceback points at a dict lookup, giving no hint that the POST actually succeeded and only the id is missing.Reproduce
Point any of the above at a server (or proxy) that returns 2xx without
Location. In a unit test:Possible fix
Treat a missing
Locationas its own failure mode, with a message that says the POST succeeded but the id couldn't be recovered:Same shape at all five sites. Since this is the fifth "the POST path needs a consistent error contract" item, the five bare
raise Exception(...)calls are probably worth promoting to a typed exception at the same time.Related: #42, #43.