Skip to content

Commit 12c8d84

Browse files
committed
Add support for HTTP_PROXY/HTTPS_PROXY variables
1 parent efc6b2a commit 12c8d84

3 files changed

Lines changed: 87 additions & 1 deletion

File tree

packages/gooddata-sdk/src/gooddata_sdk/client.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ def __init__(
2626
extra_user_agent: str | None = None,
2727
executions_cancellable: bool = False,
2828
ssl_ca_cert: str | None = None,
29+
proxy: str | None = None,
2930
) -> None:
3031
"""Take url, token for connecting to GoodData.CN.
3132
@@ -38,6 +39,10 @@ def __init__(
3839
`executions_cancellable` is a flag that sets all executions computed through this client as cancellable.
3940
In case a request for a result is interrupted, the GD server will try to free resources like killing sql queries
4041
related to the given execution.
42+
43+
`proxy` is optional URL of an HTTP(S) proxy (e.g. ``http://proxy:8080``).
44+
When not set, the standard ``HTTPS_PROXY`` / ``https_proxy`` / ``HTTP_PROXY`` /
45+
``http_proxy`` environment variables are checked automatically.
4146
"""
4247
self._hostname = host
4348
self._token = token
@@ -53,7 +58,20 @@ def __init__(
5358
f"ssl_ca_cert file path specified but the file does not exist. Path: {ssl_ca_cert_path}."
5459
)
5560

61+
if proxy is None:
62+
import os
63+
64+
proxy = (
65+
os.environ.get("HTTPS_PROXY")
66+
or os.environ.get("https_proxy")
67+
or os.environ.get("HTTP_PROXY")
68+
or os.environ.get("http_proxy")
69+
or None
70+
)
71+
5672
self._api_config = api_client.Configuration(host=host, ssl_ca_cert=ssl_ca_cert)
73+
if proxy:
74+
self._api_config.proxy = proxy
5775
self._api_client = api_client.ApiClient(
5876
configuration=self._api_config,
5977
header_name="Authorization",

packages/gooddata-sdk/src/gooddata_sdk/sdk.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,18 @@ def create(
4949
*,
5050
ssl_ca_cert: str | None = None,
5151
executions_cancellable: bool = False,
52+
proxy: str | None = None,
5253
**custom_headers_: str | None,
5354
) -> GoodDataSdk:
5455
"""
5556
Create common GoodDataApiClient and return new GoodDataSdk instance.
5657
Custom headers are filtered. Headers with None value are removed. It simplifies usage because headers
5758
can be created directly from optional values.
5859
60+
``proxy`` is an optional HTTP(S) proxy URL (e.g. ``http://proxy:8080``).
61+
When not set, the standard ``HTTPS_PROXY`` / ``https_proxy`` / ``HTTP_PROXY``
62+
/ ``http_proxy`` environment variables are checked automatically.
63+
5964
This is preferred way of creating GoodDataSdk, when no tweaks are needed.
6065
"""
6166
filtered_headers = {key: value for key, value in custom_headers_.items() if value is not None}
@@ -66,6 +71,7 @@ def create(
6671
extra_user_agent=extra_user_agent_,
6772
executions_cancellable=executions_cancellable,
6873
ssl_ca_cert=ssl_ca_cert,
74+
proxy=proxy,
6975
)
7076
return cls(client)
7177

packages/gooddata-sdk/tests/test_client.py

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# (C) 2021 GoodData Corporation
2-
from gooddata_sdk import GoodDataApiClient
2+
import os
3+
from unittest import mock
4+
5+
from gooddata_sdk import GoodDataApiClient, GoodDataSdk
36

47

58
def test_http_headers_precedence():
@@ -12,3 +15,62 @@ def test_http_headers_precedence():
1215
agent = c._api_client.default_headers["User-Agent"]
1316
assert agent.startswith("gooddata")
1417
assert agent.endswith("yes")
18+
19+
20+
class TestProxy:
21+
"""Proxy configuration for the underlying urllib3 pool manager."""
22+
23+
@mock.patch.dict(os.environ, {}, clear=True)
24+
def test_no_proxy_when_env_empty(self):
25+
c = GoodDataApiClient("https://example.com", "token")
26+
assert c._api_config.proxy is None
27+
28+
def test_explicit_proxy(self):
29+
c = GoodDataApiClient("https://example.com", "token", proxy="http://myproxy:8080")
30+
assert c._api_config.proxy == "http://myproxy:8080"
31+
32+
@mock.patch.dict(os.environ, {"HTTPS_PROXY": "http://envproxy:3128"}, clear=True)
33+
def test_proxy_from_https_proxy_env(self):
34+
c = GoodDataApiClient("https://example.com", "token")
35+
assert c._api_config.proxy == "http://envproxy:3128"
36+
37+
@mock.patch.dict(os.environ, {"https_proxy": "http://lower:3128"}, clear=True)
38+
def test_proxy_from_lowercase_https_proxy_env(self):
39+
c = GoodDataApiClient("https://example.com", "token")
40+
assert c._api_config.proxy == "http://lower:3128"
41+
42+
@mock.patch.dict(os.environ, {"HTTP_PROXY": "http://httpproxy:3128"}, clear=True)
43+
def test_proxy_from_http_proxy_env(self):
44+
c = GoodDataApiClient("https://example.com", "token")
45+
assert c._api_config.proxy == "http://httpproxy:3128"
46+
47+
@mock.patch.dict(
48+
os.environ,
49+
{
50+
"HTTPS_PROXY": "http://preferred:3128",
51+
"HTTP_PROXY": "http://fallback:3128",
52+
},
53+
clear=True,
54+
)
55+
def test_https_proxy_takes_precedence_over_http_proxy(self):
56+
c = GoodDataApiClient("https://example.com", "token")
57+
assert c._api_config.proxy == "http://preferred:3128"
58+
59+
@mock.patch.dict(os.environ, {"HTTPS_PROXY": "http://envproxy:3128"}, clear=True)
60+
def test_explicit_proxy_overrides_env(self):
61+
c = GoodDataApiClient("https://example.com", "token", proxy="http://explicit:8080")
62+
assert c._api_config.proxy == "http://explicit:8080"
63+
64+
def test_sdk_create_with_explicit_proxy(self):
65+
sdk = GoodDataSdk.create("https://example.com", "token", proxy="http://myproxy:8080")
66+
assert sdk.client._api_config.proxy == "http://myproxy:8080"
67+
68+
@mock.patch.dict(os.environ, {"HTTPS_PROXY": "http://envproxy:3128"}, clear=True)
69+
def test_sdk_create_picks_up_env_proxy(self):
70+
sdk = GoodDataSdk.create("https://example.com", "token")
71+
assert sdk.client._api_config.proxy == "http://envproxy:3128"
72+
73+
@mock.patch.dict(os.environ, {}, clear=True)
74+
def test_sdk_create_no_proxy_when_env_empty(self):
75+
sdk = GoodDataSdk.create("https://example.com", "token")
76+
assert sdk.client._api_config.proxy is None

0 commit comments

Comments
 (0)