66from typing import List , Optional
77from uuid import uuid4
88
9+ import httpx
910import jwt
1011from pydantic_settings import BaseSettings , SettingsConfigDict
1112
@@ -47,7 +48,12 @@ def __init__(
4748 timeout : Optional [float ] = 6.0 ,
4849 base_url : Optional [str ] = BASE_URL ,
4950 user_agent : Optional [str ] = None ,
51+ transport = None ,
52+ http_client = None ,
5053 ):
54+ if transport is not None and http_client is not None :
55+ raise ValueError ("Cannot specify both 'transport' and 'http_client'" )
56+
5157 if None in (api_key , api_secret , timeout , base_url ):
5258 s = Settings () # loads from env and optional .env
5359 api_key = api_key or s .api_key
@@ -68,10 +74,29 @@ def __init__(
6874
6975 self .base_url = validate_and_clean_url (base_url )
7076 self .user_agent = user_agent
77+ self ._transport = transport
78+ self ._http_client = http_client
7179 self .token = self ._create_token ()
7280 super ().__init__ (
7381 self .api_key , self .base_url , self .token , self .timeout , self .user_agent
7482 )
83+ # After super().__init__(), self.client is fully built and configured.
84+ # When the user provided custom HTTP config, sub-clients share this
85+ # client instead of each building their own.
86+ if transport is not None or http_client is not None :
87+ self ._shared_client = self .client
88+ else :
89+ self ._shared_client = None
90+
91+ def _apply_shared_client (self , sub_client ):
92+ """Replace a sub-client's auto-created httpx client with the shared
93+ one built from user-provided transport/http_client config."""
94+ if self ._shared_client is not None :
95+ if isinstance (sub_client .client , httpx .Client ):
96+ sub_client .client .close ()
97+ sub_client .client = self ._shared_client
98+ sub_client ._owns_http_client = False
99+ return sub_client
75100
76101 def create_token (
77102 self ,
@@ -169,13 +194,15 @@ def video(self) -> AsyncVideoClient:
169194 Video stream client.
170195
171196 """
172- return AsyncVideoClient (
173- api_key = self .api_key ,
174- base_url = self .base_url ,
175- token = self .token ,
176- timeout = self .timeout ,
177- stream = self ,
178- user_agent = self .user_agent ,
197+ return self ._apply_shared_client (
198+ AsyncVideoClient (
199+ api_key = self .api_key ,
200+ base_url = self .base_url ,
201+ token = self .token ,
202+ timeout = self .timeout ,
203+ stream = self ,
204+ user_agent = self .user_agent ,
205+ )
179206 )
180207
181208 @cached_property
@@ -184,13 +211,15 @@ def chat(self) -> AsyncChatClient:
184211 Chat stream client.
185212
186213 """
187- return AsyncChatClient (
188- api_key = self .api_key ,
189- base_url = self .base_url ,
190- token = self .token ,
191- timeout = self .timeout ,
192- stream = self ,
193- user_agent = self .user_agent ,
214+ return self ._apply_shared_client (
215+ AsyncChatClient (
216+ api_key = self .api_key ,
217+ base_url = self .base_url ,
218+ token = self .token ,
219+ timeout = self .timeout ,
220+ stream = self ,
221+ user_agent = self .user_agent ,
222+ )
194223 )
195224
196225 @cached_property
@@ -199,13 +228,15 @@ def moderation(self) -> AsyncModerationClient:
199228 Moderation stream client.
200229
201230 """
202- return AsyncModerationClient (
203- api_key = self .api_key ,
204- base_url = self .base_url ,
205- token = self .token ,
206- timeout = self .timeout ,
207- stream = self ,
208- user_agent = self .user_agent ,
231+ return self ._apply_shared_client (
232+ AsyncModerationClient (
233+ api_key = self .api_key ,
234+ base_url = self .base_url ,
235+ token = self .token ,
236+ timeout = self .timeout ,
237+ stream = self ,
238+ user_agent = self .user_agent ,
239+ )
209240 )
210241
211242 async def aclose (self ):
@@ -291,13 +322,15 @@ def video(self) -> VideoClient:
291322 Video stream client.
292323
293324 """
294- return VideoClient (
295- api_key = self .api_key ,
296- base_url = self .base_url ,
297- token = self .token ,
298- timeout = self .timeout ,
299- stream = self ,
300- user_agent = self .user_agent ,
325+ return self ._apply_shared_client (
326+ VideoClient (
327+ api_key = self .api_key ,
328+ base_url = self .base_url ,
329+ token = self .token ,
330+ timeout = self .timeout ,
331+ stream = self ,
332+ user_agent = self .user_agent ,
333+ )
301334 )
302335
303336 @cached_property
@@ -306,13 +339,15 @@ def chat(self) -> ChatClient:
306339 Chat stream client.
307340
308341 """
309- return ChatClient (
310- api_key = self .api_key ,
311- base_url = self .base_url ,
312- token = self .token ,
313- timeout = self .timeout ,
314- stream = self ,
315- user_agent = self .user_agent ,
342+ return self ._apply_shared_client (
343+ ChatClient (
344+ api_key = self .api_key ,
345+ base_url = self .base_url ,
346+ token = self .token ,
347+ timeout = self .timeout ,
348+ stream = self ,
349+ user_agent = self .user_agent ,
350+ )
316351 )
317352
318353 @cached_property
@@ -321,13 +356,15 @@ def moderation(self) -> ModerationClient:
321356 Moderation stream client.
322357
323358 """
324- return ModerationClient (
325- api_key = self .api_key ,
326- base_url = self .base_url ,
327- token = self .token ,
328- timeout = self .timeout ,
329- stream = self ,
330- user_agent = self .user_agent ,
359+ return self ._apply_shared_client (
360+ ModerationClient (
361+ api_key = self .api_key ,
362+ base_url = self .base_url ,
363+ token = self .token ,
364+ timeout = self .timeout ,
365+ stream = self ,
366+ user_agent = self .user_agent ,
367+ )
331368 )
332369
333370 @cached_property
@@ -336,13 +373,15 @@ def feeds(self) -> FeedsClient:
336373 Feeds stream client.
337374
338375 """
339- return FeedsClient (
340- api_key = self .api_key ,
341- base_url = self .base_url ,
342- token = self .token ,
343- timeout = self .timeout ,
344- stream = self ,
345- user_agent = self .user_agent ,
376+ return self ._apply_shared_client (
377+ FeedsClient (
378+ api_key = self .api_key ,
379+ base_url = self .base_url ,
380+ token = self .token ,
381+ timeout = self .timeout ,
382+ stream = self ,
383+ user_agent = self .user_agent ,
384+ )
346385 )
347386
348387 @telemetry .operation_name ("getstream.api.common.create_user" )
0 commit comments