Skip to content

Commit e6809f3

Browse files
tdsteinschloerke
andauthored
refactor: replace ctx.params, ctx.session, and ctx.url with ctx.client (#361)
Now that Client exists on the Context, we can remove all usage of `ctx.params`, `ctx.session`, and `ctx.url` with calls to `ctx.client`. --------- Co-authored-by: Barret Schloerke <[email protected]>
1 parent 4f6096b commit e6809f3

30 files changed

+238
-339
lines changed

src/posit/connect/_api_call.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,13 @@ def _patch_api(self, *path, json: Jsonifiable | None) -> Jsonifiable: ...
1919
def _put_api(self, *path, json: Jsonifiable | None) -> Jsonifiable: ...
2020

2121

22-
def endpoint(ctx: Context, *path) -> str:
23-
return ctx.url + posixpath.join(*path)
22+
def endpoint(*path) -> str:
23+
return posixpath.join(*path)
2424

2525

2626
# Helper methods for API interactions
2727
def get_api(ctx: Context, *path) -> Jsonifiable:
28-
response = ctx.session.get(endpoint(ctx, *path))
28+
response = ctx.client.get(*path)
2929
return response.json()
3030

3131

@@ -34,7 +34,7 @@ def put_api(
3434
*path,
3535
json: Jsonifiable | None,
3636
) -> Jsonifiable:
37-
response = ctx.session.put(endpoint(ctx, *path), json=json)
37+
response = ctx.client.put(*path, json=json)
3838
return response.json()
3939

4040

@@ -43,14 +43,14 @@ def put_api(
4343

4444
class ApiCallMixin:
4545
def _endpoint(self: ApiCallProtocol, *path) -> str:
46-
return endpoint(self._ctx, self._path, *path)
46+
return endpoint(self._path, *path)
4747

4848
def _get_api(self: ApiCallProtocol, *path) -> Jsonifiable:
49-
response = self._ctx.session.get(self._endpoint(*path))
49+
response = self._ctx.client.get(self._endpoint(*path))
5050
return response.json()
5151

5252
def _delete_api(self: ApiCallProtocol, *path) -> Jsonifiable | None:
53-
response = self._ctx.session.delete(self._endpoint(*path))
53+
response = self._ctx.client.delete(self._endpoint(*path))
5454
if len(response.content) == 0:
5555
return None
5656
return response.json()
@@ -60,13 +60,13 @@ def _patch_api(
6060
*path,
6161
json: Jsonifiable | None,
6262
) -> Jsonifiable:
63-
response = self._ctx.session.patch(self._endpoint(*path), json=json)
63+
response = self._ctx.client.patch(self._endpoint(*path), json=json)
6464
return response.json()
6565

6666
def _put_api(
6767
self: ApiCallProtocol,
6868
*path,
6969
json: Jsonifiable | None,
7070
) -> Jsonifiable:
71-
response = self._ctx.session.put(self._endpoint(*path), json=json)
71+
response = self._ctx.client.put(self._endpoint(*path), json=json)
7272
return response.json()

src/posit/connect/bundles.py

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,13 @@
33
from __future__ import annotations
44

55
import io
6-
from typing import List
6+
from typing import TYPE_CHECKING, List
77

88
from . import resources, tasks
99

10+
if TYPE_CHECKING:
11+
from .context import Context
12+
1013

1114
class BundleMetadata(resources.Resource):
1215
pass
@@ -15,13 +18,12 @@ class BundleMetadata(resources.Resource):
1518
class Bundle(resources.Resource):
1619
@property
1720
def metadata(self) -> BundleMetadata:
18-
return BundleMetadata(self.params, **self.get("metadata", {}))
21+
return BundleMetadata(self._ctx, **self.get("metadata", {}))
1922

2023
def delete(self) -> None:
2124
"""Delete the bundle."""
2225
path = f"v1/content/{self['content_guid']}/bundles/{self['id']}"
23-
url = self.params.url + path
24-
self.params.session.delete(url)
26+
self._ctx.client.delete(path)
2527

2628
def deploy(self) -> tasks.Task:
2729
"""Deploy the bundle.
@@ -40,10 +42,9 @@ def deploy(self) -> tasks.Task:
4042
None
4143
"""
4244
path = f"v1/content/{self['content_guid']}/deploy"
43-
url = self.params.url + path
44-
response = self.params.session.post(url, json={"bundle_id": self["id"]})
45+
response = self._ctx.client.post(path, json={"bundle_id": self["id"]})
4546
result = response.json()
46-
ts = tasks.Tasks(self.params)
47+
ts = tasks.Tasks(self._ctx)
4748
return ts.get(result["task_id"])
4849

4950
def download(self, output: io.BufferedWriter | str) -> None:
@@ -78,8 +79,7 @@ def download(self, output: io.BufferedWriter | str) -> None:
7879
)
7980

8081
path = f"v1/content/{self['content_guid']}/bundles/{self['id']}/download"
81-
url = self.params.url + path
82-
response = self.params.session.get(url, stream=True)
82+
response = self._ctx.client.get(path, stream=True)
8383
if isinstance(output, io.BufferedWriter):
8484
for chunk in response.iter_content():
8585
output.write(chunk)
@@ -109,10 +109,10 @@ class Bundles(resources.Resources):
109109

110110
def __init__(
111111
self,
112-
params: resources.ResourceParameters,
112+
ctx: Context,
113113
content_guid: str,
114114
) -> None:
115-
super().__init__(params)
115+
super().__init__(ctx)
116116
self.content_guid = content_guid
117117

118118
def create(self, archive: io.BufferedReader | bytes | str) -> Bundle:
@@ -164,10 +164,9 @@ def create(self, archive: io.BufferedReader | bytes | str) -> Bundle:
164164
)
165165

