Skip to content

Commit

Permalink
Snow 1272319 alias snowcli core object commands (#1067)
Browse files Browse the repository at this point in the history
* move object stage command into separate plugin

* stage commands

* git commands

* streamlit commands

* snowpark commands

* update snapshots

* stage commands: remove printing default for required arguments

* update release notes

* fix ruff

* refactor

* change object commands to aliases in integration tests

* fix help messages

* Adjust scope option help message
  • Loading branch information
sfc-gh-pczajka authored May 16, 2024
1 parent 7d34b3f commit 4dcf092
Show file tree
Hide file tree
Showing 20 changed files with 1,310 additions and 130 deletions.
7 changes: 7 additions & 0 deletions RELEASE-NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@

## New additions
* Add external access integration to snow object commands
* Add aliases for `snow object list/describe/drop` commands under:
* `snow stage` for stages
* `snow git` for git repository stages
* `snow streamlit` for streamlit apps
* `snow snowpark` for procedures and functions

## Fixes and improvements

## Fixes and improvements
* Improved support for quoted identifiers.
Expand Down
8 changes: 6 additions & 2 deletions src/snowflake/cli/api/commands/flags.py
Original file line number Diff line number Diff line change
Expand Up @@ -469,13 +469,17 @@ def experimental_option(

def identifier_argument(sf_object: str, example: str) -> typer.Argument:
return typer.Argument(
..., help=f"Identifier of the {sf_object}. For example: {example}"
...,
help=f"Identifier of the {sf_object}. For example: {example}",
show_default=False,
)


def execution_identifier_argument(sf_object: str, example: str) -> typer.Argument:
return typer.Argument(
..., help=f"Execution identifier of the {sf_object}. For example: {example}"
...,
help=f"Execution identifier of the {sf_object}. For example: {example}",
show_default=False,
)


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
from snowflake.cli.plugins.nativeapp import plugin_spec as nativeapp_plugin_spec
from snowflake.cli.plugins.notebook import plugin_spec as notebook_plugin_spec
from snowflake.cli.plugins.object import plugin_spec as object_plugin_spec

# TODO 3.0: remove this import
from snowflake.cli.plugins.object_stage_deprecated import (
plugin_spec as object_stage_deprecated_plugin_spec,
)
from snowflake.cli.plugins.snowpark import plugin_spec as snowpark_plugin_spec
from snowflake.cli.plugins.spcs import plugin_spec as spcs_plugin_spec
from snowflake.cli.plugins.sql import plugin_spec as sql_plugin_spec
Expand All @@ -23,6 +28,7 @@ def get_builtin_plugin_name_to_plugin_spec():
"streamlit": streamlit_plugin_spec,
"git": git_plugin_spec,
"notebook": notebook_plugin_spec,
"object-stage-deprecated": object_stage_deprecated_plugin_spec,
}

return plugin_specs
13 changes: 13 additions & 0 deletions src/snowflake/cli/plugins/git/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
from snowflake.cli.api.output.types import CollectionResult, CommandResult, QueryResult
from snowflake.cli.api.utils.path_utils import is_stage_path
from snowflake.cli.plugins.git.manager import GitManager
from snowflake.cli.plugins.object.command_aliases import (
add_object_command_aliases,
scope_option,
)
from snowflake.cli.plugins.object.manager import ObjectManager
from snowflake.cli.plugins.stage.commands import get
from snowflake.cli.plugins.stage.manager import OnErrorType
Expand Down Expand Up @@ -52,6 +56,15 @@ def _repo_path_argument_callback(path):
),
callback=_repo_path_argument_callback,
)
add_object_command_aliases(
app=app,
object_type=ObjectType.GIT_REPOSITORY,
name_argument=RepoNameArgument,
like_option=like_option(
help_example='`list --like "my%"` lists all git repositories with name that begin with “my”',
),
scope_option=scope_option(help_example="`list --in database my_db`"),
)


def _assure_repository_does_not_exist(om: ObjectManager, repository_name: str) -> None:
Expand Down
51 changes: 51 additions & 0 deletions src/snowflake/cli/plugins/object/command_aliases.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
from __future__ import annotations

from typing import Tuple

