Skip to content

Commit 5797bc6

Browse files
authored
Merge branch 'main' into fix/typed-list-pydantic-parsed
2 parents 43dbacf + 624c8e7 commit 5797bc6

File tree

11 files changed

+496
-299
lines changed

11 files changed

+496
-299
lines changed

README.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,31 @@ client = genai.Client(
109109
)
110110
```
111111

112+
### Proxy
113+
114+
When you use the default httpx client, both sync and async use
115+
`urllib.request.getproxies` from environment variables.
116+
Before client initialization, you may set proxy (and optional SSL_CERT_FILE) by setting the environment variables:
117+
118+
119+
```bash
120+
export HTTPS_PROXY='http://username:password@proxy_uri:port'
121+
export SSL_CERT_FILE='client.pem'
122+
```
123+
124+
If you need `socks5` proxy. httpx [supports](https://www.python-httpx.org/advanced/proxies/#socks) `socks5` proxy if you pass it via
125+
args to `httpx.Client()`. You can pass it through the following way:
126+
127+
```python
128+
129+
http_options = types.HttpOptions(
130+
client_args=...,
131+
async_client_args=..,.
132+
)
133+
134+
client=Client(..., http_options=http_options).
135+
```
136+
112137
## Types
113138

114139
Parameter types can be specified as either dictionaries(`TypedDict`) or

docs/_sources/index.rst.txt

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,33 @@ To set the API version to `v1alpha` for the Gemini Developer API:
115115
)
116116
117117
118+
Proxy
119+
^^^^^^^
120+
121+
When you use the default httpx client, both sync and async use
122+
`urllib.request.getproxies` from environment variables.
123+
Before client initialization, you may set proxy (and optional SSL_CERT_FILE)
124+
by setting the environment variables:
125+
126+
.. code:: bash
127+
128+
export HTTPS_PROXY='http://username:password@proxy_uri:port'
129+
export SSL_CERT_FILE='client.pem'
130+
131+
132+
If you need `socks5` proxy. httpx supports `socks5` proxy if you pass it via
133+
args to httpx.Client(). You can pass it through the following way:
134+
135+
.. code:: python
136+
137+
http_options = types.HttpOptions(
138+
client_args=...,
139+
async_client_args=..,.
140+
)
141+
142+
client=Client(..., http_options=http_options)
143+
144+
118145
Types
119146
-----
120147

docs/genai.html

Lines changed: 234 additions & 234 deletions
Large diffs are not rendered by default.

docs/index.html

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,29 @@ <h3>API Selection<a class="headerlink" href="#api-selection" title="Link to this
353353
</pre></div>
354354
</div>
355355
</section>
356+
<section id="proxy">
357+
<h3>Proxy<a class="headerlink" href="#proxy" title="Link to this heading">¶</a></h3>
358+
<dl class="simple">
359+
<dt>When you use the default httpx client, both sync and async use</dt><dd><p><cite>urllib.request.getproxies</cite> from environment variables.</p>
360+
</dd>
361+
</dl>
362+
<p>Before client initialization, you may set proxy (and optional SSL_CERT_FILE)
363+
by setting the environment variables:</p>
364+
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span><span class="nb">export</span><span class="w"> </span><span class="nv">HTTPS_PROXY</span><span class="o">=</span><span class="s1">&#39;http://username:password@proxy_uri:port&#39;</span>
365+
<span class="nb">export</span><span class="w"> </span><span class="nv">SSL_CERT_FILE</span><span class="o">=</span><span class="s1">&#39;client.pem&#39;</span>
366+
</pre></div>
367+
</div>
368+
<p>If you need <cite>socks5</cite> proxy. httpx supports <cite>socks5</cite> proxy if you pass it via
369+
args to httpx.Client(). You can pass it through the following way:</p>
370+
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">http_options</span> <span class="o">=</span> <span class="n">types</span><span class="o">.</span><span class="n">HttpOptions</span><span class="p">(</span>
371+
<span class="n">client_args</span><span class="o">=...</span><span class="p">,</span>
372+
<span class="n">async_client_args</span><span class="o">=..</span><span class="p">,</span><span class="o">.</span>
373+
<span class="p">)</span>
374+
375+
<span class="n">client</span><span class="o">=</span><span class="n">Client</span><span class="p">(</span><span class="o">...</span><span class="p">,</span> <span class="n">http_options</span><span class="o">=</span><span class="n">http_options</span><span class="p">)</span>
376+
</pre></div>
377+
</div>
378+
</section>
356379
</section>
357380
<section id="types">
358381
<h2>Types<a class="headerlink" href="#types" title="Link to this heading">¶</a></h2>
@@ -5335,6 +5358,7 @@ <h1>Reference<a class="headerlink" href="#reference" title="Link to this heading
53355358
<li><a class="reference internal" href="#imports">Imports</a></li>
53365359
<li><a class="reference internal" href="#create-a-client">Create a client</a><ul>
53375360
<li><a class="reference internal" href="#api-selection">API Selection</a></li>
5361+
<li><a class="reference internal" href="#proxy">Proxy</a></li>
53385362
</ul>
53395363
</li>
53405364
<li><a class="reference internal" href="#types">Types</a></li>

docs/searchindex.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

google/genai/_api_client.py

Lines changed: 52 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
from dataclasses import dataclass
2626
import datetime
2727
import http
28+
import inspect
2829
import io
2930
import json
3031
import logging
@@ -34,7 +35,7 @@
3435
import sys
3536
import threading
3637
import time
37-
from typing import Any, AsyncIterator, Optional, Tuple, TYPE_CHECKING, Union
38+
from typing import Any, AsyncIterator, Optional, TYPE_CHECKING, Tuple, Union
3839
from urllib.parse import urlparse
3940
from urllib.parse import urlunparse
4041

@@ -509,6 +510,11 @@ def __init__(
509510
)
510511
self._httpx_client = SyncHttpxClient(**client_args)
511512
self._async_httpx_client = AsyncHttpxClient(**async_client_args)
513+
if has_aiohttp:
514+
# Do it once at the genai.Client level. Share among all requests.
515+
self._async_client_session_request_args = self._ensure_aiohttp_ssl_ctx(
516+
self._http_options
517+
)
512518

513519
@staticmethod
514520
def _ensure_httpx_ssl_ctx(
@@ -561,7 +567,12 @@ def _maybe_set(
561567
if not args or not args.get(verify):
562568
args = (args or {}).copy()
563569
args[verify] = ctx
564-
return args
570+
# Drop the args that isn't used by the httpx client.
571+
copied_args = args.copy()
572+
for key in copied_args.copy():
573+
if key not in inspect.signature(httpx.Client.__init__).parameters:
574+
del copied_args[key]
575+
return copied_args
565576

566577
return (
567578
_maybe_set(args, ctx),
@@ -581,7 +592,7 @@ def _ensure_aiohttp_ssl_ctx(options: HttpOptions) -> dict[str, Any]:
581592
An async aiohttp ClientSession._request args.
582593
"""
583594

584-
verify = 'verify'
595+
verify = 'ssl' # keep it consistent with httpx.
585596
async_args = options.async_client_args
586597
ctx = async_args.get(verify) if async_args else None
587598

@@ -613,10 +624,16 @@ def _maybe_set(
613624
"""
614625
if not args or not args.get(verify):
615626
args = (args or {}).copy()
616-
args['ssl'] = ctx
617-
else:
618-
args['ssl'] = args.pop(verify)
619-
return args
627+
args[verify] = ctx
628+
# Drop the args that isn't in the aiohttp RequestOptions.
629+
copied_args = args.copy()
630+
for key in copied_args.copy():
631+
if (
632+
key
633+
not in inspect.signature(aiohttp.ClientSession._request).parameters
634+
):
635+
del copied_args[key]
636+
return copied_args
620637

621638
return _maybe_set(async_args, ctx)
622639

@@ -819,30 +836,16 @@ async def _async_request(
819836
if has_aiohttp:
820837
session = aiohttp.ClientSession(
821838
headers=http_request.headers,
839+
trust_env=True,
840+
)
841+
response = await session.request(
842+
method=http_request.method,
843+
url=http_request.url,
844+
headers=http_request.headers,
845+
data=data,
846+
timeout=aiohttp.ClientTimeout(connect=http_request.timeout),
847+
**self._async_client_session_request_args,
822848
)
823-
if self._http_options.async_client_args:
824-
# When using aiohttp request options with ssl context, the latency will higher than using httpx.
825-
# Use it only if necessary. Otherwise, httpx asyncclient is faster.
826-
async_client_args = self._ensure_aiohttp_ssl_ctx(
827-
self._http_options
828-
)
829-
response = await session.request(
830-
method=http_request.method,
831-
url=http_request.url,
832-
headers=http_request.headers,
833-
data=data,
834-
timeout=aiohttp.ClientTimeout(connect=http_request.timeout),
835-
**async_client_args,
836-
)
837-
else:
838-
# Aiohttp performs better than httpx w/o ssl context.
839-
response = await session.request(
840-
method=http_request.method,
841-
url=http_request.url,
842-
headers=http_request.headers,
843-
data=data,
844-
timeout=aiohttp.ClientTimeout(connect=http_request.timeout),
845-
)
846849
await errors.APIError.raise_for_async_response(response)
847850
return HttpResponse(response.headers, response)
848851
else:
@@ -862,39 +865,20 @@ async def _async_request(
862865
return HttpResponse(client_response.headers, client_response)
863866
else:
864867
if has_aiohttp:
865-
if self._http_options.async_client_args:
866-
# Note that when using aiohttp request options with ssl context, the
867-
# latency will higher than using httpx async client with ssl context.
868-
async_client_args = self._ensure_aiohttp_ssl_ctx(
869-
self._http_options
868+
async with aiohttp.ClientSession(
869+
headers=http_request.headers,
870+
trust_env=True,
871+
) as session:
872+
response = await session.request(
873+
method=http_request.method,
874+
url=http_request.url,
875+
headers=http_request.headers,
876+
data=data,
877+
timeout=aiohttp.ClientTimeout(connect=http_request.timeout),
878+
**self._async_client_session_request_args,
870879
)
871-
async with aiohttp.ClientSession(
872-
headers=http_request.headers
873-
) as session:
874-
response = await session.request(
875-
method=http_request.method,
876-
url=http_request.url,
877-
headers=http_request.headers,
878-
data=data,
879-
timeout=aiohttp.ClientTimeout(connect=http_request.timeout),
880-
**async_client_args,
881-
)
882-
await errors.APIError.raise_for_async_response(response)
883-
return HttpResponse(response.headers, [await response.text()])
884-
else:
885-
# Aiohttp performs better than httpx if not using ssl context.
886-
async with aiohttp.ClientSession(
887-
headers=http_request.headers
888-
) as session:
889-
response = await session.request(
890-
method=http_request.method,
891-
url=http_request.url,
892-
headers=http_request.headers,
893-
data=data,
894-
timeout=aiohttp.ClientTimeout(connect=http_request.timeout),
895-
)
896-
await errors.APIError.raise_for_async_response(response)
897-
return HttpResponse(response.headers, [await response.text()])
880+
await errors.APIError.raise_for_async_response(response)
881+
return HttpResponse(response.headers, [await response.text()])
898882
else:
899883
# aiohttp is not available. Fall back to httpx.
900884
client_response = await self._async_httpx_client.request(
@@ -1192,7 +1176,8 @@ async def _async_upload_fd(
11921176
# Upload the file in chunks
11931177
if has_aiohttp: # pylint: disable=g-import-not-at-top
11941178
async with aiohttp.ClientSession(
1195-
headers=self._http_options.headers
1179+
headers=self._http_options.headers,
1180+
trust_env=True,
11961181
) as session:
11971182
while True:
11981183
if isinstance(file, io.IOBase):
@@ -1367,7 +1352,10 @@ async def async_download_file(
13671352
data = http_request.data
13681353

13691354
if has_aiohttp:
1370-
async with aiohttp.ClientSession(headers=http_request.headers) as session:
1355+
async with aiohttp.ClientSession(
1356+
headers=http_request.headers,
1357+
trust_env=True,
1358+
) as session:
13711359
response = await session.request(
13721360
method=http_request.method,
13731361
url=http_request.url,

google/genai/_live_converters.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -517,9 +517,23 @@ def _FunctionDeclaration_to_mldev(
517517
if getv(from_object, ['parameters']) is not None:
518518
setv(to_object, ['parameters'], getv(from_object, ['parameters']))
519519

520+
if getv(from_object, ['parameters_json_schema']) is not None:
521+
setv(
522+
to_object,
523+
['parametersJsonSchema'],
524+
getv(from_object, ['parameters_json_schema']),
525+
)
526+
520527
if getv(from_object, ['response']) is not None:
521528
setv(to_object, ['response'], getv(from_object, ['response']))
522529

530+
if getv(from_object, ['response_json_schema']) is not None:
531+
setv(
532+
to_object,
533+
['responseJsonSchema'],
534+
getv(from_object, ['response_json_schema']),
535+
)
536+
523537
return to_object
524538

525539

@@ -541,9 +555,23 @@ def _FunctionDeclaration_to_vertex(
541555
if getv(from_object, ['parameters']) is not None:
542556
setv(to_object, ['parameters'], getv(from_object, ['parameters']))
543557

558+
if getv(from_object, ['parameters_json_schema']) is not None:
559+
setv(
560+
to_object,
561+
['parametersJsonSchema'],
562+
getv(from_object, ['parameters_json_schema']),
563+
)
564+
544565
if getv(from_object, ['response']) is not None:
545566
setv(to_object, ['response'], getv(from_object, ['response']))
546567

568+
if getv(from_object, ['response_json_schema']) is not None:
569+
setv(
570+
to_object,
571+
['responseJsonSchema'],
572+
getv(from_object, ['response_json_schema']),
573+
)
574+
547575
return to_object
548576

549577

google/genai/_tokens_converters.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -517,9 +517,23 @@ def _FunctionDeclaration_to_mldev(
517517
if getv(from_object, ['parameters']) is not None:
518518
setv(to_object, ['parameters'], getv(from_object, ['parameters']))
519519

520+
if getv(from_object, ['parameters_json_schema']) is not None:
521+
setv(
522+
to_object,
523+
['parametersJsonSchema'],
524+
getv(from_object, ['parameters_json_schema']),
525+
)
526+
520527
if getv(from_object, ['response']) is not None:
521528
setv(to_object, ['response'], getv(from_object, ['response']))
522529

530+
if getv(from_object, ['response_json_schema']) is not None:
531+
setv(
532+
to_object,
533+
['responseJsonSchema'],
534+
getv(from_object, ['response_json_schema']),
535+
)
536+
523537
return to_object
524538

525539

@@ -541,9 +555,23 @@ def _FunctionDeclaration_to_vertex(
541555
if getv(from_object, ['parameters']) is not None:
542556
setv(to_object, ['parameters'], getv(from_object, ['parameters']))
543557

558+
if getv(from_object, ['parameters_json_schema']) is not None:
559+
setv(
560+
to_object,
561+
['parametersJsonSchema'],
562+
getv(from_object, ['parameters_json_schema']),
563+
)
564+
544565
if getv(from_object, ['response']) is not None:
545566
setv(to_object, ['response'], getv(from_object, ['response']))
546567

568+
if getv(from_object, ['response_json_schema']) is not None:
569+
setv(
570+
to_object,
571+
['responseJsonSchema'],
572+
getv(from_object, ['response_json_schema']),
573+
)
574+
547575
return to_object
548576

549577

0 commit comments

Comments
 (0)