166166
path = f"v1/content/{self.content_guid}/bundles"
167-
url = self.params.url + path
168-
response = self.params.session.post(url, data=data)
167+
response = self._ctx.client.post(path, data=data)
169168
result = response.json()
170-
return Bundle(self.params, **result)
169+
return Bundle(self._ctx, **result)
171170

172171
def find(self) -> List[Bundle]:
173172
"""Find all bundles.
@@ -178,10 +177,9 @@ def find(self) -> List[Bundle]:
178177
List of all found bundles.
179178
"""
180179
path = f"v1/content/{self.content_guid}/bundles"
181-
url = self.params.url + path
182-
response = self.params.session.get(url)
180+
response = self._ctx.client.get(path)
183181
results = response.json()
184-
return [Bundle(self.params, **result) for result in results]
182+
return [Bundle(self._ctx, **result) for result in results]
185183

186184
def find_one(self) -> Bundle | None:
187185
"""Find a bundle.
@@ -208,7 +206,6 @@ def get(self, uid: str) -> Bundle:
208206
The bundle with the specified ID.
209207
"""
210208
path = f"v1/content/{self.content_guid}/bundles/{uid}"
211-
url = self.params.url + path
212-
response = self.params.session.get(url)
209+
response = self._ctx.client.get(path)
213210
result = response.json()
214-
return Bundle(self.params, **result)
211+
return Bundle(self._ctx, **result)

src/posit/connect/client.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from .groups import Groups
1515
from .metrics import Metrics
1616
from .oauth import OAuth
17-
from .resources import ResourceParameters, _PaginatedResourceSequence, _ResourceSequence
17+
from .resources import _PaginatedResourceSequence, _ResourceSequence
1818
from .system import System
1919
from .tags import Tags
2020
from .tasks import Tasks
@@ -160,7 +160,6 @@ def __init__(self, *args, **kwargs) -> None:
160160
session.hooks["response"].append(hooks.check_for_deprecation_header)
161161
session.hooks["response"].append(hooks.handle_errors)
162162
self.session = session
163-
self.resource_params = ResourceParameters(session, self.cfg.url)
164163
self._ctx = Context(self)
165164

