Skip to content

Commit 8dd6d0b

Browse files
committed
Overhaul ContentItem
1 parent 45660cf commit 8dd6d0b

File tree

2 files changed

+63
-39
lines changed

2 files changed

+63
-39
lines changed

src/posit/connect/content.py

Lines changed: 51 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -16,39 +16,44 @@
1616
)
1717

1818
from . import tasks
19-
from ._active import ActiveDict, JsonifiableDict
19+
from ._content_repository import ContentItemRepository
20+
from ._json import JsonifiableDict
21+
from ._types_content_item import ContentItemActiveDict, ContentItemContext, ContentItemResourceDict
2022
from ._typing_extensions import NotRequired, Required, TypedDict, Unpack
21-
from ._utils import _assert_content_guid, _assert_guid
23+
from ._utils import _assert_guid
2224
from .bundles import Bundles
2325
from .context import Context
2426
from .env import EnvVars
2527
from .errors import ClientError
2628
from .jobs import JobsMixin
2729
from .oauth.associations import ContentItemAssociations
2830
from .permissions import Permissions
29-
from .resources import Resource, ResourceParameters, Resources
30-
from .vanities import VanityMixin
31+
from .resources import ResourceParameters, Resources, context_to_resource_parameters
32+
from .vanities import ContentItemVanityMixin
3133
from .variants import Variants
3234

3335
if TYPE_CHECKING:
3436
from .tasks import Task
37+
from .users import User
3538

3639

37-
class ContentItemOAuth(Resource):
38-
def __init__(self, params: ResourceParameters, content_guid: str) -> None:
39-
super().__init__(params)
40-
self["content_guid"] = content_guid
40+
class ContentItemOAuth(ContentItemResourceDict):
41+
def __init__(self, ctx: ContentItemContext) -> None:
42+
super().__init__(ctx)
4143

4244
@property
4345
def associations(self) -> ContentItemAssociations:
44-
return ContentItemAssociations(self.params, content_guid=self["content_guid"])
46+
return ContentItemAssociations(
47+
context_to_resource_parameters(self._ctx),
48+
content_guid=self._ctx.content_guid,
49+
)
4550

4651

47-
class ContentItemOwner(Resource):
52+
class ContentItemOwner(ContentItemResourceDict):
4853
pass
4954

5055

51-
class ContentItem(JobsMixin, VanityMixin, Resource):
56+
class ContentItem(JobsMixin, ContentItemVanityMixin, ContentItemActiveDict):
5257
class _AttrsBase(TypedDict, total=False):
5358
# # `name` will be set by other _Attrs classes
5459
# name: str
@@ -119,24 +124,27 @@ def __init__(
119124
) -> None:
120125
_assert_guid(guid)
121126

122-
ctx = Context(params.session, params.url)
127+
ctx = ContentItemContext(Context(params.session, params.url), content_guid=guid)
123128
path = f"v1/content/{guid}"
124-
super().__init__(ctx, path, guid=guid, **kwargs)
129+
get_data = len(kwargs) == 0
130+
131+
super().__init__(ctx, path, get_data, guid=guid, **kwargs)
125132

126133
def __getitem__(self, key: Any) -> Any:
127134
v = super().__getitem__(key)
135+
# TODO-barret-Q: Why isn't this a property?
128136
if key == "owner" and isinstance(v, dict):
129-
return ContentItemOwner(params=self.params, **v)
137+
return ContentItemOwner(self._ctx, **v)
130138
return v
131139

132140
@property
133141
def oauth(self) -> ContentItemOAuth:
134-
return ContentItemOAuth(self.params, content_guid=self["guid"])
142+
return ContentItemOAuth(self._ctx)
135143

136144
@property
137145
def repository(self) -> ContentItemRepository | None:
138146
try:
139-
return ContentItemRepository(self._ctx, content_guid=self["guid"])
147+
return ContentItemRepository(self._ctx)
140148
except ClientError:
141149
return None
142150

