Skip to content

Commit 1892c80

Browse files
authored
Merge pull request #558 from rstudio/shiny-express-manifest
Add support for Shiny Express apps when writing manifest files
2 parents a5a1668 + 6267897 commit 1892c80

File tree

6 files changed

+345
-311
lines changed

6 files changed

+345
-311
lines changed

pyproject.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ requires-python = ">=3.8"
99

1010
dependencies = [
1111
"six>=1.14.0",
12-
"click>=7.0.0",
1312
"pip>=10.0.0",
1413
"semver>=2.0.0,<3.0.0",
1514
"pyjwt>=2.4.0",

rsconnect/actions.py

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""
22
Public API for managing settings and deploying content.
33
"""
4+
from __future__ import annotations
45

56
import contextlib
67
import json
@@ -11,7 +12,8 @@
1112
import subprocess
1213
import sys
1314
import traceback
14-
from typing import IO
15+
import typing
16+
from typing import IO, Optional
1517
from warnings import warn
1618
from os.path import abspath, basename, dirname, exists, isdir, join, relpath, splitext
1719
from .exception import RSConnectException
@@ -46,10 +48,6 @@
4648
import click
4749
from six.moves.urllib_parse import urlparse
4850

49-
try:
50-
import typing
51-
except ImportError:
52-
typing = None
5351

5452
line_width = 45
5553
_module_pattern = re.compile(r"^[A-Za-z0-9_]+:[A-Za-z0-9_]+$")
@@ -153,7 +151,7 @@ def inspect_environment(
153151
return MakeEnvironment(**json.loads(environment_json)) # type: ignore
154152

155153

156-
def _verify_server(connect_server):
154+
def _verify_server(connect_server: api.RSConnectServer):
157155
"""
158156
Test whether the server identified by the given full URL can be reached and is
159157
running Connect.
@@ -188,7 +186,7 @@ def _to_server_check_list(url):
188186
return [item % url for item in items]
189187

190188

191-
def test_server(connect_server):
189+
def test_server(connect_server: api.RSConnectServer) -> tuple[api.RSConnectServer, object]:
192190
"""
193191
Test whether the given server can be reached and is running Connect. The server
194192
may be provided with or without a scheme. If a scheme is omitted, the server will
@@ -228,7 +226,7 @@ def test_rstudio_server(server: api.PositServer):
228226
raise RSConnectException("Failed to verify with {} ({}).".format(server.remote_name, exc))
229227

230228

231-
def test_api_key(connect_server):
229+
def test_api_key(connect_server: api.RSConnectServer) -> str:
232230
"""
233231
Test that an API Key may be used to authenticate with the given Posit Connect server.
234232
If the API key verifies, we return the username of the associated user.
@@ -424,7 +422,7 @@ def validate_entry_point(entry_point, directory):
424422
return entry_point
425423

426424

427-
def which_quarto(quarto=None):
425+
def which_quarto(quarto: Optional[str] = None) -> str:
428426
"""
429427
Identify a valid Quarto executable. When a Quarto location is not provided
430428
as input, an attempt is made to discover Quarto from the PATH and other

rsconnect/actions_content.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,16 @@
22
Public API for administering content.
33
"""
44

5+
from __future__ import annotations
6+
57
import json
68
import time
79
import traceback
810
from concurrent.futures import ThreadPoolExecutor, as_completed
911
from datetime import datetime, timedelta
1012
import semver
1113

12-
from .api import RSConnectClient, emit_task_log
14+
from .api import RSConnectClient, RSConnectServer, emit_task_log
1315
from .log import logger
1416
from .models import BuildStatus, ContentGuidWithBundle
1517
from .metadata import ContentBuildStore
@@ -18,7 +20,7 @@
1820
_content_build_store = None # type: ContentBuildStore
1921

2022

21-
def init_content_build_store(connect_server):
23+
def init_content_build_store(connect_server: RSConnectServer):
2224
global _content_build_store
2325
if not _content_build_store:
2426
logger.info("Initializing ContentBuildStore for %s" % connect_server.url)
@@ -64,7 +66,12 @@ def build_add_content(connect_server, content_guids_with_bundle):
6466
_content_build_store.set_content_item_build_status(content["guid"], BuildStatus.NEEDS_BUILD)
6567

6668

67-
def build_remove_content(connect_server, guid, all=False, purge=False):
69+
def build_remove_content(
70+
connect_server: RSConnectServer,
71+
guid: str,
72+
all: bool = False,
73+
purge: bool = False,
74+
) -> list[str]:
6875
"""
6976
:return: A list of guids of the content items that were removed
7077
"""
@@ -73,7 +80,7 @@ def build_remove_content(connect_server, guid, all=False, purge=False):
7380
raise RSConnectException(
7481
"There is a build running on this server, " + "please wait for it to finish before removing content."
7582
)
76-
guids = [guid]
83+
guids: list[str] = [guid]
7784
if all:
7885
guids = [c["guid"] for c in _content_build_store.get_content_items()]
7986
for guid in guids:

rsconnect/api.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1454,7 +1454,7 @@ def do_deploy(self, bundle_id, app_id):
14541454
raise e
14551455

14561456

1457-
def verify_server(connect_server):
1457+
def verify_server(connect_server: RSConnectServer):
14581458
"""
14591459
Verify that the given server information represents a Connect instance that is
14601460
reachable, active and appears to be actually running Posit Connect. If the
@@ -1473,7 +1473,7 @@ def verify_server(connect_server):
14731473
raise RSConnectException("There is an SSL/TLS configuration problem: %s" % ssl_error)
14741474

14751475

1476-
def verify_api_key(connect_server):
1476+
def verify_api_key(connect_server: RSConnectServer) -> str:
14771477
"""
14781478
Verify that an API Key may be used to authenticate with the given Posit Connect server.
14791479
If the API key verifies, we return the username of the associated user.

rsconnect/bundle.py

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
from mimetypes import guess_type
2121
from pathlib import Path
2222
from copy import deepcopy
23-
from typing import Optional, Any
23+
from typing import Optional, Any, Sequence
2424
import click
2525

2626
from os.path import basename, dirname, exists, isdir, join, relpath, splitext, isfile, abspath
@@ -844,12 +844,12 @@ def make_api_manifest(
844844
entry_point: str,
845845
app_mode: AppMode,
846846
environment: Environment,
847-
extra_files: list[str],
848-
excludes: list[str],
847+
extra_files: Sequence[str],
848+
excludes: Sequence[str],
849849
image: Optional[str] = None,
850850
env_management_py: Optional[bool] = None,
851851
env_management_r: Optional[bool] = None,
852-
) -> typing.Tuple[typing.Dict[str, typing.Any], typing.List[str]]:
852+
) -> tuple[dict[str, Any], list[str]]:
853853
"""
854854
Makes a manifest for an API.
855855
@@ -1237,8 +1237,8 @@ def make_api_bundle(
12371237

12381238
def _create_quarto_file_list(
12391239
directory: str,
1240-
extra_files: typing.List[str],
1241-
excludes: typing.List[str],
1240+
extra_files: Sequence[str],
1241+
excludes: Sequence[str],
12421242
) -> typing.List[str]:
12431243
"""
12441244
Builds a full list of files under the given directory that should be included
@@ -1269,8 +1269,8 @@ def make_quarto_manifest(
12691269
quarto_inspection: typing.Dict[str, typing.Any],
12701270
app_mode: AppMode,
12711271
environment: Environment,
1272-
extra_files: typing.List[str],
1273-
excludes: typing.List[str],
1272+
extra_files: Sequence[str],
1273+
excludes: Sequence[str],
12741274
image: str = None,
12751275
env_management_py: bool = None,
12761276
env_management_r: bool = None,
@@ -1406,7 +1406,7 @@ def validate_extra_files(directory: str, extra_files: typing.Sequence[str], use_
14061406
return result
14071407

14081408

1409-
def validate_manifest_file(file_or_directory):
1409+
def validate_manifest_file(file_or_directory: str) -> str:
14101410
"""
14111411
Validates that the name given represents either an existing manifest.json file or
14121412
a directory that contains one. If not, an exception is raised.
@@ -1674,12 +1674,12 @@ def write_notebook_manifest_json(
16741674
entry_point_file: str,
16751675
environment: Environment,
16761676
app_mode: AppMode,
1677-
extra_files: typing.List[str],
1678-
hide_all_input: bool,
1679-
hide_tagged_input: bool,
1680-
image: str = None,
1681-
env_management_py: bool = None,
1682-
env_management_r: bool = None,
1677+
extra_files: Sequence[str],
1678+
hide_all_input: Optional[bool],
1679+
hide_tagged_input: Optional[bool],
1680+
image: Optional[str] = None,
1681+
env_management_py: Optional[bool] = None,
1682+
env_management_r: Optional[bool] = None,
16831683
) -> bool:
16841684
"""
16851685
Creates and writes a manifest.json file for the given entry point file. If
@@ -1840,8 +1840,8 @@ def write_voila_manifest_json(
18401840
entrypoint: str,
18411841
environment: Environment,
18421842
app_mode: AppMode = AppModes.JUPYTER_VOILA,
1843-
extra_files: typing.List[str] = None,
1844-
excludes: typing.List[str] = None,
1843+
extra_files: Sequence[str] = None,
1844+
excludes: Sequence[str] = None,
18451845
force_generate: bool = True,
18461846
image: str = None,
18471847
env_management_py: bool = None,
@@ -1932,11 +1932,11 @@ def write_api_manifest_json(
19321932
entry_point: str,
19331933
environment: Environment,
19341934
app_mode: AppMode,
1935-
extra_files: typing.List[str],
1936-
excludes: typing.List[str],
1937-
image: str = None,
1938-
env_management_py: bool = None,
1939-
env_management_r: bool = None,
1935+
extra_files: Sequence[str],
1936+
excludes: Sequence[str],
1937+
image: Optional[str] = None,
1938+
env_management_py: Optional[bool] = None,
1939+
env_management_r: Optional[bool] = None,
19401940
) -> bool:
19411941
"""
19421942
Creates and writes a manifest.json file for the given entry point file. If
@@ -2015,8 +2015,8 @@ def write_quarto_manifest_json(
20152015
inspect: typing.Any,
20162016
app_mode: AppMode,
20172017
environment: Environment,
2018-
extra_files: typing.List[str],
2019-
excludes: typing.List[str],
2018+
extra_files: Sequence[str],
2019+
excludes: Sequence[str],
20202020
image: str = None,
20212021
env_management_py: bool = None,
20222022
env_management_r: bool = None,

0 commit comments

Comments
 (0)