Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: adds bundles #161

Merged
merged 2 commits into from
Apr 11, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 129 additions & 0 deletions src/posit/connect/bundles.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
from __future__ import annotations

from typing import List

from requests.sessions import Session as Session

from posit.connect.config import Config

from . import urls

from .resources import Resources, Resource


class BundleMetadata(Resource):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this need to be a Class? It's not a Resource properly, is it? There's nothing you can do with it. It just feels like a nested field in Bundle to me, Bundle.metadata is a dict.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm considering this a continuation of the pattern of using @property methods for fields to support compatibility between server versions.

@property
def source(self) -> str | None:
return self.get("source")

@property
def source_repo(self) -> str | None:
return self.get("source_repo")

@property
def source_branch(self) -> str | None:
return self.get("source_branch")

@property
def source_commit(self) -> str | None:
return self.get("source_commit")

@property
def archive_md5(self) -> str | None:
return self.get("archive_md5")

@property
def archive_sha1(self) -> str | None:
return self.get("archive_sha1")


class Bundle(Resource):
@property
def id(self) -> str:
return self["id"]

@property
def content_guid(self) -> str:
return self["content_guid"]

@property
def created_time(self) -> str:
return self["created_time"]

@property
def cluster_name(self) -> str | None:
return self.get("cluster_name")

@property
def image_name(self) -> str | None:
return self.get("image_name")

@property
def r_version(self) -> str | None:
return self.get("r_version")

@property
def r_environment_management(self) -> bool | None:
return self.get("r_environment_management")

@property
def py_version(self) -> str | None:
return self.get("py_version")

@property
def py_environment_management(self) -> bool | None:
return self.get("py_environment_management")

@property
def quarto_version(self) -> str | None:
return self.get("quarto_version")

@property
def active(self) -> bool | None:
return self["active"]

@property
def size(self) -> int | None:
return self["size"]

@property
def metadata(self) -> BundleMetadata:
return BundleMetadata(self.config, self.session, **self.get("metadata", {}))

# Accessor Methods

def delete(self) -> None:
path = f"v1/content/{self.content_guid}/bundles/{self.id}"
url = urls.append_path(self.config.url, path)
self.session.delete(url)


class Bundles(Resources):
def __init__(self, config: Config, session: Session, content_guid: str) -> None:
super().__init__(config, session)
self.content_guid = content_guid

def find(self) -> List[Bundle]:
path = f"v1/content/{self.content_guid}/bundles"
url = urls.append_path(self.config.url, path)
response = self.session.get(url)
results = response.json()
return [
Bundle(
self.config,
self.session,
**result,
)
for result in results
]

def find_one(self) -> Bundle | None:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

find_one() is pretty pointless without any args or query params, no?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have defined find and fine_one in each of the Resources classes thus far, it seems ok to continue that pattern. I'm still up for adding fetch and fetch_one in place of find and find_one when there aren't any supported query params for the endpoint.

bundles = self.find()
return next(iter(bundles), None)

def get(self, id: str) -> Bundle:
path = f"v1/content/{self.content_guid}/bundles/{id}"
url = urls.append_path(self.config.url, path)
response = self.session.get(url)
result = response.json()
return Bundle(self.config, self.session, **result)
17 changes: 14 additions & 3 deletions src/posit/connect/content.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,26 @@
from . import urls

from .config import Config
from .bundles import Bundles
from .permissions import Permissions
from .resources import Resources, Resource


class ContentItem(Resource):
"""A piece of content."""

# Relationships

@property
def bundles(self) -> Bundles:
return Bundles(self.config, self.session, self.guid)

@property
def permissions(self) -> Permissions:
return Permissions(self.config, self.session, self.guid)

# Properties

@property
def id(self) -> str:
return self.get("id") # type: ignore
Expand Down Expand Up @@ -189,9 +202,7 @@ def dashboard_url(self) -> str:
def app_role(self) -> str:
return self.get("app_role") # type: ignore

@property
def permissions(self) -> Permissions:
return Permissions(self.config, self.session, content_guid=self.guid)
# Accessor Methods
tdstein marked this conversation as resolved.
Show resolved Hide resolved

def delete(self) -> None:
"""Delete the content item."""
Expand Down
2 changes: 1 addition & 1 deletion src/posit/connect/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def update(self, *args, **kwargs) -> None:


class Permissions(Resources):
def __init__(self, config: Config, session: Session, *, content_guid: str) -> None:
def __init__(self, config: Config, session: Session, content_guid: str) -> None:
super().__init__(config, session)
self.content_guid = content_guid

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[
{
"id": "101",
"content_guid": "f2f37341-e21d-3d80-c698-a935ad614066",
"created_time": "2006-01-02T15:04:05Z07:00",
"cluster_name": "Local",
"image_name": "Local",
"r_version": "3.5.1",
"r_environment_management": true,
"py_version": "3.8.2",
"py_environment_management": true,
"quarto_version": "0.2.22",
"active": false,
"size": 1000000,
"metadata": {
"source": "string",
"source_repo": "string",
"source_branch": "string",
"source_commit": "string",
"archive_md5": "37324238a80595c453c706b22adb83d3",
"archive_sha1": "a2f7d13d87657df599aeeabdb70194d508cfa92f"
}
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"id": "101",
"content_guid": "f2f37341-e21d-3d80-c698-a935ad614066",
"created_time": "2006-01-02T15:04:05Z07:00",
"cluster_name": "Local",
"image_name": "Local",
"r_version": "3.5.1",
"r_environment_management": true,
"py_version": "3.8.2",
"py_environment_management": true,
"quarto_version": "0.2.22",
"active": false,
"size": 1000000,
"metadata": {
"source": "string",
"source_repo": "string",
"source_branch": "string",
"source_commit": "string",
"archive_md5": "37324238a80595c453c706b22adb83d3",
"archive_sha1": "a2f7d13d87657df599aeeabdb70194d508cfa92f"
}
}
Loading
Loading