1212
1313import asyncio
1414import json
15+ from collections .abc import Collection
1516from typing import Any
1617
1718from .exceptions import TopicError
1819
1920try :
2021 import aiohttp
22+
2123 HAS_AIOHTTP = True
2224except ImportError :
2325 HAS_AIOHTTP = False
2426
27+ ADMIN_HTTP_TIMEOUT_SECONDS = 10
28+
2529
2630class _AdminHttpTransport :
2731 """Thin REST transport for the Streamline admin HTTP API.
@@ -45,20 +49,22 @@ async def get(self, path: str) -> Any:
4549 if HAS_AIOHTTP :
4650 async with aiohttp .ClientSession () as session :
4751 async with session .get (
48- url , timeout = aiohttp .ClientTimeout (total = 10 )
52+ url ,
53+ timeout = aiohttp .ClientTimeout (total = ADMIN_HTTP_TIMEOUT_SECONDS ),
4954 ) as resp :
50- if resp .status == 404 :
51- raise TopicError (f"Not found: { path } " )
52- if resp .status != 200 :
53- text = await resp .text ()
54- raise TopicError (f"HTTP { resp .status } : { text } " )
55+ await self ._raise_for_status (resp , path , {200 })
5556 return await resp .json ()
5657 else :
5758 import urllib .request
59+
5860 req = urllib .request .Request (url )
61+
5962 def _sync_get ():
60- with urllib .request .urlopen (req , timeout = 10 ) as resp :
63+ with urllib .request .urlopen (
64+ req , timeout = ADMIN_HTTP_TIMEOUT_SECONDS
65+ ) as resp :
6166 return json .loads (resp .read ())
67+
6268 return await asyncio .to_thread (_sync_get )
6369
6470 async def post (self , path : str , body : Any ) -> Any :
@@ -68,22 +74,25 @@ async def post(self, path: str, body: Any) -> Any:
6874 if HAS_AIOHTTP :
6975 async with aiohttp .ClientSession () as session :
7076 async with session .post (
71- url , json = body , timeout = aiohttp .ClientTimeout (total = 10 )
77+ url ,
78+ json = body ,
79+ timeout = aiohttp .ClientTimeout (total = ADMIN_HTTP_TIMEOUT_SECONDS ),
7280 ) as resp :
73- if resp .status == 404 :
74- raise TopicError (f"Not found: { path } " )
75- if resp .status not in (200 , 201 ):
76- text = await resp .text ()
77- raise TopicError (f"HTTP { resp .status } : { text } " )
81+ await self ._raise_for_status (resp , path , {200 , 201 })
7882 return await resp .json ()
7983 else :
8084 import urllib .request
85+
8186 payload = json .dumps (body ).encode ("utf-8" )
8287 req = urllib .request .Request (url , data = payload , method = "POST" )
8388 req .add_header ("Content-Type" , "application/json" )
89+
8490 def _sync_post ():
85- with urllib .request .urlopen (req , timeout = 10 ) as resp :
91+ with urllib .request .urlopen (
92+ req , timeout = ADMIN_HTTP_TIMEOUT_SECONDS
93+ ) as resp :
8694 return json .loads (resp .read ())
95+
8796 return await asyncio .to_thread (_sync_post )
8897
8998 async def delete (self , path : str ) -> None :
@@ -93,17 +102,27 @@ async def delete(self, path: str) -> None:
93102 if HAS_AIOHTTP :
94103 async with aiohttp .ClientSession () as session :
95104 async with session .delete (
96- url , timeout = aiohttp .ClientTimeout (total = 10 )
105+ url ,
106+ timeout = aiohttp .ClientTimeout (total = ADMIN_HTTP_TIMEOUT_SECONDS ),
97107 ) as resp :
98- if resp .status == 404 :
99- raise TopicError (f"Not found: { path } " )
100- if resp .status >= 300 :
101- text = await resp .text ()
102- raise TopicError (f"HTTP { resp .status } : { text } " )
108+ await self ._raise_for_status (resp , path , range (200 , 300 ))
103109 else :
104110 import urllib .request
111+
105112 req = urllib .request .Request (url , method = "DELETE" )
113+
106114 def _sync_delete ():
107- with urllib .request .urlopen (req , timeout = 10 ):
115+ with urllib .request .urlopen (req , timeout = ADMIN_HTTP_TIMEOUT_SECONDS ):
108116 pass
117+
109118 await asyncio .to_thread (_sync_delete )
119+
120+ @staticmethod
121+ async def _raise_for_status (
122+ response : Any , path : str , success_statuses : Collection [int ]
123+ ) -> None :
124+ if response .status == 404 :
125+ raise TopicError (f"Not found: { path } " )
126+ if response .status not in success_statuses :
127+ text = await response .text ()
128+ raise TopicError (f"HTTP { response .status } : { text } " )
0 commit comments