Skip to content

Commit 8601629

Browse files
authored
Added support for interaction with Posit Connect deployments in SPCS (#660)
1 parent 59bb89d commit 8601629

14 files changed

+987
-110
lines changed

.github/workflows/main.yml

+1-2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ permissions:
1717
jobs:
1818
test:
1919
strategy:
20+
fail-fast: false
2021
matrix:
2122
os: [ubuntu-latest]
2223
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']
@@ -254,5 +255,3 @@ jobs:
254255
name: cypress-screenshots_${{ matrix.PY_VERSION }}_native
255256
path: test/connect-rsconnect-python/cypress/screenshots
256257
if-no-files-found: ignore
257-
258-

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
88

99
### Added
1010

11+
- Added support for interaction with Posit Connect deployments
12+
hosted in Snowpark Container Services.
1113
- `rsconnect` now detects Python interpreter version requirements from
1214
`.python-version`, `pyproject.toml` and `setup.cfg`
1315
- `--python` and `--override-python-version` options are now deprecated

pyproject.toml

+1
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ test = [
3838
"twine",
3939
"types-Flask",
4040
]
41+
snowflake = ["snowflake-cli"]
4142

4243
[project.urls]
4344
Repository = "http://github.com/posit-dev/rsconnect-python"

rsconnect/actions.py

+8
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,14 @@ def test_rstudio_server(server: api.PositServer):
172172
raise RSConnectException("Failed to verify with {} ({}).".format(server.remote_name, exc))
173173

174174

175+
def test_spcs_server(server: api.SPCSConnectServer):
176+
with api.RSConnectClient(server) as client:
177+
try:
178+
client.me()
179+
except RSConnectException as exc:
180+
raise RSConnectException("Failed to verify with {} ({}).".format(server.remote_name, exc))
181+
182+
175183
def test_api_key(connect_server: api.RSConnectServer) -> str:
176184
"""
177185
Test that an API Key may be used to authenticate with the given Posit Connect server.

rsconnect/actions_content.py

+18-14
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@
99
import traceback
1010
from concurrent.futures import ThreadPoolExecutor, as_completed
1111
from datetime import datetime, timedelta
12-
from typing import Iterator, Literal, Optional, Sequence, cast
12+
from typing import Iterator, Literal, Optional, Sequence, cast, Union
1313

1414
import semver
1515

16-
from .api import RSConnectClient, RSConnectServer, emit_task_log
16+
from .api import RSConnectServer, SPCSConnectServer, RSConnectClient, emit_task_log
1717
from .exception import RSConnectException
1818
from .log import logger
1919
from .metadata import ContentBuildStore, ContentItemWithBuildState
@@ -33,7 +33,7 @@ def content_build_store() -> ContentBuildStore:
3333
return _content_build_store
3434

3535

36-
def ensure_content_build_store(connect_server: RSConnectServer) -> ContentBuildStore:
36+
def ensure_content_build_store(connect_server: Union[RSConnectServer, SPCSConnectServer]) -> ContentBuildStore:
3737
global _content_build_store
3838
if not _content_build_store:
3939
logger.info("Initializing ContentBuildStore for %s" % connect_server.url)
@@ -42,7 +42,7 @@ def ensure_content_build_store(connect_server: RSConnectServer) -> ContentBuildS
4242

4343

4444
def build_add_content(
45-
connect_server: RSConnectServer,
45+
connect_server: Union[RSConnectServer, SPCSConnectServer],
4646
content_guids_with_bundle: Sequence[ContentGuidWithBundle],
4747
):
4848
"""
@@ -85,7 +85,7 @@ def _validate_build_rm_args(guid: Optional[str], all: bool, purge: bool):
8585

8686

8787
def build_remove_content(
88-
connect_server: RSConnectServer,
88+
connect_server: Union[RSConnectServer, SPCSConnectServer],
8989
guid: Optional[str],
9090
all: bool,
9191
purge: bool,
@@ -109,20 +109,20 @@ def build_remove_content(
109109
return guids
110110

111111

112-
def build_list_content(connect_server: RSConnectServer, guid: str, status: Optional[str]):
112+
def build_list_content(connect_server: Union[RSConnectServer, SPCSConnectServer], guid: str, status: Optional[str]):
113113
build_store = ensure_content_build_store(connect_server)
114114
if guid:
115115
return [build_store.get_content_item(g) for g in guid]
116116
else:
117117
return build_store.get_content_items(status=status)
118118

119119

120-
def build_history(connect_server: RSConnectServer, guid: str):
120+
def build_history(connect_server: Union[RSConnectServer, SPCSConnectServer], guid: str):
121121
return ensure_content_build_store(connect_server).get_build_history(guid)
122122

123123

124124
def build_start(
125-
connect_server: RSConnectServer,
125+
connect_server: Union[RSConnectServer, SPCSConnectServer],
126126
parallelism: int,
127127
aborted: bool = False,
128128
error: bool = False,
@@ -251,7 +251,9 @@ def build_start(
251251
build_monitor.shutdown()
252252

253253

254-
def _monitor_build(connect_server: RSConnectServer, content_items: list[ContentItemWithBuildState]):
254+
def _monitor_build(
255+
connect_server: Union[RSConnectServer, SPCSConnectServer], content_items: list[ContentItemWithBuildState]
256+
):
255257
"""
256258
:return bool: True if the build completed without errors, False otherwise
257259
"""
@@ -296,7 +298,9 @@ def _monitor_build(connect_server: RSConnectServer, content_items: list[ContentI
296298
return True
297299

298300

299-
def _build_content_item(connect_server: RSConnectServer, content: ContentItemWithBuildState, poll_wait: int):
301+
def _build_content_item(
302+
connect_server: Union[RSConnectServer, SPCSConnectServer], content: ContentItemWithBuildState, poll_wait: int
303+
):
300304
build_store = ensure_content_build_store(connect_server)
301305
with RSConnectClient(connect_server) as client:
302306
# Pending futures will still try to execute when ThreadPoolExecutor.shutdown() is called
@@ -351,7 +355,7 @@ def write_log(line: str):
351355

352356

353357
def emit_build_log(
354-
connect_server: RSConnectServer,
358+
connect_server: Union[RSConnectServer, SPCSConnectServer],
355359
guid: str,
356360
format: str,
357361
task_id: Optional[str] = None,
@@ -369,7 +373,7 @@ def emit_build_log(
369373
raise RSConnectException("Log file not found for content: %s" % guid)
370374

371375

372-
def download_bundle(connect_server: RSConnectServer, guid_with_bundle: ContentGuidWithBundle):
376+
def download_bundle(connect_server: Union[RSConnectServer, SPCSConnectServer], guid_with_bundle: ContentGuidWithBundle):
373377
"""
374378
:param guid_with_bundle: models.ContentGuidWithBundle
375379
"""
@@ -387,7 +391,7 @@ def download_bundle(connect_server: RSConnectServer, guid_with_bundle: ContentGu
387391
return client.download_bundle(guid_with_bundle.guid, guid_with_bundle.bundle_id)
388392

389393

390-
def get_content(connect_server: RSConnectServer, guid: str | list[str]):
394+
def get_content(connect_server: Union[RSConnectServer, SPCSConnectServer], guid: str | list[str]):
391395
"""
392396
:param guid: a single guid as a string or list of guids.
393397
:return: a list of content items.
@@ -401,7 +405,7 @@ def get_content(connect_server: RSConnectServer, guid: str | list[str]):
401405

402406

403407
def search_content(
404-
connect_server: RSConnectServer,
408+
connect_server: Union[RSConnectServer, SPCSConnectServer],
405409
published: bool,
406410
unpublished: bool,
407411
content_type: Sequence[str],

0 commit comments

Comments
 (0)