Skip to content

Commit da056ef

Browse files
committed
Ruff formatter rerun
1 parent 6a33784 commit da056ef

16 files changed

Lines changed: 259 additions & 77 deletions

File tree

examples/ws_list.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
from tfe import TFEClient, TFEConfig
22

3+
34
def main():
45
client = TFEClient(TFEConfig.from_env())
56
org = "prab-sandbox01"
67
for ws in client.workspaces.list(org):
78
print("WS:", ws.name, ws.id)
89

10+
911
if __name__ == "__main__":
1012
main()

src/tfe/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@
22
from .client import TFEClient
33

44
from . import errors
5+
56
__all__ = ["TFEConfig", "TFEClient", "errors"]

src/tfe/_http.py

Lines changed: 113 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,25 @@
66

77
_RETRY_STATUSES = {429, 502, 503, 504}
88

9+
910
class HTTPTransport:
10-
def __init__(self, address: str, token: str, *, timeout: float, verify_tls: bool,
11-
user_agent_suffix: str | None, max_retries: int, backoff_base: float,
12-
backoff_cap: float, backoff_jitter: bool, http2: bool, proxies: dict | None,
13-
ca_bundle: str | None):
14-
self.base = address.rstrip('/')
11+
def __init__(
12+
self,
13+
address: str,
14+
token: str,
15+
*,
16+
timeout: float,
17+
verify_tls: bool,
18+
user_agent_suffix: str | None,
19+
max_retries: int,
20+
backoff_base: float,
21+
backoff_cap: float,
22+
backoff_jitter: bool,
23+
http2: bool,
24+
proxies: dict | None,
25+
ca_bundle: str | None,
26+
):
27+
self.base = address.rstrip("/")
1528
self.headers = build_headers(user_agent_suffix)
1629
if token:
1730
self.headers["Authorization"] = f"Bearer {token}"
@@ -24,70 +37,131 @@ def __init__(self, address: str, token: str, *, timeout: float, verify_tls: bool
2437
self.http2 = http2
2538
self.proxies = proxies
2639
self.ca_bundle = ca_bundle
27-
self._sync = httpx.Client(http2=http2, timeout=timeout, verify=ca_bundle or verify_tls) #proxies=proxies
28-
self._async = httpx.AsyncClient(http2=http2, timeout=timeout, verify=ca_bundle or verify_tls) #proxies=proxies
40+
self._sync = httpx.Client(
41+
http2=http2, timeout=timeout, verify=ca_bundle or verify_tls
42+
) # proxies=proxies
43+
self._async = httpx.AsyncClient(
44+
http2=http2, timeout=timeout, verify=ca_bundle or verify_tls
45+
) # proxies=proxies
2946

30-
def request(self, method: str, path: str, *, params: Mapping[str, Any] | None = None,
31-
json_body: Mapping[str, Any] | None = None, headers: dict[str, str] | None = None,
32-
allow_redirects: bool = True) -> httpx.Response:
47+
def request(
48+
self,
49+
method: str,
50+
path: str,
51+
*,
52+
params: Mapping[str, Any] | None = None,
53+
json_body: Mapping[str, Any] | None = None,
54+
headers: dict[str, str] | None = None,
55+
allow_redirects: bool = True,
56+
) -> httpx.Response:
3357
url = f"{self.base}{path}"
3458
hdrs = dict(self.headers)
3559
if headers:
3660
hdrs.update(headers)
3761
attempt = 0
3862
while True:
3963
try:
40-
resp = self._sync.request(method, url, params=params, json=json_body, headers=hdrs, follow_redirects=allow_redirects)
64+
resp = self._sync.request(
65+
method,
66+
url,
67+
params=params,
68+
json=json_body,
69+
headers=hdrs,
70+
follow_redirects=allow_redirects,
71+
)
4172
except httpx.HTTPError as e:
42-
if attempt >= self.max_retries: raise ServerError(str(e))
43-
self._sleep(attempt, None); attempt += 1; continue
73+
if attempt >= self.max_retries:
74+
raise ServerError(str(e))
75+
self._sleep(attempt, None)
76+
attempt += 1
77+
continue
4478
if resp.status_code in _RETRY_STATUSES and attempt < self.max_retries:
4579
retry_after = _parse_retry_after(resp)
46-
self._sleep(attempt, retry_after); attempt += 1; continue
47-
self._raise_if_error(resp); return resp
80+
self._sleep(attempt, retry_after)
81+
attempt += 1
82+
continue
83+
self._raise_if_error(resp)
84+
return resp
4885

49-
async def arequest(self, method: str, path: str, *, params: Mapping[str, Any] | None = None,
50-
json_body: Mapping[str, Any] | None = None, headers: dict[str, str] | None = None,
51-
allow_redirects: bool = True) -> httpx.Response:
52-
url = f"{self.base}{path}"; hdrs = dict(self.headers); hdrs.update(headers or {})
86+
async def arequest(
87+
self,
88+
method: str,
89+
path: str,
90+
*,
91+
params: Mapping[str, Any] | None = None,
92+
json_body: Mapping[str, Any] | None = None,
93+
headers: dict[str, str] | None = None,
94+
allow_redirects: bool = True,
95+
) -> httpx.Response:
96+
url = f"{self.base}{path}"
97+
hdrs = dict(self.headers)
98+
hdrs.update(headers or {})
5399
attempt = 0
54100
while True:
55101
try:
56-
resp = await self._async.request(method, url, params=params, json=json_body, headers=hdrs, follow_redirects=allow_redirects)
102+
resp = await self._async.request(
103+
method,
104+
url,
105+
params=params,
106+
json=json_body,
107+
headers=hdrs,
108+
follow_redirects=allow_redirects,
109+
)
57110
except httpx.HTTPError as e:
58-
if attempt >= self.max_retries: raise ServerError(str(e))
59-
await self._asleep(attempt, None); attempt += 1; continue
111+
if attempt >= self.max_retries:
112+
raise ServerError(str(e))
113+
await self._asleep(attempt, None)
114+
attempt += 1
115+
continue
60116
if resp.status_code in _RETRY_STATUSES and attempt < self.max_retries:
61117
retry_after = _parse_retry_after(resp)
62-
await self._asleep(attempt, retry_after); attempt += 1; continue
63-
self._raise_if_error(resp); return resp
118+
await self._asleep(attempt, retry_after)
119+
attempt += 1
120+
continue
121+
self._raise_if_error(resp)
122+
return resp
64123

65124
def _sleep(self, attempt: int, retry_after: float | None):
66-
if retry_after is not None: time.sleep(retry_after); return
67-
delay = min(self.backoff_cap, self.backoff_base * (2 ** attempt))
125+
if retry_after is not None:
126+
time.sleep(retry_after)
127+
return
128+
delay = min(self.backoff_cap, self.backoff_base * (2**attempt))
68129
time.sleep(delay)
69130

70131
async def _asleep(self, attempt: int, retry_after: float | None):
71-
if retry_after is not None: await anyio.sleep(retry_after); return
72-
delay = min(self.backoff_cap, self.backoff_base * (2 ** attempt))
132+
if retry_after is not None:
133+
await anyio.sleep(retry_after)
134+
return
135+
delay = min(self.backoff_cap, self.backoff_base * (2**attempt))
73136
await anyio.sleep(delay)
74137

75138
def _raise_if_error(self, resp: httpx.Response):
76-
if 200 <= resp.status_code < 300: return
77-
try: payload = resp.json()
78-
except Exception: payload = {}
139+
if 200 <= resp.status_code < 300:
140+
return
141+
try:
142+
payload = resp.json()
143+
except Exception:
144+
payload = {}
79145
errors = parse_error_payload(payload)
80-
msg = (errors[0].get("detail") if errors else f"HTTP {resp.status_code}")
146+
msg = errors[0].get("detail") if errors else f"HTTP {resp.status_code}"
81147
status = resp.status_code
82-
if status in (401,403): raise AuthError(msg, status=status, errors=errors)
83-
if status == 404: raise NotFound(msg, status=status, errors=errors)
148+
if status in (401, 403):
149+
raise AuthError(msg, status=status, errors=errors)
150+
if status == 404:
151+
raise NotFound(msg, status=status, errors=errors)
84152
if status == 429:
85-
ra = _parse_retry_after(resp); raise RateLimited(msg, status=status, errors=errors, retry_after=ra)
86-
if status >= 500: raise ServerError(msg, status=status, errors=errors)
153+
ra = _parse_retry_after(resp)
154+
raise RateLimited(msg, status=status, errors=errors, retry_after=ra)
155+
if status >= 500:
156+
raise ServerError(msg, status=status, errors=errors)
87157
raise TFEError(msg, status=status, errors=errors)
88158

159+
89160
def _parse_retry_after(resp: httpx.Response) -> float | None:
90161
ra = resp.headers.get("Retry-After")
91-
if not ra: return None
92-
try: return float(ra)
93-
except Exception: return None
162+
if not ra:
163+
return None
164+
try:
165+
return float(ra)
166+
except Exception:
167+
return None

src/tfe/_jsonapi.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from __future__ import annotations
22
from typing import Any
33

4+
45
def build_headers(user_agent_suffix: str | None = None) -> dict[str, str]:
56
ua = "python-tfe/0.1"
67
if user_agent_suffix:
@@ -11,10 +12,11 @@ def build_headers(user_agent_suffix: str | None = None) -> dict[str, str]:
1112
"User-Agent": ua,
1213
}
1314

