Skip to content

Commit 91aa99b

Browse files
committed
refactor: correct method names and reduce fluff.
1 parent ab69342 commit 91aa99b

File tree

2 files changed

+42
-90
lines changed

2 files changed

+42
-90
lines changed

src/posit/connect/vanities.py

Lines changed: 42 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
from typing import Callable, List, Optional, Union, overload
1+
from typing import Callable, List, Optional, TypedDict, Union
22

3-
from posit.connect.errors import ClientError
3+
from typing_extensions import NotRequired, Required, Unpack
44

5+
from .errors import ClientError
56
from .resources import Resource, ResourceParameters, Resources
67

78
AfterDestroyCallback = Callable[[], None]
@@ -51,6 +52,7 @@ def __init__(
5152
/,
5253
params: ResourceParameters,
5354
*,
55+
content_guid: str,
5456
after_destroy: Optional[AfterDestroyCallback] = None,
5557
**kwargs,
5658
):
@@ -62,7 +64,8 @@ def __init__(
6264
after_destroy : AfterDestroyCallback, optional
6365
Called after the Vanity is successfully destroyed, by default None
6466
"""
65-
super().__init__(params, **kwargs)
67+
super().__init__(params, content_guid=content_guid, **kwargs)
68+
self._endpoint = self.params.url + f"v1/content/{content_guid}/vanity"
6669
self._after_destroy = after_destroy
6770

6871
def destroy(self) -> None:
@@ -81,11 +84,7 @@ def destroy(self) -> None:
8184
----
8285
This action requires administrator privileges.
8386
"""
84-
fuid = self.get("content_guid")
85-
if fuid is None:
86-
raise ValueError("Missing value for required field: 'content_guid'.")
87-
endpoint = self.params.url + f"v1/content/{fuid}/vanity"
88-
self.params.session.delete(endpoint)
87+
self.params.session.delete(self._endpoint)
8988

9089
if self._after_destroy:
9190
self._after_destroy()
@@ -114,35 +113,37 @@ def all(self) -> List[Vanity]:
114113
class VanityMixin(Resource):
115114
"""Mixin class to add a vanity attribute to a resource."""
116115

117-
_uid: str = "guid"
118-
"""str : the unique identifier field for this resource"""
116+
class HasGuid(TypedDict):
117+
"""Has a guid."""
118+
119+
guid: str
119120

120-
def __init__(self, /, params: ResourceParameters, **kwargs):
121+
def __init__(self, /, params: ResourceParameters, **kwargs: Unpack[HasGuid]):
121122
super().__init__(params, **kwargs)
123+
self._uid = kwargs['guid']
122124
self._vanity: Optional[Vanity] = None
123125

126+
@property
127+
def _endpoint(self):
128+
return self.params.url + f"v1/content/{self._uid}/vanity"
129+
124130
@property
125131
def vanity(self) -> Optional[Vanity]:
126-
"""Retrieve or lazily load the associated vanity resource."""
132+
"""Get the vanity."""
127133
if self._vanity:
128134
return self._vanity
129135

130136
try:
131-
v = self.get(self._uid)
132-
if v is None:
133-
raise ValueError(f"Missing value for required field: '{self._uid}'.")
134-
endpoint = self.params.url + f"v1/content/{v}/vanity"
135-
response = self.params.session.get(endpoint)
136-
result = response.json()
137-
self._vanity = Vanity(self.params, after_destroy=self.reset_vanity, **result)
137+
self._vanity = self.find_vanity()
138+
self._vanity._after_destroy = self.reset_vanity
138139
return self._vanity
139140
except ClientError as e:
140141
if e.http_status == 404:
141142
return None
142143
raise e
143144

144145
@vanity.setter
145-
def vanity(self, value: Union[str, dict]) -> None:
146+
def vanity(self, value: Union[str, "CreateVanityRequest"]) -> None:
146147
"""Set the vanity.
147148
148149
Parameters
@@ -151,9 +152,9 @@ def vanity(self, value: Union[str, dict]) -> None:
151152
The value can be a string or a dictionary. If provided as a string, it represents the vanity path. If provided as a dictionary, it contains key-value pairs with detailed information about the object.
152153
"""
153154
if isinstance(value, str):
154-
self.set_vanity(path=value)
155+
self.create_vanity(path=value)
155156
elif isinstance(value, dict):
156-
self.set_vanity(**value)
157+
self.create_vanity(**value)
157158
self.reset_vanity()
158159

159160
@vanity.deleter
@@ -183,71 +184,33 @@ def reset_vanity(self) -> None:
183184
"""
184185
self._vanity = None
185186

186-
@overload
187-
def set_vanity(self, *, path: str) -> None:
188-
"""Set the vanity.
189-
190-
Parameters
191-
----------
192-
path : str
193-
The vanity path.
194-
195-
Raises
196-
------
197-
ValueError
198-
If the unique identifier field is missing or the value is None.
199-
"""
200-
...
187+
class CreateVanityRequest(TypedDict, total=False):
188+
"""A request schema for creating a vanity.
201189
202-
@overload
203-
def set_vanity(self, *, path: str, force: bool) -> None:
204-
"""Set the vanity.
205-
206-
Parameters
190+
Attributes
207191
----------
208192
path : str
209-
The vanity path.
193+
The path for the vanity.
210194
force : bool
211-
If `True`, overwrite the ownership of this vanity to this resource, default `False`
212-
213-
Raises
214-
------
215-
ValueError
216-
If the unique identifier field is missing or the value is None.
195+
Whether to force the creation of the vanity.
217196
"""
218-
...
219-
220-
@overload
221-
def set_vanity(self, **attributes) -> None:
222-
"""Set the vanity.
223197

224-
Parameters
225-
----------
226-
**attributes : dict, optional
227-
Arbitrary attributes. All attributes are passed as the request body to POST 'v1/content/:guid/vanity'
228-
229-
Raises
230-
------
231-
ValueError
232-
If the unique identifier field is missing or the value is None.
233-
"""
234-
...
198+
path: Required[str]
199+
force: NotRequired[bool]
235200

236-
def set_vanity(self, **attributes) -> None:
237-
"""Set the vanity.
201+
def create_vanity(self, **kwargs: Unpack[CreateVanityRequest]) -> None:
202+
"""Create a vanity.
238203
239204
Parameters
240205
----------
241-
**attributes : dict, optional
242-
Arbitrary attributes. All attributes are passed as the request body to POST 'v1/content/:guid/vanity'
243-
244-
Raises
245-
------
246-
ValueError
247-
If the unique identifier field is missing or the value is None.
206+
path : str, required
207+
The path for the vanity.
208+
force : bool, not required
209+
Whether to force the creation of the vanity, default False
248210
"""
249-
v = self.get(self._uid)
250-
if v is None:
251-
raise ValueError(f"Missing value for required field: '{self._uid}'.")
252-
endpoint = self.params.url + f"v1/content/{v}/vanity"
253-
self.params.session.put(endpoint, json=attributes)
211+
self.params.session.put(self._endpoint, json=kwargs)
212+
213+
def find_vanity(self):
214+
response = self.params.session.get(self._endpoint)
215+
result = response.json()
216+
return Vanity(self.params, **result)

tests/posit/connect/test_vanities.py

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
from unittest.mock import Mock
22

3-
import pytest
43
import requests
54
import responses
65
from responses.matchers import json_params_matcher
@@ -27,16 +26,6 @@ def test_destroy_sends_delete_request(self):
2726

2827
assert mock_delete.call_count == 1
2928

30-
def test_destroy_without_content_guid_raises_value_error(self):
31-
vanity = Vanity(params=Mock())
32-
with pytest.raises(ValueError):
33-
vanity.destroy()
34-
35-
def test_destroy_with_none_content_guid_raises_value_error(self):
36-
vanity = Vanity(params=Mock(), content_guid=None)
37-
with pytest.raises(ValueError):
38-
vanity.destroy()
39-
4029
@responses.activate
4130
def test_destroy_calls_after_destroy_callback(self):
4231
content_guid = "8ce6eaca-60af-4c2f-93a0-f5f3cddf5ee5"

0 commit comments

Comments
 (0)