Skip to content

Commit f4c5445

Browse files
committed
feat: add factory support to resource sequences
1 parent 8f8b982 commit f4c5445

File tree

3 files changed

+29
-30
lines changed

3 files changed

+29
-30
lines changed

src/posit/connect/content.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@
1919
overload,
2020
)
2121

22-
from posit.connect.jobs import _Jobs, Job
23-
2422
from . import tasks
2523
from ._api import ApiDictEndpoint, JsonifiableDict
2624
from .bundles import Bundles
@@ -516,7 +514,7 @@ def tags(self) -> ContentItemTags:
516514
@property
517515
def jobs(self) -> Jobs:
518516
path = posixpath.join(self._path, "jobs")
519-
return _Jobs(self._ctx, path, uid="key")
517+
return _ResourceSequence(self._ctx, path, uid="key")
520518

521519
@property
522520
@requires(version="2024.11.0")

src/posit/connect/jobs.py

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
from __future__ import annotations
22

3-
from typing import Any, List
4-
53
from typing_extensions import (
64
Iterable,
75
Literal,
86
Protocol,
97
runtime_checkable,
108
)
119

12-
from .resources import Resource, ResourceSequence, _Resource, _ResourceSequence
10+
from .resources import Resource, ResourceSequence
1311

1412
JobTag = Literal[
1513
"unknown",
@@ -56,11 +54,6 @@ def destroy(self) -> None:
5654
"""
5755

5856

59-
class _Job(_Resource):
60-
def wait_for(self) -> None:
61-
pass
62-
63-
6457
@runtime_checkable
6558
class Jobs(ResourceSequence[Job], Protocol):
6659
def fetch(self) -> Iterable[Job]:
@@ -173,9 +166,3 @@ def find_by(
173166
This action requires administrator, owner, or collaborator privileges.
174167
"""
175168
...
176-
177-
178-
class _Jobs(_ResourceSequence[Job]):
179-
def fetch(self, **conditions) -> Iterable[Any]:
180-
resources = super().fetch(**conditions)
181-
return [_Job(**resource) for resource in resources]

src/posit/connect/resources.py

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import posixpath
44
import warnings
55
from abc import ABC
6+
from typing import ItemsView, cast
67

78
from typing_extensions import (
89
TYPE_CHECKING,
@@ -73,6 +74,8 @@ def __init__(self, ctx: Context, path: str, /, **attributes):
7374
class Resource(Protocol):
7475
def __getitem__(self, key: Hashable) -> Any: ...
7576

77+
def items(self) -> ItemsView: ...
78+
7679

7780
class _Resource(dict, Resource):
7881
def __init__(self, ctx: Context, path: str, **attributes):
@@ -92,6 +95,10 @@ def update(self, **attributes): # type: ignore[reportIncompatibleMethodOverride
9295
T = TypeVar("T", bound=Resource)
9396

9497

98+
class ResourceFactory(Protocol):
99+
def __call__(self, ctx: Context, path: str, **attributes) -> Resource: ...
100+
101+
95102
class ResourceSequence(Protocol[T]):
96103
@overload
97104
def __getitem__(self, index: SupportsIndex, /) -> T: ...
@@ -109,10 +116,17 @@ def __repr__(self) -> str: ...
109116

110117

111118
class _ResourceSequence(Sequence[T], ResourceSequence[T]):
112-
def __init__(self, ctx: Context, path: str, *, uid: str = "guid"):
119+
def __init__(
120+
self,
121+
ctx: Context,
122+
path: str,
123+
factory: ResourceFactory = _Resource,
124+
uid: str = "guid",
125+
):
113126
self._ctx = ctx
114127
self._path = path
115128
self._uid = uid
129+
self._factory = factory
116130

117131
def __getitem__(self, index):
118132
return list(self.fetch())[index]
@@ -129,32 +143,32 @@ def __str__(self) -> str:
129143
def __repr__(self) -> str:
130144
return repr(self.fetch())
131145

132-
def create(self, **attributes: Any) -> Any:
146+
def create(self, **attributes: Any) -> T:
133147
response = self._ctx.client.post(self._path, json=attributes)
134148
result = response.json()
135149
uid = result[self._uid]
136150
path = posixpath.join(self._path, uid)
137-
return _Resource(self._ctx, path, **result)
151+
return cast(T, self._factory(self._ctx, path, **result))
138152

139-
def fetch(self, **conditions) -> Iterable[Any]:
153+
def fetch(self, **conditions) -> Iterable[T]:
140154
response = self._ctx.client.get(self._path, params=conditions)
141155
results = response.json()
142-
resources = []
156+
resources: List[T] = []
143157
for result in results:
144158
uid = result[self._uid]
145159
path = posixpath.join(self._path, uid)
146-
resource = _Resource(self._ctx, path, **result)
160+
resource = cast(T, self._factory(self._ctx, path, **result))
147161
resources.append(resource)
148162

149163
return resources
150164

151-
def find(self, *args: str) -> Any:
165+
def find(self, *args: str) -> T:
152166
path = posixpath.join(self._path, *args)
153167
response = self._ctx.client.get(path)
154168
result = response.json()
155-
return _Resource(self._ctx, path, **result)
169+
return cast(T, self._factory(self._ctx, path, **result))
156170

157-
def find_by(self, **conditions) -> Any | None:
171+
def find_by(self, **conditions) -> T | None:
158172
"""
159173
Find the first record matching the specified conditions.
160174
@@ -169,19 +183,19 @@ def find_by(self, **conditions) -> Any | None:
169183
Optional[T]
170184
The first record matching the conditions, or `None` if no match is found.
171185
"""
172-
collection = self.fetch(**conditions)
186+
collection: Iterable[T] = self.fetch(**conditions)
173187
return next((v for v in collection if v.items() >= conditions.items()), None)
174188

175189

176-
class _PaginatedResourceSequence(_ResourceSequence):
177-
def fetch(self, **conditions):
190+
class _PaginatedResourceSequence(_ResourceSequence[T]):
191+
def fetch(self, **conditions) -> Iterator[T]:
178192
paginator = Paginator(self._ctx, self._path, dict(**conditions))
179193
for page in paginator.fetch_pages():
180194
resources = []
181195
results = page.results
182196
for result in results:
183197
uid = result[self._uid]
184198
path = posixpath.join(self._path, uid)
185-
resource = _Resource(self._ctx, path, **result)
199+
resource = cast(T, self._factory(self._ctx, path, **result))
186200
resources.append(resource)
187201
yield from resources

0 commit comments

Comments
 (0)