15+
1416
def parse_error_payload(payload: dict[str, Any]) -> list[dict]:
1517
errs = payload.get("errors")
1618
if isinstance(errs, list):
1719
return errs
1820
if "message" in payload:
19-
return [ {"detail": payload.get("message")} ]
21+
return [{"detail": payload.get("message")}]
2022
return []

src/tfe/aclient.py

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,27 @@
1-
'''
2-
Async TFE Client: This client should not be used for now.
3-
'''
1+
"""
2+
Async TFE Client: This client should not be used for now.
3+
"""
44

55
from __future__ import annotations
66
from .config import TFEConfig
77
from ._http import HTTPTransport
88
from .resources.admin.settings import AdminSettingsAsync
99

10+
1011
class AsyncTFEClient:
1112
def __init__(self, config: TFEConfig | None = None):
1213
cfg = config or TFEConfig.from_env()
1314
self._transport = HTTPTransport(
14-
cfg.address, cfg.token, timeout=cfg.timeout, verify_tls=cfg.verify_tls,
15-
user_agent_suffix=cfg.user_agent_suffix, max_retries=cfg.max_retries,
16-
backoff_base=cfg.backoff_base, backoff_cap=cfg.backoff_cap, backoff_jitter=cfg.backoff_jitter,
17-
http2=cfg.http2, proxies=cfg.proxies, ca_bundle=cfg.ca_bundle
15+
cfg.address,
16+
cfg.token,
17+
timeout=cfg.timeout,
18+
verify_tls=cfg.verify_tls,
19+
user_agent_suffix=cfg.user_agent_suffix,
20+
max_retries=cfg.max_retries,
21+
backoff_base=cfg.backoff_base,
22+
backoff_cap=cfg.backoff_cap,
23+
backoff_jitter=cfg.backoff_jitter,
24+
http2=cfg.http2,
25+
proxies=cfg.proxies,
26+
ca_bundle=cfg.ca_bundle,
1827
)

