Skip to content

Commit

Permalink
fix: remove all warnings from attribute access (#323)
Browse files Browse the repository at this point in the history
Removes all warning messages created by direct attribute access.
  • Loading branch information
tdstein authored Nov 8, 2024
1 parent 1dacc4d commit e507d3f
Show file tree
Hide file tree
Showing 18 changed files with 84 additions and 304 deletions.
4 changes: 3 additions & 1 deletion integration/tests/posit/connect/oauth/test_associations.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,9 @@ def test_find_update_by_content(self):
updated_associations = self.content.oauth.associations.find()
assert len(updated_associations) == 1
assert updated_associations[0]["app_guid"] == self.content["guid"]
assert updated_associations[0]["oauth_integration_guid"] == self.another_integration.guid
assert (
updated_associations[0]["oauth_integration_guid"] == self.another_integration["guid"]
)

# unset content association
self.content.oauth.associations.delete()
Expand Down
2 changes: 1 addition & 1 deletion integration/tests/posit/connect/oauth/test_integrations.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ def test_create_update_delete(self):

created.update(name="updated integration name")
updated = self.client.oauth.integrations.get(integration["guid"])
assert updated.name == "updated integration name"
assert updated["name"] == "updated integration name"

# delete the new integration

Expand Down
4 changes: 3 additions & 1 deletion integration/tests/posit/connect/test_groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@


class TestGroups:
@classmethod
def setup_class(cls):
cls.client = connect.Client()
cls.item = cls.client.groups.create(name="Friends")

@classmethod
def teardown_class(cls):
cls.item.delete()
assert cls.client.groups.count() == 0
Expand All @@ -14,7 +16,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
8 changes: 4 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,9 @@ 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 +77,7 @@ 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
16 changes: 8 additions & 8 deletions src/posit/connect/content.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def oauth(self) -> ContentItemOAuth:

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 @@ -75,7 +75,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 @@ -99,7 +99,7 @@ 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 @@ -108,7 +108,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 @@ -132,12 +132,12 @@ def restart(self) -> None:
self.environment_variables.create(key, unix_epoch_in_seconds)
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}")
url = posixpath.join(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 @@ -276,7 +276,7 @@ def _variants(self) -> Variants:

@property
def is_interactive(self) -> bool:
return self.app_mode in {
return self["app_mode"] in {
"api",
"jupyter-voila",
"python-api",
Expand All @@ -293,7 +293,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 @@ -14,7 +14,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 @@ -33,13 +33,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
2 changes: 1 addition & 1 deletion src/posit/connect/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,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
2 changes: 1 addition & 1 deletion src/posit/connect/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def lock(self, *, force: bool = False):
>>> user.lock(force=True)
"""
_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.",
)
Expand Down
68 changes: 9 additions & 59 deletions tests/posit/connect/oauth/test_integrations.py
Original file line number Diff line number Diff line change
@@ -1,61 +1,11 @@
from unittest import mock

import responses
from responses import matchers

from posit.connect.client import Client
from posit.connect.oauth.associations import IntegrationAssociations
from posit.connect.oauth.integrations import Integration

from ..api import load_mock # type: ignore


class TestIntegrationAttributes:
@classmethod
def setup_class(cls):
guid = "22644575-a27b-4118-ad06-e24459b05126"
fake_item = load_mock(f"v1/oauth/integrations/{guid}.json")
cls.item = Integration(mock.Mock(), **fake_item)

def test_id(self):
assert self.item.id == "3"

def test_guid(self):
assert self.item.guid == "22644575-a27b-4118-ad06-e24459b05126"

def test_name(self):
assert self.item.name == "keycloak integration"

def test_description(self):
assert self.item.description == "integration description"

def test_template(self):
assert self.item.template == "custom"

def test_config(self):
assert self.item.config["auth_mode"] == "Confidential"
assert (
self.item.config["authorization_uri"]
== "http://keycloak:8080/realms/rsconnect/protocol/openid-connect/auth"
)
assert self.item.config["client_id"] == "rsconnect-oidc"
assert self.item.config["scopes"] == "email"
assert self.item.config["token_endpoint_auth_method"] == "client_secret_basic"
assert (
self.item.config["token_uri"]
== "http://keycloak:8080/realms/rsconnect/protocol/openid-connect/token"
)

def test_created_time(self):
assert self.item.created_time == "2024-07-16T19:28:05Z"

def test_updated_time(self):
assert self.item.updated_time == "2024-07-17T19:28:05Z"

def test_associations(self):
assert isinstance(self.item.associations, IntegrationAssociations)


class TestIntegrationDelete:
@responses.activate
def test(self):
Expand Down Expand Up @@ -96,7 +46,7 @@ def test(self):
c = Client("https://connect.example", "12345")
c.ctx.version = None
integration = c.oauth.integrations.get(guid)
assert integration.guid == guid
assert integration["guid"] == guid

new_name = "New Name"

Expand All @@ -111,7 +61,7 @@ def test(self):

integration.update(name=new_name)
assert mock_update.call_count == 1
assert integration.name == new_name
assert integration["name"] == new_name


class TestIntegrationsCreate:
Expand Down Expand Up @@ -151,10 +101,10 @@ def test(self):

# assert
assert mock_create.call_count == 1
assert integration.name == fake_integration["name"]
assert integration.description == fake_integration["description"]
assert integration.template == fake_integration["template"]
assert integration.config == fake_integration["config"]
assert integration["name"] == fake_integration["name"]
assert integration["description"] == fake_integration["description"]
assert integration["template"] == fake_integration["template"]
assert integration["config"] == fake_integration["config"]


class TestIntegrationsFind:
Expand All @@ -176,8 +126,8 @@ def test(self):
# assert
assert mock_get.call_count == 1
assert len(integrations) == 2
assert integrations[0].id == "3"
assert integrations[1].id == "4"
assert integrations[0]["id"] == "3"
assert integrations[1]["id"] == "4"


class TestIntegrationsGet:
Expand All @@ -197,4 +147,4 @@ def test(self):
integration = c.oauth.integrations.get(guid)

assert mock_get.call_count == 1
assert integration.guid == guid
assert integration["guid"] == guid
40 changes: 4 additions & 36 deletions tests/posit/connect/oauth/test_sessions.py
Original file line number Diff line number Diff line change
@@ -1,43 +1,11 @@
from unittest import mock

import responses
from responses import matchers

from posit.connect.client import Client
from posit.connect.oauth.sessions import Session

from ..api import load_mock # type: ignore


class TestOAuthSessionAttributes:
@classmethod
def setup_class(cls):
guid = "32c04dc6-0318-41b7-bc74-7e321b196f14"
fake_item = load_mock(f"v1/oauth/sessions/{guid}.json")
cls.item = Session(mock.Mock(), **fake_item)

def test_id(self):
assert self.item.id == "54"

def test_guid(self):
assert self.item.guid == "32c04dc6-0318-41b7-bc74-7e321b196f14"

def test_user_guid(self):
assert self.item.user_guid == "217be1f2-6a32-46b9-af78-e3f4b89f2e74"

def test_oauth_integration_guid(self):
assert self.item.oauth_integration_guid == "967f0ad3-3e3b-4491-8539-1a193b35a415"

def test_has_refresh_token(self):
assert self.item.has_refresh_token

def test_created_time(self):
assert self.item.created_time == "2024-07-24T15:59:51Z"

def test_updated_time(self):
assert self.item.updated_time == "2024-07-24T16:59:51Z"


class TestSessionDelete:
@responses.activate
def test(self):
Expand Down Expand Up @@ -82,9 +50,9 @@ def test(self):
# assert
assert mock_get.call_count == 1
assert len(sessions) == 3
assert sessions[0].id == "54"
assert sessions[1].id == "55"
assert sessions[2].id == "56"
assert sessions[0]["id"] == "54"
assert sessions[1]["id"] == "55"
assert sessions[2]["id"] == "56"

@responses.activate
def test_params_all(self):
Expand Down Expand Up @@ -126,4 +94,4 @@ def test(self):

# assert
assert mock_get.call_count == 1
assert session.guid == guid
assert session["guid"] == guid
Loading

0 comments on commit e507d3f

Please sign in to comment.