@@ -163,11 +171,10 @@ def create_repository(
163171
"""
164172
return ContentItemRepository._create(self._ctx, self["guid"], **attrs)
165173

174+
# Rename to destroy()?
166175
def delete(self) -> None:
167176
"""Delete the content item."""
168-
path = f"v1/content/{self['guid']}"
169-
url = self.params.url + path
170-
self.params.session.delete(url)
177+
self._delete_api()
171178

172179
def deploy(self) -> tasks.Task:
173180
"""Deploy the content.
@@ -186,10 +193,10 @@ def deploy(self) -> tasks.Task:
186193
None
187194
"""
188195
path = f"v1/content/{self['guid']}/deploy"
189-
url = self.params.url + path
190-
response = self.params.session.post(url, json={"bundle_id": None})
196+
url = self._ctx.url + path
197+
response = self._ctx.session.post(url, json={"bundle_id": None})
191198
result = response.json()
192-
ts = tasks.Tasks(self.params)
199+
ts = tasks.Tasks(context_to_resource_parameters(self._ctx))
193200
return ts.get(result["task_id"])
194201

195202
def render(self) -> Task:
@@ -242,8 +249,8 @@ def restart(self) -> None:
242249
self.environment_variables.create(key, unix_epoch_in_seconds)
243250
self.environment_variables.delete(key)
244251
# GET via the base Connect URL to force create a new worker thread.
245-
url = posixpath.join(dirname(self.params.url), f"content/{self['guid']}")
246-
self.params.session.get(url)
252+
url = posixpath.join(dirname(self._ctx.url), f"content/{self['guid']}")
253+
self._ctx.session.get(url)
247254
return None
248255
else:
249256
raise ValueError(
@@ -253,7 +260,7 @@ def restart(self) -> None:
253260
def update(
254261
self,
255262
**attrs: Unpack[ContentItem._Attrs],
256-
) -> None:
263+
) -> ContentItem:
257264
"""Update the content item.
258265
259266
Parameters
@@ -313,38 +320,47 @@ def update(
313320
-------
314321
None
315322
"""
316-
url = self.params.url + f"v1/content/{self['guid']}"
317-
response = self.params.session.patch(url, json=attrs)
318-
super().update(**response.json())
323+
result = self._patch_api(json=cast(JsonifiableDict, dict(attrs)))
324+
assert isinstance(result, dict)
325+
assert "guid" in result
326+
new_content_item = ContentItem(
327+
params=context_to_resource_parameters(self._ctx),
328+
# `guid=` is contained within the `result` dict
329+
**result, # pyright: ignore[reportArgumentType, reportCallIssue]
330+
)
331+
# TODO-barret Update method returns new content item
332+
return new_content_item
319333

320334
# Relationships
321335

322336
@property
323337
def bundles(self) -> Bundles:
324-
return Bundles(self.params, self["guid"])
338+
return Bundles(context_to_resource_parameters(self._ctx), self["guid"])
325339

326340
@property
327341
def environment_variables(self) -> EnvVars:
328-
return EnvVars(self.params, self["guid"])
342+
return EnvVars(context_to_resource_parameters(self._ctx), self["guid"])
329343

330344
@property
331345
def permissions(self) -> Permissions:
332-
return Permissions(self.params, self["guid"])
346+
return Permissions(context_to_resource_parameters(self._ctx), self["guid"])
347+
348+
_owner: User
333349

334350
@property
335351
def owner(self) -> dict:
336-
if "owner" not in self:
352+
if "_owner" not in self.__dict__:
337353
# It is possible to get a content item that does not contain owner.
338354
# "owner" is an optional additional request param.
339355
# If it's not included, we can retrieve the information by `owner_guid`
340356
from .users import Users
341357

342-
self["owner"] = Users(self.params).get(self["owner_guid"])
343-
return self["owner"]
358+
self._owner = Users(context_to_resource_parameters(self._ctx)).get(self["owner_guid"])
359+
return self._owner
344360

345361
@property
346362
def _variants(self) -> Variants:
347-
return Variants(self.params, self["guid"])
363+
return Variants(context_to_resource_parameters(self._ctx), self["guid"])
348364

349365
@property
350366
def is_interactive(self) -> bool:

tests/posit/connect/test_content.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import responses
44
from responses import matchers
55

6+
from posit.connect._types_content_item import ContentItemContext
67
from posit.connect.client import Client
78
from posit.connect.content import ContentItem, ContentItemRepository
89
from posit.connect.context import Context
@@ -119,8 +120,8 @@ def test_update(self):
119120
json=fake_content,
120121
)
121122

122-
content.update(name=new_name)
123-
assert content["name"] == new_name
123+
new_content = content.update(name=new_name)
124+
assert new_content["name"] == new_name
124125

125126

126127
class TestContentCreate:
@@ -562,15 +563,22 @@ def content_guid(self):
562563

563564
@property
564565
def content_item(self):
565-
return ContentItem(self.params, guid=self.content_guid)
566+
return ContentItem(
567+
self.params,
568+
guid=self.content_guid,
569+
name="testing", # provide name to avoid request
570+
)
566571

567572
@property
568573
def endpoint(self):
569574
return f"{self.base_url}/__api__/v1/content/{self.content_guid}/repository"
570575

571576
@property
572577
def ctx(self):
573-
return Context(requests.Session(), Url(self.base_url))
578+
return ContentItemContext(
579+
Context(requests.Session(), Url(self.base_url)),
580+
content_guid=self.content_guid,
581+
)
574582

575583
@property
576584
def params(self):

0 commit comments

Comments
 (0)