src/tfe/client.py

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,27 @@
66
from .resources.workspaces import Workspaces
77
from .resources.admin.settings import AdminSettings
88

9+
910
class TFEClient:
1011
def __init__(self, config: TFEConfig | None = None):
1112
cfg = config or TFEConfig.from_env()
1213
self._transport = HTTPTransport(
13-
cfg.address, cfg.token, timeout=cfg.timeout, verify_tls=cfg.verify_tls,
14-
user_agent_suffix=cfg.user_agent_suffix, max_retries=cfg.max_retries,
15-
backoff_base=cfg.backoff_base, backoff_cap=cfg.backoff_cap, backoff_jitter=cfg.backoff_jitter,
16-
http2=cfg.http2, proxies=cfg.proxies, ca_bundle=cfg.ca_bundle
14+
cfg.address,
15+
cfg.token,
16+
timeout=cfg.timeout,
17+
verify_tls=cfg.verify_tls,
18+
user_agent_suffix=cfg.user_agent_suffix,
19+
max_retries=cfg.max_retries,
20+
backoff_base=cfg.backoff_base,
21+
backoff_cap=cfg.backoff_cap,
22+
backoff_jitter=cfg.backoff_jitter,
23+
http2=cfg.http2,
24+
proxies=cfg.proxies,
25+
ca_bundle=cfg.ca_bundle,
1726
)
1827
self.organizations = Organizations(self._transport)
1928
self.projects = Projects(self._transport)
2029
self.workspaces = Workspaces(self._transport)
2130

