Skip to content

Commit

Permalink
Merge pull request #499 from rstudio/tdstein/491
Browse files Browse the repository at this point in the history
Adds 'flask' sub-command
  • Loading branch information
tdstein authored Oct 23, 2023
2 parents 175a4c3 + 0d163a3 commit b6cbcbc
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 25 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## Unreleased

### Fixed
Expand All @@ -26,10 +27,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
recognized filename patterns, the file patterns `app-*.py`, `app_*.py`, `*-app.py`,
and `*_app.py` are now considered. However, if the directory contains more than
one file matching these new patterns, you must provide rsconnect-python with an
explicit `--entrypoint` argument.
explicit `--entrypoint` argument.\
- Added a new verbose logging level. Specifying `-v` on the command line uses this
new level. Currently this will cause filenames to be logged as they are added to
a bundle. To enable maximum verbosity (debug level), use `-vv`.
- Added the `deploy flask` command.
- Added the `write-manifest flask` command.

### Changed
- Removing experimental support for Conda. Connect does not support restoring Conda environments.
Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -270,8 +270,9 @@ rsconnect write-manifest notebook my-notebook.ipynb
You can deploy a variety of APIs and applications using sub-commands of the
`rsconnect deploy` command.

* `api`: WSGI-compliant APIs such as Flask and packages based on Flask
* `fastapi`: ASGI-compliant APIs (FastAPI, Quart, Sanic, and Falcon)
* `api`: WSGI-compliant APIs (e.g., `bottle`, `falcon`, `flask`, `flask-restx`, `flasgger`, `pycnic`).
* `flask`: Flask APIs (_Note: `flask` is an alias of `api`._).
* `fastapi`: ASGI-compliant APIs (e.g, `fastapi`, `quart`, `sanic`, `starlette`)
* `dash`: Python Dash apps
* `streamlit`: Streamlit apps
* `bokeh`: Bokeh server apps
Expand Down
53 changes: 31 additions & 22 deletions rsconnect/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import click
from os.path import abspath, dirname, exists, isdir, join
from functools import wraps
from typing import Optional

from rsconnect.certificates import read_certificate_file

