Skip to content

Commit 6687092

Browse files
committed
Refactor internals of openapi class
This will mask attributes of the class private and add a bit of abstraction from requests.
1 parent baffd78 commit 6687092

File tree

2 files changed

+64
-49
lines changed

2 files changed

+64
-49
lines changed

pulp-glue/pulp_glue/common/openapi.py

Lines changed: 63 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -30,20 +30,14 @@
3030
class OpenAPIError(Exception):
3131
"""Base Exception for errors related to using the openapi spec."""
3232

33-
pass
34-
3533

3634
class OpenAPIValidationError(OpenAPIError):
3735
"""Exception raised for failed client side validation of parameters or request bodies."""
3836

39-
pass
40-
4137

4238
class UnsafeCallError(OpenAPIError):
4339
"""Exception raised for POST, PUT, PATCH or DELETE calls with `safe_calls_only=True`."""
4440

45-
pass
46-
4741

4842
class AuthProviderBase:
4943
"""
@@ -174,53 +168,71 @@ def __init__(
174168
user_agent: t.Optional[str] = None,
175169
cid: t.Optional[str] = None,
176170
):
177-
if verify is False:
178-
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
179-
180-
self.debug_callback: t.Callable[[int, str], t.Any] = debug_callback or (lambda i, x: None)
181-
self.base_url: str = base_url
182-
self.doc_path: str = doc_path
183-
self.safe_calls_only: bool = safe_calls_only
184-
self.auth_provider = auth_provider
185-
186-
self._session: requests.Session = requests.session()
187-
if self.auth_provider:
188-
if cert or key:
189-
raise OpenAPIError(_("Cannot use both 'auth' and 'cert'."))
190-
else:
191-
if cert and key:
192-
self._session.cert = (cert, key)
193-
elif cert:
194-
self._session.cert = cert
195-
elif key:
196-
raise OpenAPIError(_("Cert is required if key is set."))
197-
self._session.headers.update(
171+
self._debug_callback: t.Callable[[int, str], t.Any] = debug_callback or (lambda i, x: None)
172+
self._base_url: str = base_url
173+
self._doc_path: str = doc_path
174+
self._safe_calls_only: bool = safe_calls_only
175+
self._headers = headers or {}
176+
self._verify = verify
177+
self._auth_provider = auth_provider
178+
self._cert = cert
179+
self._key = key
180+
181+
self._headers.update(
198182
{
199183
"User-Agent": user_agent or f"Pulp-glue openapi parser ({__version__})",
200184
"Accept": "application/json",
201185
}
202186
)
203187
if cid:
204-
self._session.headers["Correlation-Id"] = cid
205-
if headers:
206-
self._session.headers.update(headers)
207-
self._session.max_redirects = 0
188+
self._headers["Correlation-Id"] = cid
189+
190+
self._setup_session()
208191

192+
self.load_api(refresh_cache=refresh_cache)
193+
194+
def _setup_session(self) -> None:
195+
# This is specific requests library.
196+
197+
if self._verify is False:
198+
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
199+
200+
self._session: requests.Session = requests.session()
201+
# Don't redirect, because carrying auth accross redirects is unsafe.
202+
self._session.max_redirects = 0
203+
self._session.headers.update(self._headers)
204+
if self._auth_provider:
205+
if self._cert or self._key:
206+
raise OpenAPIError(_("Cannot use both 'auth' and 'cert'."))
207+
else:
208+
if self._cert and self._key:
209+
self._session.cert = (self._cert, self._key)
210+
elif self._cert:
211+
self._session.cert = self._cert
212+
elif self._key:
213+
raise OpenAPIError(_("Cert is required if key is set."))
209214
session_settings = self._session.merge_environment_settings(
210-
base_url, {}, None, verify, None
215+
self._base_url, {}, None, self._verify, None
211216
)
212217
self._session.verify = session_settings["verify"]
213218
self._session.proxies = session_settings["proxies"]
214219

215-
self.load_api(refresh_cache=refresh_cache)
220+
@property
221+
def base_url(self) -> str:
222+
return self._base_url
223+
224+
@property
225+
def cid(self) -> t.Optional[str]:
226+
return self._headers.get("Correlation-Id")
216227

217228
def load_api(self, refresh_cache: bool = False) -> None:
218229
# TODO: Find a way to invalidate caches on upstream change
219230
xdg_cache_home: str = os.environ.get("XDG_CACHE_HOME") or "~/.cache"
220231
apidoc_cache: str = os.path.join(
221232
os.path.expanduser(xdg_cache_home),
222233
"squeezer",
223-
(self.base_url + "_" + self.doc_path).replace(":", "_").replace("/", "_") + "api.json",
234+
(self._base_url + "_" + self._doc_path).replace(":", "_").replace("/", "_")
235+
+ "api.json",
224236
)
225237
try:
226238
if refresh_cache:
@@ -252,7 +264,7 @@ def _parse_api(self, data: bytes) -> None:
252264

253265
def _download_api(self) -> bytes:
254266
try:
255-
response: requests.Response = self._session.get(urljoin(self.base_url, self.doc_path))
267+
response: requests.Response = self._session.get(urljoin(self._base_url, self._doc_path))
256268
except requests.RequestException as e:
257269
raise OpenAPIError(str(e))
258270
response.raise_for_status()
@@ -261,14 +273,16 @@ def _download_api(self) -> bytes:
261273
return response.content
262274

263275
def _set_correlation_id(self, correlation_id: str) -> None:
264-
if "Correlation-ID" in self._session.headers:
265-
if self._session.headers["Correlation-ID"] != correlation_id:
276+
if "Correlation-ID" in self._headers:
277+
if self._headers["Correlation-ID"] != correlation_id:
266278
raise OpenAPIError(
267279
_("Correlation ID returned from server did not match. {} != {}").format(
268-
self._session.headers["Correlation-ID"], correlation_id
280+
self._headers["Correlation-ID"], correlation_id
269281
)
270282
)
271283
else:
284+
self._headers["Correlation-ID"] = correlation_id
285+
# Do it for requests too...
272286
self._session.headers["Correlation-ID"] = correlation_id
273287

274288
def param_spec(
@@ -420,7 +434,7 @@ def validate_schema(self, schema: t.Any, name: str, value: t.Any) -> t.Any:
420434
# TextField
421435
# DateTimeField etc.
422436
# ChoiceField
423-
# FielField (binary data)
437+
# FileField (binary data)
424438
value = self.validate_string(schema, name, value)
425439
elif schema_type == "integer":
426440
# IntegerField
@@ -654,12 +668,12 @@ def render_request(
654668
security: t.List[t.Dict[str, t.List[str]]] = method_spec.get(
655669
"security", self.api_spec.get("security", {})
656670
)
657-
if security and self.auth_provider:
671+
if security and self._auth_provider:
658672
if "Authorization" in self._session.headers:
659673
# Bad idea, but you wanted it that way.
660674
auth = None
661675
else:
662-
auth = self.auth_provider(security, self.api_spec["components"]["securitySchemes"])
676+
auth = self._auth_provider(security, self.api_spec["components"]["securitySchemes"])
663677
else:
664678
# No auth required? Don't provide it.
665679
# No auth_provider available? Hope for the best (should do the trick for cert auth).
@@ -751,7 +765,7 @@ def call(
751765
names=", ".join(parameters.keys()), operation_id=operation_id
752766
)
753767
)
754-
url = urljoin(self.base_url, path)
768+
url = urljoin(self._base_url, path)
755769

756770
request: requests.PreparedRequest = self.render_request(
757771
path_spec,
@@ -763,12 +777,12 @@ def call(
763777
validate_body=validate_body,
764778
)
765779

766-
self.debug_callback(1, f"{operation_id} : {method} {request.url}")
780+
self._debug_callback(1, f"{operation_id} : {method} {request.url}")
767781
for key, value in request.headers.items():
768-
self.debug_callback(2, f" {key}: {value}")
782+
self._debug_callback(2, f" {key}: {value}")
769783
if request.body is not None:
770-
self.debug_callback(3, f"{request.body!r}")
771-
if self.safe_calls_only and method.upper() not in SAFE_METHODS:
784+
self._debug_callback(3, f"{request.body!r}")
785+
if self._safe_calls_only and method.upper() not in SAFE_METHODS:
772786
raise UnsafeCallError(_("Call aborted due to safe mode"))
773787
try:
774788
response: requests.Response = self._session.send(request)
@@ -781,13 +795,13 @@ def call(
781795
)
782796
except requests.RequestException as e:
783797
raise OpenAPIError(str(e))
784-
self.debug_callback(
798+
self._debug_callback(
785799
1, _("Response: {status_code}").format(status_code=response.status_code)
786800
)
787801
for key, value in response.headers.items():
788-
self.debug_callback(2, f" {key}: {value}")
802+
self._debug_callback(2, f" {key}: {value}")
789803
if response.text:
790-
self.debug_callback(3, f"{response.text}")
804+
self._debug_callback(3, f"{response.text}")
791805
if "Correlation-ID" in response.headers:
792806
self._set_correlation_id(response.headers["Correlation-ID"])
793807
response.raise_for_status()

pulp-glue/pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ classifiers = [
2323
"Typing :: Typed",
2424
]
2525
dependencies = [
26+
"aiohttp>=3.10.10,<3.11",
2627
"packaging>=20.0,<25",
2728
"requests>=2.24.0,<2.33",
2829
"importlib_resources>=5.4.0,<6.2;python_version<'3.9'",

0 commit comments

Comments
 (0)