import typer
from snowflake.cli.api.commands.snow_typer import SnowTyper
from snowflake.cli.api.constants import ObjectType
from snowflake.cli.plugins.object.commands import (
describe,
drop,
list_,
scope_option, # noqa: F401
)


def add_object_command_aliases(
app: SnowTyper,
object_type: ObjectType,
name_argument: typer.Argument,
like_option: typer.Option,
scope_option: typer.Option,
):
@app.command("list", requires_connection=True)
def list_cmd(
like: str = like_option,
scope: Tuple[str, str] = scope_option,
**options,
):
list_(object_type=object_type.value.cli_name, like=like, scope=scope, **options)

list_cmd.__doc__ = f"Lists all available {object_type.value.sf_plural_name}."

@app.command("drop", requires_connection=True)
def drop_cmd(name: str = name_argument, **options):
drop(
object_type=object_type.value.cli_name,
object_name=name,
**options,
)

drop_cmd.__doc__ = f"Drops {object_type.value.sf_name} with given name."

@app.command("describe", requires_connection=True)
def describe_cmd(name: str = name_argument, **options):
describe(
object_type=object_type.value.cli_name,
object_name=name,
**options,
)

describe_cmd.__doc__ = f"Provides description of {object_type.value.sf_name}."
16 changes: 10 additions & 6 deletions src/snowflake/cli/plugins/object/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,11 @@
from snowflake.cli.api.output.types import QueryResult
from snowflake.cli.api.project.util import is_valid_identifier
from snowflake.cli.plugins.object.manager import ObjectManager
from snowflake.cli.plugins.object.stage_deprecated.commands import app as stage_app

app = SnowTyper(
name="object",
help="Manages Snowflake objects like warehouses and stages",
)
app.add_typer(stage_app)


NameArgument = typer.Argument(help="Name of the object")
Expand All @@ -40,10 +38,16 @@ def _scope_validate(object_type: str, scope: Tuple[str, str]):
raise ClickException("compute-pool scope is only supported for listing service")


