From 7a7b3093824841a5889290e0cb57bd3352eb8d04 Mon Sep 17 00:00:00 2001 From: Winston Chang Date: Thu, 11 Apr 2024 23:25:15 -0500 Subject: [PATCH 1/2] Fix usage of AppModes.get_by_ordinal --- rsconnect/api.py | 2 +- rsconnect/models.py | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/rsconnect/api.py b/rsconnect/api.py index 495780e9..05801195 100644 --- a/rsconnect/api.py +++ b/rsconnect/api.py @@ -1053,7 +1053,7 @@ def validate_app_mode(self, app_mode: AppMode): # TODO: verify that this is correct. The previous code seemed # incorrect. It passed an arg to app.get(), which would have # been ignored. - existing_app_mode = AppModes.get_by_ordinal(app.app_mode, True) + existing_app_mode = AppModes.get_by_ordinal(app["app_mode"], True) except RSConnectException as e: raise RSConnectException( f"{e} Try setting the --new flag to overwrite the previous deployment." diff --git a/rsconnect/models.py b/rsconnect/models.py index 1e0a463a..b3a4f2b1 100644 --- a/rsconnect/models.py +++ b/rsconnect/models.py @@ -27,7 +27,7 @@ _content_guid_pattern = r"([^,]*),?(.*)" -class BuildStatus(object): +class BuildStatus: NEEDS_BUILD = "NEEDS_BUILD" # marked for build RUNNING = "RUNNING" # running now ABORTED = "ABORTED" # cancelled while running @@ -37,7 +37,7 @@ class BuildStatus(object): _all = [NEEDS_BUILD, RUNNING, ABORTED, COMPLETE, ERROR] -class AppMode(object): +class AppMode: """ Data class defining an "app mode" as understood by Posit Connect @@ -51,14 +51,14 @@ def __init__( ext: Optional[str] = None, ): self._ordinal = ordinal - self._name = name + self._name: AppModes.Modes = name self._text = text self._ext = ext def ordinal(self): return self._ordinal - def name(self): + def name(self) -> AppModes.Modes: return self._name def desc(self): @@ -74,7 +74,7 @@ def __repr__(self): return self.desc() -class AppModes(object): +class AppModes: """ Enumeration-like collection of known `AppMode`s with lookup functions @@ -151,7 +151,7 @@ class AppModes(object): } @classmethod - def get_by_ordinal(cls, ordinal: int, return_unknown: bool = False): + def get_by_ordinal(cls, ordinal: int, return_unknown: bool = False) -> AppMode: """Get an AppMode by its associated ordinal (integer)""" return cls._find_by( lambda mode: mode.ordinal() == ordinal, @@ -160,12 +160,12 @@ def get_by_ordinal(cls, ordinal: int, return_unknown: bool = False): ) @classmethod - def get_by_name(cls, name: str, return_unknown: bool = False): + def get_by_name(cls, name: str, return_unknown: bool = False) -> AppMode: """Get an AppMode by name""" return cls._find_by(lambda mode: mode.name() == name, "named %s" % name, return_unknown) @classmethod - def get_by_extension(cls, extension: Optional[str], return_unknown: bool = False): + def get_by_extension(cls, extension: Optional[str], return_unknown: bool = False) -> AppMode: """Get an app mode by its associated extension""" # We can't allow a lookup by None since some modes have that for an extension. if extension is None: @@ -180,11 +180,11 @@ def get_by_extension(cls, extension: Optional[str], return_unknown: bool = False ) @classmethod - def get_by_cloud_name(cls, name: str): + def get_by_cloud_name(cls, name: str) -> AppMode: return cls._cloud_to_connect_modes.get(name, cls.UNKNOWN) @classmethod - def _find_by(cls, predicate: Callable[[AppMode], bool], message: str, return_unknown: bool): + def _find_by(cls, predicate: Callable[[AppMode], bool], message: str, return_unknown: bool) -> AppMode: for mode in cls._modes: if predicate(mode): return mode @@ -373,7 +373,7 @@ class ContentItemV0(TypedDict): name: str title: str | None bundle_id: int | None - app_mode: AppModes.Modes + app_mode: int content_category: str has_parameters: bool created_time: str From cd39c7470952a6e4e7bbf072eb13b98f3574865e Mon Sep 17 00:00:00 2001 From: Winston Chang Date: Thu, 11 Apr 2024 23:25:39 -0500 Subject: [PATCH 2/2] Add and correct fields to ContentItemV0 --- rsconnect/models.py | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/rsconnect/models.py b/rsconnect/models.py index b3a4f2b1..358b8cbe 100644 --- a/rsconnect/models.py +++ b/rsconnect/models.py @@ -369,7 +369,7 @@ class ContentItemV0(TypedDict): amd_gpu_limit: int | None nvidia_gpu_limit: int | None url: str - vanity_url: str + vanity_url: bool name: str title: str | None bundle_id: int | None @@ -393,10 +393,20 @@ class ContentItemV0(TypedDict): run_as: str | None run_as_current_user: bool description: str - # Note: the next one is listed as "environment_json" in the AppRecord type, but - # in practice it comes in as "EnvironmentJson" from the API, so it's commented out - # here. - # environment_json: object + EnvironmentJson: str | None + app_role: AppRole + owner_first_name: str + owner_last_name: str + owner_username: str + owner_guid: str + owner_email: str + owner_locked: bool + is_scheduled: bool + # Not sure how the following 4 fields are structured, so just use object for now. + git: object | None + users: object | None + groups: object | None + vanities: object | None # Also known as V1 ContentOutputDTO in Connect (note: this is not V1 experimental).