Expand Down Expand Up @@ -65,6 +66,7 @@
from .log import logger, LogOutputFormat
from .metadata import ServerStore, AppStore
from .models import (
AppMode,
AppModes,
BuildStatus,
ContentGuidWithBundleParamType,
Expand Down Expand Up @@ -1254,18 +1256,22 @@ def deploy_html(
)


def generate_deploy_python(app_mode, alias, min_version):
def generate_deploy_python(app_mode: AppMode, alias: str, min_version: str, desc: Optional[str] = None):

if desc is None:
desc = app_mode.desc()

# noinspection SpellCheckingInspection
@deploy.command(
name=alias,
short_help="Deploy a {desc} to Posit Connect [v{version}+], Posit Cloud, or shinyapps.io.".format(
desc=app_mode.desc(),
desc=desc,
version=min_version,
),
help=(
"Deploy a {desc} module to Posit Connect, Posit Cloud, or shinyapps.io (if supported by the platform). "
'The "directory" argument must refer to an existing directory that contains the application code.'
).format(desc=app_mode.desc()),
).format(desc=desc),
no_args_is_help=True,
)
@server_args
Expand All @@ -1277,7 +1283,7 @@ def generate_deploy_python(app_mode, alias, min_version):
"-e",
help=(
"The module and executable object which serves as the entry point for the {desc} (defaults to app)"
).format(desc=app_mode.desc()),
).format(desc=desc),
)
@click.option(
"--exclude",
Expand Down Expand Up @@ -1372,14 +1378,13 @@ def deploy_app(
return deploy_app


deploy_api = generate_deploy_python(app_mode=AppModes.PYTHON_API, alias="api", min_version="1.8.2")
# TODO: set fastapi min_version correctly
# deploy_fastapi = generate_deploy_python(app_mode=AppModes.PYTHON_FASTAPI, alias="fastapi", min_version="2021.08.0")
deploy_fastapi = generate_deploy_python(app_mode=AppModes.PYTHON_FASTAPI, alias="fastapi", min_version="2021.08.0")
deploy_dash_app = generate_deploy_python(app_mode=AppModes.DASH_APP, alias="dash", min_version="1.8.2")
deploy_streamlit_app = generate_deploy_python(app_mode=AppModes.STREAMLIT_APP, alias="streamlit", min_version="1.8.4")
deploy_bokeh_app = generate_deploy_python(app_mode=AppModes.BOKEH_APP, alias="bokeh", min_version="1.8.4")
deploy_shiny = generate_deploy_python(app_mode=AppModes.PYTHON_SHINY, alias="shiny", min_version="2022.07.0")
generate_deploy_python(app_mode=AppModes.PYTHON_API, alias="api", min_version="1.8.2")
generate_deploy_python(app_mode=AppModes.PYTHON_API, alias="flask", min_version="1.8.2", desc="Flask API")
generate_deploy_python(app_mode=AppModes.PYTHON_FASTAPI, alias="fastapi", min_version="2021.08.0")
generate_deploy_python(app_mode=AppModes.DASH_APP, alias="dash", min_version="1.8.2")
generate_deploy_python(app_mode=AppModes.STREAMLIT_APP, alias="streamlit", min_version="1.8.4")
generate_deploy_python(app_mode=AppModes.BOKEH_APP, alias="bokeh", min_version="1.8.4")
generate_deploy_python(app_mode=AppModes.PYTHON_SHINY, alias="shiny", min_version="2022.07.0")


@deploy.command(
Expand Down Expand Up @@ -1711,24 +1716,27 @@ def write_manifest_quarto(
)


def generate_write_manifest_python(app_mode, alias):
def generate_write_manifest_python(app_mode, alias, desc: Optional[str] = None):
if desc is None:
desc = app_mode.desc()

# noinspection SpellCheckingInspection
@write_manifest.command(
name=alias,
short_help="Create a manifest.json file for a {desc}.".format(desc=app_mode.desc()),
short_help="Create a manifest.json file for a {desc}.".format(desc=desc),
help=(
"Create a manifest.json file for a {desc} for later deployment. This will create an "
'environment file ("requirements.txt") if one does not exist. All files '
"are created in the same directory as the API code."
).format(desc=app_mode.desc()),
).format(desc=desc),
)
@click.option("--overwrite", "-o", is_flag=True, help="Overwrite manifest.json, if it exists.")
@click.option(
"--entrypoint",
"-e",
help=(
"The module and executable object which serves as the entry point for the {desc} (defaults to app)"
).format(desc=app_mode.desc()),
).format(desc=desc),
)
@click.option(
"--exclude",
Expand Down Expand Up @@ -1793,12 +1801,13 @@ def manifest_writer(
return manifest_writer


write_manifest_api = generate_write_manifest_python(AppModes.PYTHON_API, alias="api")
write_manifest_fastapi = generate_write_manifest_python(AppModes.PYTHON_FASTAPI, alias="fastapi")
write_manifest_dash = generate_write_manifest_python(AppModes.DASH_APP, alias="dash")
write_manifest_streamlit = generate_write_manifest_python(AppModes.STREAMLIT_APP, alias="streamlit")
write_manifest_bokeh = generate_write_manifest_python(AppModes.BOKEH_APP, alias="bokeh")
write_manifest_shiny = generate_write_manifest_python(AppModes.PYTHON_SHINY, alias="shiny")
generate_write_manifest_python(AppModes.BOKEH_APP, alias="bokeh")
generate_write_manifest_python(AppModes.DASH_APP, alias="dash")
generate_write_manifest_python(AppModes.PYTHON_API, alias="api")
generate_write_manifest_python(AppModes.PYTHON_API, alias="flask", desc="Flask API")
generate_write_manifest_python(AppModes.PYTHON_FASTAPI, alias="fastapi")
generate_write_manifest_python(AppModes.PYTHON_SHINY, alias="shiny")
generate_write_manifest_python(AppModes.STREAMLIT_APP, alias="streamlit")


# noinspection SpellCheckingInspection
Expand Down

0 comments on commit b6cbcbc

Please sign in to comment.