ScopeOption = typer.Option(
(None, None),
"--in",
help="Specifies the scope of this command using '--in <scope> <name>' (e.g. list tables --in database my_db). Some object types have specialized scopes (e.g. list service --in compute-pool my_pool)",
def scope_option(help_example: str):
return typer.Option(
(None, None),
"--in",
help=f"Specifies the scope of this command using '--in <scope> <name>', for example {help_example}.",
)


ScopeOption = scope_option(
help_example="`list table --in database my_db`. Some object types have specialized scopes (e.g. list service --in compute-pool my_pool)"
)

SUPPORTED_TYPES_MSG = "\n\nSupported types: " + ", ".join(SUPPORTED_OBJECTS)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# TODO 3.0: remove this file
20 changes: 20 additions & 0 deletions src/snowflake/cli/plugins/object_stage_deprecated/plugin_spec.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# TODO 3.0: remove this file

from snowflake.cli.api.plugins.command import (
CommandPath,
CommandSpec,
CommandType,
plugin_hook_impl,
)
from snowflake.cli.plugins.object_stage_deprecated.commands import (
app as stage_deprecated_app,
)


@plugin_hook_impl
def command_spec():
return CommandSpec(
parent_command_path=CommandPath(["object"]),
command_type=CommandType.COMMAND_GROUP,
typer_instance=stage_deprecated_app,
)
58 changes: 56 additions & 2 deletions src/snowflake/cli/plugins/snowpark/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import logging
from enum import Enum
from typing import Dict, List, Optional, Set
from typing import Dict, List, Optional, Set, Tuple

import typer
from click import ClickException
Expand All @@ -14,6 +14,8 @@
ReplaceOption,
deprecated_flag_callback_enum,
execution_identifier_argument,
identifier_argument,
like_option,
)
from snowflake.cli.api.commands.project_initialisation import add_init_command
from snowflake.cli.api.commands.snow_typer import SnowTyper
Expand All @@ -37,6 +39,18 @@
ProcedureSchema,
)
from snowflake.cli.api.secure_path import SecurePath
from snowflake.cli.plugins.object.commands import (
describe as object_describe,
)
from snowflake.cli.plugins.object.commands import (
drop as object_drop,
)
from snowflake.cli.plugins.object.commands import (
list_ as object_list,
)
from snowflake.cli.plugins.object.commands import (
scope_option,
)
from snowflake.cli.plugins.object.manager import ObjectManager
from snowflake.cli.plugins.snowpark import package_utils
from snowflake.cli.plugins.snowpark.common import (
Expand Down Expand Up @@ -73,8 +87,15 @@
ObjectTypeArgument = typer.Argument(
help="Type of Snowpark object",
case_sensitive=False,
show_default=False,
)
IdentifierArgument = identifier_argument(
"function/procedure",
example="hello(int, string)",
)
LikeOption = like_option(
help_example='`list function --like "my%"` lists all functions that begin with “my”',
)

add_init_command(app, project_type="Snowpark", template="default_snowpark")


Expand Down Expand Up @@ -465,3 +486,36 @@ def execute(
"execute", object_type=object_type, execution_identifier=execution_identifier
)
return SingleQueryResult(cursor)


@app.command("list", requires_connection=True)
def list_(
object_type: _SnowparkObject = ObjectTypeArgument,
like: str = LikeOption,
scope: Tuple[str, str] = scope_option(
help_example="`list function --in database my_db`"
),
**options,
):
"""Lists all available procedures or functions."""
object_list(object_type=object_type.value, like=like, scope=scope, **options)


@app.command("drop", requires_connection=True)
def drop(
object_type: _SnowparkObject = ObjectTypeArgument,
identifier: str = IdentifierArgument,
**options,
):
"""Drop procedure or function."""
object_drop(object_type=object_type.value, object_name=identifier, **options)


@app.command("describe", requires_connection=True)
def describe(
object_type: _SnowparkObject = ObjectTypeArgument,
identifier: str = IdentifierArgument,
**options,
):
"""Provides description of a procedure or function."""
object_describe(object_type=object_type.value, object_name=identifier, **options)
32 changes: 29 additions & 3 deletions src/snowflake/cli/plugins/stage/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@
OnErrorOption,
PatternOption,
VariablesOption,
like_option,
)
from snowflake.cli.api.commands.snow_typer import SnowTyper
from snowflake.cli.api.console import cli_console
from snowflake.cli.api.constants import ObjectType
from snowflake.cli.api.output.types import (
CollectionResult,
CommandResult,
Expand All @@ -22,6 +24,10 @@
SingleQueryResult,
)
from snowflake.cli.api.utils.path_utils import is_stage_path
from snowflake.cli.plugins.object.command_aliases import (
add_object_command_aliases,
scope_option,
)
from snowflake.cli.plugins.stage.diff import DiffResult, compute_stage_diff
from snowflake.cli.plugins.stage.manager import OnErrorType, StageManager

Expand All @@ -32,6 +38,16 @@

StageNameArgument = typer.Argument(..., help="Name of the stage.", show_default=False)

add_object_command_aliases(
app=app,
object_type=ObjectType.STAGE,
name_argument=StageNameArgument,
like_option=like_option(
help_example='`list --like "my%"` lists all stages that begin with “my”',
),
scope_option=scope_option(help_example="`list --in database my_db`"),
)


@app.command("list-files", requires_connection=True)
def stage_list_files(
Expand Down Expand Up @@ -112,7 +128,11 @@ def stage_create(stage_name: str = StageNameArgument, **options) -> CommandResul
@app.command("remove", requires_connection=True)
def stage_remove(
stage_name: str = StageNameArgument,
file_name: str = typer.Argument(..., help="Name of the file to remove."),
file_name: str = typer.Argument(
...,
help="Name of the file to remove.",
show_default=False,
),
**options,
) -> CommandResult:
"""
Expand All @@ -125,8 +145,14 @@ def stage_remove(

@app.command("diff", hidden=True, requires_connection=True)
def stage_diff(
stage_name: str = typer.Argument(help="Fully qualified name of a stage"),
folder_name: str = typer.Argument(help="Path to local folder"),
stage_name: str = typer.Argument(
help="Fully qualified name of a stage",
show_default=False,
),
folder_name: str = typer.Argument(
help="Path to local folder",
show_default=False,
),
**options,
) -> ObjectResult:
"""
Expand Down
Loading

0 comments on commit 4dcf092

Please sign in to comment.