Skip to content

Commit

Permalink
chore! drop support field access by attribute.
Browse files Browse the repository at this point in the history
BREAKING CHANGE: removes support for accessing resource fields using
`__getattr__` (e.g., `user.username`). Use `__getitem__` instead (e.g.,
`user["username"]`.
  • Loading branch information
tdstein committed Sep 6, 2024
1 parent cdcb1bf commit 895d996
Show file tree
Hide file tree
Showing 16 changed files with 79 additions and 444 deletions.
6 changes: 3 additions & 3 deletions integration/tests/posit/connect/test_content.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def test_count(self):
assert self.client.content.count() == 1

def test_get(self):
assert self.client.content.get(self.content.guid) == self.content
assert self.client.content.get(self.content["guid"]) == self.content

def test_find(self):
assert self.client.content.find()
Expand All @@ -34,12 +34,12 @@ def test_find_one(self):
def test_content_item_owner(self):
item = self.client.content.find_one(include=None)
owner = item.owner
assert owner.guid == self.client.me.guid
assert owner["guid"] == self.client.me["guid"]

def test_content_item_owner_from_include(self):
item = self.client.content.find_one(include="owner")
owner = item.owner
assert owner.guid == self.client.me.guid
assert owner["guid"] == self.client.me["guid"]

@pytest.mark.skipif(
CONNECT_VERSION <= version.parse("2024.04.1"),
Expand Down
2 changes: 1 addition & 1 deletion integration/tests/posit/connect/test_groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ def test_count(self):
assert self.client.groups.count() == 1

def test_get(self):
assert self.client.groups.get(self.item.guid)
assert self.client.groups.get(self.item["guid"])

def test_find(self):
assert self.client.groups.find() == [self.item]
Expand Down
12 changes: 8 additions & 4 deletions src/posit/connect/bundles.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def metadata(self) -> BundleMetadata:

def delete(self) -> None:
"""Delete the bundle."""
path = f"v1/content/{self.content_guid}/bundles/{self.id}"
path = f"v1/content/{self['content_guid']}/bundles/{self['id']}"
url = self.params.url + path
self.params.session.delete(url)

Expand All @@ -39,9 +39,11 @@ def deploy(self) -> tasks.Task:
>>> task.wait_for()
None
"""
path = f"v1/content/{self.content_guid}/deploy"
path = f"v1/content/{self['content_guid']}/deploy"
url = self.params.url + path
response = self.params.session.post(url, json={"bundle_id": self.id})
response = self.params.session.post(
url, json={"bundle_id": self["id"]}
)
result = response.json()
ts = tasks.Tasks(self.params)
return ts.get(result["task_id"])
Expand Down Expand Up @@ -77,7 +79,9 @@ def download(self, output: io.BufferedWriter | str) -> None:
f"download() expected argument type 'io.BufferedWriter` or 'str', but got '{type(output).__name__}'"
)

path = f"v1/content/{self.content_guid}/bundles/{self.id}/download"
path = (
f"v1/content/{self['content_guid']}/bundles/{self['id']}/download"
)
url = self.params.url + path
response = self.params.session.get(url, stream=True)
if isinstance(output, io.BufferedWriter):
Expand Down
30 changes: 16 additions & 14 deletions src/posit/connect/content.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def __getitem__(self, key: Any) -> Any:

def delete(self) -> None:
"""Delete the content item."""
path = f"v1/content/{self.guid}"
path = f"v1/content/{self['guid']}"
url = self.params.url + path
self.params.session.delete(url)

Expand All @@ -49,7 +49,7 @@ def deploy(self) -> tasks.Task:
>>> task.wait_for()
None
"""
path = f"v1/content/{self.guid}/deploy"
path = f"v1/content/{self['guid']}/deploy"
url = self.params.url + path
response = self.params.session.post(url, json={"bundle_id": None})
result = response.json()
Expand All @@ -73,7 +73,9 @@ def render(self) -> Task:

if self.is_rendered:
variants = self._variants.find()
variants = [variant for variant in variants if variant.is_default]
variants = [
variant for variant in variants if variant["is_default"]
]
if len(variants) != 1:
raise RuntimeError(
f"Found {len(variants)} default variants. Expected 1. Without a single default variant, the content cannot be refreshed. This is indicative of a corrupted state."
Expand All @@ -82,7 +84,7 @@ def render(self) -> Task:
return variant.render()
else:
raise ValueError(
f"Render not supported for this application mode: {self.app_mode}. Did you need to use the 'restart()' method instead? Note that some application modes do not support 'render()' or 'restart()'."
f"Render not supported for this application mode: {{self['app_mode']}}. Did you need to use the 'restart()' method instead? Note that some application modes do not support 'render()' or 'restart()'."
)

def restart(self) -> None:
Expand All @@ -107,13 +109,13 @@ def restart(self) -> None:
self.environment_variables.delete(key)
# GET via the base Connect URL to force create a new worker thread.
url = posixpath.join(
dirname(self.params.url), f"content/{self.guid}"
dirname(self.params.url), f"content/{self['guid']}"
)
self.params.session.get(url)
return None
else:
raise ValueError(
f"Restart not supported for this application mode: {self.app_mode}. Did you need to use the 'render()' method instead? Note that some application modes do not support 'render()' or 'restart()'."
f"Restart not supported for this application mode: {self['app_mode']}. Did you need to use the 'render()' method instead? Note that some application modes do not support 'render()' or 'restart()'."
)

@overload
Expand Down Expand Up @@ -187,23 +189,23 @@ def update(self, *args, **kwargs) -> None:
def update(self, *args, **kwargs) -> None:
"""Update the content item."""
body = dict(*args, **kwargs)
url = self.params.url + f"v1/content/{self.guid}"
url = self.params.url + f"v1/content/{self['guid']}"
response = self.params.session.patch(url, json=body)
super().update(**response.json())

# Relationships

@property
def bundles(self) -> Bundles:
return Bundles(self.params, self.guid)
return Bundles(self.params, self["guid"])

@property
def environment_variables(self) -> EnvVars:
return EnvVars(self.params, self.guid)
return EnvVars(self.params, self["guid"])

@property
def permissions(self) -> Permissions:
return Permissions(self.params, self.guid)
return Permissions(self.params, self["guid"])

@property
def owner(self) -> dict:
Expand All @@ -213,16 +215,16 @@ def owner(self) -> dict:
# If it's not included, we can retrieve the information by `owner_guid`
from .users import Users

self["owner"] = Users(self.params).get(self.owner_guid)
self["owner"] = Users(self.params).get(self["owner_guid"])
return self["owner"]

@property
def _variants(self) -> Variants:
return Variants(self.params, self.guid)
return Variants(self.params, self["guid"])

@property
def is_interactive(self) -> bool:
return self.app_mode in {
return self["app_mode"] in {
"api",
"jupyter-voila",
"python-api",
Expand All @@ -239,7 +241,7 @@ def is_interactive(self) -> bool:

@property
def is_rendered(self) -> bool:
return self.app_mode in {
return self["app_mode"] in {
"rmd-static",
"jupyter-static",
"quarto-static",
Expand Down
2 changes: 1 addition & 1 deletion src/posit/connect/groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
class Group(Resource):
def delete(self) -> None:
"""Delete the group."""
path = f"v1/groups/{self.guid}"
path = f"v1/groups/{self['guid']}"
url = self.params.url + path
self.params.session.delete(url)

Expand Down
10 changes: 5 additions & 5 deletions src/posit/connect/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
class Permission(Resource):
def delete(self) -> None:
"""Delete the permission."""
path = f"v1/content/{self.content_guid}/permissions/{self.id}"
path = f"v1/content/{self['content_guid']}/permissions/{self['id']}"
url = self.params.url + path
self.params.session.delete(url)

Expand All @@ -35,13 +35,13 @@ def update(self, *args, **kwargs) -> None:
def update(self, *args, **kwargs) -> None:
"""Update the permission."""
body = {
"principal_guid": self.principal_guid,
"principal_type": self.principal_type,
"role": self.role,
"principal_guid": self.get("principal_guid"),
"principal_type": self.get("principal_type"),
"role": self.get("role"),
}
body.update(dict(*args))
body.update(**kwargs)
path = f"v1/content/{self.content_guid}/permissions/{self.id}"
path = f"v1/content/{self['content_guid']}/permissions/{self['id']}"
url = self.params.url + path
response = self.params.session.put(
url,
Expand Down
11 changes: 0 additions & 11 deletions src/posit/connect/resources.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import warnings
from dataclasses import dataclass

import requests
Expand Down Expand Up @@ -26,16 +25,6 @@ def __init__(self, /, params: ResourceParameters, **kwargs):
self.params = params
super().__init__(**kwargs)

def __getattr__(self, name):
if name in self:
warnings.warn(
f"Accessing the field '{name}' via attribute is deprecated and will be removed in v1.0.0. "
f"Please use __getitem__ (e.g., {self.__class__.__name__.lower()}['{name}']) for field access instead.",
DeprecationWarning,
)
return self[name]
return None

def update(self, *args, **kwargs):
super().update(*args, **kwargs)

Expand Down
2 changes: 1 addition & 1 deletion src/posit/connect/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ def update(self, *args, **kwargs) -> None:
]
"""
params = dict(*args, **kwargs)
path = f"v1/tasks/{self.id}"
path = f"v1/tasks/{self['id']}"
url = self.params.url + path
response = self.params.session.get(url, params=kwargs)
result = response.json()
Expand Down
10 changes: 5 additions & 5 deletions src/posit/connect/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
class User(Resource):
@property
def content(self) -> Content:
return Content(self.params, owner_guid=self.guid)
return Content(self.params, owner_guid=self["guid"])

def lock(self, *, force: bool = False):
"""
Expand All @@ -29,11 +29,11 @@ def lock(self, *, force: bool = False):
None
"""
_me = me.get(self.params)
if _me.guid == self.guid and not force:
if _me["guid"] == self["guid"] and not force:
raise RuntimeError(
"You cannot lock your own account. Set force=True to override this behavior."
)
url = self.params.url + f"v1/users/{self.guid}/lock"
url = self.params.url + f"v1/users/{self['guid']}/lock"
body = {"locked": True}
self.params.session.post(url, json=body)
super().update(locked=True)
Expand All @@ -46,7 +46,7 @@ def unlock(self):
-------
None
"""
url = self.params.url + f"v1/users/{self.guid}/lock"
url = self.params.url + f"v1/users/{self['guid']}/lock"
body = {"locked": False}
self.params.session.post(url, json=body)
super().update(locked=False)
Expand Down Expand Up @@ -106,7 +106,7 @@ def update(self, *args, **kwargs) -> None:
None
"""
body = dict(*args, **kwargs)
url = self.params.url + f"v1/users/{self.guid}"
url = self.params.url + f"v1/users/{self['guid']}"
response = self.params.session.put(url, json=body)
super().update(**response.json())

Expand Down
Loading

0 comments on commit 895d996

Please sign in to comment.