166165
@property
@@ -208,7 +207,7 @@ def tasks(self) -> Tasks:
208207
tasks.Tasks
209208
The tasks resource instance.
210209
"""
211-
return Tasks(self.resource_params)
210+
return Tasks(self._ctx)
212211

213212
@property
214213
def users(self) -> Users:
@@ -282,7 +281,7 @@ def metrics(self) -> Metrics:
282281
>>> len(events)
283282
24
284283
"""
285-
return Metrics(self.resource_params)
284+
return Metrics(self._ctx)
286285

287286
@property
288287
@requires(version="2024.08.0")
@@ -295,7 +294,7 @@ def oauth(self) -> OAuth:
295294
OAuth
296295
The oauth API instance.
297296
"""
298-
return OAuth(self.resource_params, self.cfg.api_key)
297+
return OAuth(self._ctx, self.cfg.api_key)
299298

300299
@property
301300
@requires(version="2024.11.0")
@@ -304,7 +303,7 @@ def packages(self) -> Packages:
304303

305304
@property
306305
def vanities(self) -> Vanities:
307-
return Vanities(self.resource_params)
306+
return Vanities(self._ctx)
308307

309308
@property
310309
def system(self) -> System:

src/posit/connect/content.py

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
import posixpath
66
import time
7-
from posixpath import dirname
87
from typing import (
98
TYPE_CHECKING,
109
Any,
@@ -25,7 +24,7 @@
2524
from .errors import ClientError
2625
from .oauth.associations import ContentItemAssociations
2726
from .permissions import Permissions
28-
from .resources import Active, Resource, ResourceParameters, Resources, _ResourceSequence
27+
from .resources import Active, Resource, Resources, _ResourceSequence
2928
from .tags import ContentItemTags
3029
from .vanities import VanityMixin
3130
from .variants import Variants
@@ -162,13 +161,13 @@ def update(
162161

163162

164163
class ContentItemOAuth(Resource):
165-
def __init__(self, params: ResourceParameters, content_guid: str) -> None:
166-
super().__init__(params)
164+
def __init__(self, ctx: Context, content_guid: str) -> None:
165+
super().__init__(ctx)
167166
self["content_guid"] = content_guid
168167

169168
@property
170169
def associations(self) -> ContentItemAssociations:
171-
return ContentItemAssociations(self.params, content_guid=self["content_guid"])
170+
return ContentItemAssociations(self._ctx, content_guid=self["content_guid"])
172171

173172

174173
class ContentItemOwner(Resource):
@@ -255,12 +254,12 @@ def __init__(
255254
def __getitem__(self, key: Any) -> Any:
256255
v = super().__getitem__(key)
257256
if key == "owner" and isinstance(v, dict):
258-
return ContentItemOwner(params=self.params, **v)
257+
return ContentItemOwner(self._ctx, **v)
259258
return v
260259

261260
@property
262261
def oauth(self) -> ContentItemOAuth:
263-
return ContentItemOAuth(self.params, content_guid=self["guid"])
262+
return ContentItemOAuth(self._ctx, content_guid=self["guid"])
264263

265264
@property
266265
def repository(self) -> ContentItemRepository | None:
@@ -316,7 +315,7 @@ def deploy(self) -> tasks.Task:
316315
path = f"v1/content/{self['guid']}/deploy"
317316
response = self._ctx.client.post(path, json={"bundle_id": None})
318317
result = response.json()
319-
ts = tasks.Tasks(self.params)
318+
ts = tasks.Tasks(self._ctx)
320319
return ts.get(result["task_id"])
321320

322321
def render(self) -> Task:
@@ -369,8 +368,8 @@ def restart(self) -> None:
369368
self.environment_variables.create(key, unix_epoch_in_seconds)
370369
self.environment_variables.delete(key)
371370
# GET via the base Connect URL to force create a new worker thread.
372-
url = posixpath.join(dirname(self._ctx.url), f"content/{self['guid']}")
373-
self._ctx.session.get(url)
371+
path = f"../content/{self['guid']}"
372+
self._ctx.client.get(path)
374373
return None
375374
else:
376375
raise ValueError(
@@ -447,15 +446,15 @@ def update(
447446

448447
@property
449448
def bundles(self) -> Bundles:
450-
return Bundles(self.params, self["guid"])
449+
return Bundles(self._ctx, self["guid"])
451450

452451
@property
453452
def environment_variables(self) -> EnvVars:
454-
return EnvVars(self.params, self["guid"])
453+
return EnvVars(self._ctx, self["guid"])
455454

456455
@property
457456
def permissions(self) -> Permissions:
458-
return Permissions(self.params, self["guid"])
457+
return Permissions(self._ctx, self["guid"])
459458

460459
@property
461460
def owner(self) -> dict:
@@ -472,7 +471,7 @@ def owner(self) -> dict:
472471

473472
@property
474473
def _variants(self) -> Variants:
475-
return Variants(self.params, self["guid"])
474+
return Variants(self._ctx, self["guid"])
476475

477476
@property
478477
def is_interactive(self) -> bool:
@@ -540,7 +539,7 @@ def __init__(
540539
*,
541540
owner_guid: str | None = None,
542541
) -> None:
543-
super().__init__(ctx.client.resource_params)
542+
super().__init__(ctx)
544543
self.owner_guid = owner_guid
545544
self._ctx = ctx
546545

src/posit/connect/context.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,7 @@
77
from packaging.version import Version
88

99
if TYPE_CHECKING:
10-
import requests
11-
1210
from .client import Client
13-
from .urls import Url
1411

1512

1613
def requires(version: str):
@@ -31,17 +28,14 @@ def wrapper(instance: ContextManager, *args, **kwargs):
3128

3229
class Context:
3330
def __init__(self, client: Client):
34-
self.session: requests.Session = client.session
35-
self.url: Url = client.cfg.url
3631
# Since this is a child object of the client, we use a weak reference to avoid circular
3732
# references (which would prevent garbage collection)
3833
self.client: Client = weakref.proxy(client)
3934

4035
@property
4136
def version(self) -> str | None:
4237
if not hasattr(self, "_version"):
43-
endpoint = self.url + "server_settings"
44-
response = self.session.get(endpoint)
38+
response = self.client.get("server_settings")
4539
result = response.json()
4640
self._version: str | None = result.get("version")
4741

src/posit/connect/cursors.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from typing import TYPE_CHECKING, Any, Generator, List
55

66
if TYPE_CHECKING:
7-
import requests
7+
from .context import Context
88

99
# The maximum page size supported by the API.
1010
_MAX_PAGE_SIZE = 500
@@ -19,15 +19,16 @@ class CursorPage:
1919
class CursorPaginator:
2020
def __init__(
2121
self,
22-
session: requests.Session,
23-
url: str,
22+
ctx: Context,
23+
path: str,
2424
params: dict[str, Any] | None = None,
2525
) -> None:
2626
if params is None:
2727
params = {}
28-
self.session = session
29-
self.url = url
30-
self.params = params
28+
29+
self._ctx = ctx
30+
self._path = path
31+
self._params = params
3132

3233
def fetch_results(self) -> List[dict]:
3334
"""Fetch results.
@@ -74,9 +75,9 @@ def fetch_page(self, next_page: str | None = None) -> CursorPage:
7475
Page
7576
"""
7677
params = {
77-
**self.params,
78+
**self._params,
7879
"next": next_page,
7980
"limit": _MAX_PAGE_SIZE,
8081
}
81-
response = self.session.get(self.url, params=params)
82+
response = self._ctx.client.get(self._path, params=params)
8283
return CursorPage(**response.json())

0 commit comments

Comments
 (0)