22-
def close(self): pass
31+
def close(self):
32+
pass

src/tfe/config.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,18 @@
22
from pydantic import BaseModel, Field
33
import os
44

5+
56
class TFEConfig(BaseModel):
6-
address: str = Field(default_factory=lambda: os.getenv("TFE_ADDRESS", "https://app.terraform.io"))
7+
address: str = Field(
8+
default_factory=lambda: os.getenv("TFE_ADDRESS", "https://app.terraform.io")
9+
)
710
token: str = Field(default_factory=lambda: os.getenv("TFE_TOKEN", ""))
811
timeout: float = float(os.getenv("TFE_TIMEOUT", "30"))
9-
verify_tls: bool = os.getenv("TFE_VERIFY_TLS", "true").lower() not in ("0","false","no")
12+
verify_tls: bool = os.getenv("TFE_VERIFY_TLS", "true").lower() not in (
13+
"0",
14+
"false",
15+
"no",
16+
)
1017
user_agent_suffix: str | None = None
1118
max_retries: int = int(os.getenv("TFE_MAX_RETRIES", "5"))
1219
backoff_base: float = 0.5

src/tfe/errors.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from typing import Optional, List, Dict
22

3+
34
class TFEError(Exception):
45
def __init__(
56
self,
@@ -12,13 +13,26 @@ def __init__(
1213
self.status = status
1314
self.errors = errors or []
1415

16+
1517
class AuthError(TFEError): ...
18+
19+
1620
class NotFound(TFEError): ...
21+
22+
1723
class RateLimited(TFEError):
1824
def __init__(self, message: str, *, retry_after: Optional[float] = None, **kw):
1925
super().__init__(message, **kw)
2026
self.retry_after = retry_after
27+
28+
2129
class ValidationError(TFEError): ...
30+
31+
2232
class ServerError(TFEError): ...
33+
34+
2335
class UnsupportedInCloud(TFEError): ...
36+
37+
2438
class UnsupportedInEnterprise(TFEError): ...

src/tfe/resources/_base.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22
from typing import Iterator, AsyncIterator
33
from .._http import HTTPTransport
44

5+
56
class _Service:
67
def __init__(self, t: HTTPTransport):
78
self.t = t
9+
810
def _list(self, path: str, *, params: dict | None = None):
911
page = 1
1012
while True:
@@ -19,12 +21,16 @@ def _list(self, path: str, *, params: dict | None = None):
1921
break
2022
page += 1
2123

22-
'''
24+
25+
"""
2326
Warning: Do Not Use this Async Service as its not stable with HashiCorp API.
24-
'''
27+
"""
28+
29+
2530
class _AService:
2631
def __init__(self, t: HTTPTransport):
2732
self.t = t
33+
2834
async def _alist(self, path: str, *, params: dict | None = None):
2935
page = 1
3036
while True:

0 commit comments

Comments
 (0)