Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

new: usr: JUPY-567, SDK-394: Add SDK bindings for JupyterNotebookCommand #304

Merged
merged 30 commits into from
Mar 12, 2020
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions bin/qds.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@
"shellcmd": ShellCommand,
"dbexportcmd": DbExportCommand,
"dbimportcmd": DbImportCommand,
"prestocmd": PrestoCommand
"prestocmd": PrestoCommand,
"jupyternotebookcmd": JupyterNotebookCommand
}

SensorClasses = {
Expand All @@ -46,7 +47,7 @@
usage_str = (
"Usage: qds.py [options] <subcommand>\n"
"\nCommand subcommands:\n"
" <hivecmd|hadoopcmd|prestocmd|pigcmd|shellcmd|dbexportcmd|dbimportcmd|dbtapquerycmd|sparkcmd> <action>\n"
" <hivecmd|hadoopcmd|prestocmd|pigcmd|shellcmd|dbexportcmd|dbimportcmd|dbtapquerycmd|sparkcmd|jupyternotebookcmd> <action>\n"
" submit [cmd-specific-args .. ] : submit cmd & print id\n"
" run [cmd-specific-args .. ] : submit cmd & wait. print results\n"
" check <id> <include-query-properties> : id -> print the cmd object for this id\n"
Expand Down
43 changes: 43 additions & 0 deletions qds_sdk/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -1347,6 +1347,49 @@ def parse(cls, args):
v["command_type"] = "DbTapQueryCommand"
return v

class JupyterNotebookCommand(Command):
usage = "jupyternotebookcmd <submit|run> [options]"

optparser = GentleOptionParser(usage=usage)
optparser.add_option("--path", dest="path", help="Path including name of the Jupyter notebook to be run with extension.")
chattarajoy marked this conversation as resolved.
Show resolved Hide resolved
optparser.add_option("--cluster-label", dest="label", help="Label of the cluster on which the this command should be run. If this parameter is not specified then label = 'default' is used.")
optparser.add_option("--arguments", dest="arguments", help="Valid JSON to be sent to the notebook. Specify the parameters in notebooks and pass the parameter value using the JSON format. key is the parameter's name and value is the parameter's value. Supported types in parameters are string, integer, float and boolean.")
optparser.add_option("--print-logs", action="store_true", dest="print_logs", default=False, help="Fetch logs and print them to stderr.")
optparser.add_option("--print-logs-live", action="store_true", dest="print_logs_live", default=False, help="Fetch logs and print them to stderr while command is running.")

@classmethod
def parse(cls, args):
"""
Parse command line arguments to construct a dictionary of command
parameters that can be used to create a command

Args:
`args`: sequence of arguments

Returns:
Dictionary that can be used in create method

Raises:
ParseError: when the arguments are not correct
"""
try:
options, args = cls.optparser.parse_args(args)
if options.path is None:
raise ParseError("Notebook Path must be specified", cls.optparser.format_help())
chattarajoy marked this conversation as resolved.
Show resolved Hide resolved
if options.arguments is not None:
try:
json.loads(options.arguments)
except ValueError:
raise ParseError("Given Arguments is not valid JSON", cls.optparser.format_help())
except OptionParsingError as e:
raise ParseError(e.msg, cls.optparser.format_help())
except OptionParsingExit as e:
return None

params = vars(options)
params["command_type"] = "JupyterNotebookCommand"
return params

class SignalHandler:
"""
Catch terminate signals to allow graceful termination of run()
Expand Down
2 changes: 1 addition & 1 deletion qds_sdk/scheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ def filter_fields(schedule, fields):
def create(args):
with open(args.data) as f:
spec = json.load(f)
schedule = Scheduler(spec)
schedule = Scheduler.create(**spec)
tgvr marked this conversation as resolved.
Show resolved Hide resolved
return json.dumps(schedule.attributes, sort_keys=True, indent=4)

@staticmethod
Expand Down
41 changes: 41 additions & 0 deletions tests/test_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,13 @@ def test_dbtapquerycmd(self):
qds.main()
Connection._api_call.assert_called_with("GET", "commands/123", params={'include_query_properties': 'false'})

def test_jupyternotebookcmd(self):
sys.argv = ['qds.py', 'jupyternotebookcmd', 'check', '123']
print_command()
Connection._api_call = Mock(return_value={})
qds.main()
Connection._api_call.assert_called_with("GET", "commands/123", params={'include_query_properties': 'false'})

def test_includequeryproperty(self):
sys.argv = ['qds.py', 'hivecmd', 'check', '123', 'true']
print_command()
Expand Down Expand Up @@ -224,6 +231,14 @@ def test_dbtapquerycmd(self):
Connection._api_call.assert_called_with("PUT", "commands/123",
{'status': 'kill'})

def test_jupyternotebookcmd(self):
sys.argv = ['qds.py', 'jupyternotebookcmd', 'cancel', '123']
print_command()
Connection._api_call = Mock(return_value={'kill_succeeded': True})
qds.main()
Connection._api_call.assert_called_with("PUT", "commands/123",
{'status': 'kill'})


class TestCommandGetJobs(QdsCliTestCase):

Expand Down Expand Up @@ -2029,6 +2044,32 @@ def test_submit_with_valid_local_script_location(self):
'command_type': 'DbTapQueryCommand',
'can_notify': False})

class TestJupyterNotebookCommand(QdsCliTestCase):

def test_submit_none(self):
sys.argv = ['qds.py', 'jupyternotebookcmd', 'submit']
print_command()
with self.assertRaises(qds_sdk.exception.ParseError):
qds.main()

def test_submit_no_path(self):
sys.argv = ['qds.py', 'jupyternotebookcmd', 'submit', '--cluster-label', 'demo-cluster']
print_command()
with self.assertRaises(qds_sdk.exception.ParseError):
qds.main()

def test_submit_all(self):
sys.argv = ['qds.py', 'jupyternotebookcmd', 'submit', '--path', 'folder/file',
'--cluster-label', 'demo-cluster', '--arguments', '{"key1": "value1", "key2": "value2"}']
print_command()
Connection._api_call = Mock(return_value={'id': 1234})
qds.main()
Connection._api_call.assert_called_with('POST', 'commands',
{'path': 'folder/file',
'label': 'demo-cluster',
'arguments': '{"key1": "value1", "key2": "value2"}',
'command_type': 'JupyterNotebookCommand'})

class TestGetResultsCommand(QdsCliTestCase):

def test_result_with_enable_header_true(self):
Expand Down