Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
82d6786
Flag required params in workspace commands
Jul 19, 2022
7378c6d
Fix azdev style violations
Jul 29, 2022
8b6e153
Restore _params.py
Jul 29, 2022
e561aef
Apply configured_default to workspace_name_type
Aug 5, 2022
47f1cde
Delete required=False on workspace_name_type
Aug 5, 2022
ccc2515
Show more parameters as Required
Aug 6, 2022
4b5042b
Show job parameters as Required
Aug 9, 2022
10902c2
Show target parameters as Required
Aug 9, 2022
eb7b529
Fix output of az quantum target show
Aug 10, 2022
d168641
Delete commented-out lines
Aug 10, 2022
1d12c9a
Go back to using show_command for job and target
Aug 11, 2022
4882655
Add required parameters in help examples
Aug 11, 2022
a88c931
Delete help example and trailing whitespace
Aug 11, 2022
e36337d
Add test_job_errors
Aug 13, 2022
8c6d505
Add unit tests
Aug 16, 2022
7a35d0a
Delete unused imports and commented-out code
Aug 16, 2022
10f22cc
Delete more unused imports and commented-out code
Aug 16, 2022
a173e10
Empty commit to trigger CI/CD check pipeline (like /azp run)
Aug 24, 2022
e9787a4
Remove capsys from tests
Aug 25, 2022
705ce75
Ensure test failure if command with missing parameters doesn’t fail
Aug 25, 2022
dfcb55a
Add comment about TODO in utils.py
Aug 26, 2022
9a017cb
Revise the 'az quantum target show' error message
Sep 10, 2022
ed2c6fb
Restore version number to 0.16.0
Oct 4, 2022
d6d8c1d
Correct 'az quantum workspace delete' help example
Oct 4, 2022
2c722d9
Modify help example to pass CLI Linter check
Oct 10, 2022
240a5e8
Add note to help example for consistency with related example
Oct 10, 2022
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
18 changes: 6 additions & 12 deletions src/quantum/azext_quantum/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,15 +86,15 @@
- name: Submit the Q# program from the current folder.
text: |-
az quantum job submit -g MyResourceGroup -w MyWorkspace -l MyLocation \\
--job-name MyJob
-t MyTarget --job-name MyJob
- name: Submit the Q# program from the current folder with job parameters for a target.
text: |-
az quantum job submit -g MyResourceGroup -w MyWorkspace -l MyLocation \\
--job-name MyJob --job-params param1=value1 param2=value2
-t MyTarget --job-name MyJob --job-params param1=value1 param2=value2
- name: Submit the Q# program with program parameters (e.g. n-qubits = 2).
text: |-
az quantum job submit -g MyResourceGroup -w MyWorkspace -l MyLocation \\
--job-name MyJob -- --n-qubits=2
-t MyTarget --job-name MyJob -- --n-qubits=2
- name: Submit a Q# program from the current folder with a target-capability parameter.
text: |-
az quantum job submit -g MyResourceGroup -w MyWorkspace -l MyLocation -t MyTarget \\
Expand Down Expand Up @@ -190,7 +190,7 @@

helps['quantum target show'] = """
type: command
short-summary: Get the details of the given (or current) target to use when submitting jobs to Azure Quantum.
short-summary: Get the Target ID of the current default target to use when submitting jobs to Azure Quantum.
examples:
- name: Show the currently selected default target
text: |-
Expand Down Expand Up @@ -231,12 +231,9 @@
type: command
short-summary: Delete the given (or current) Azure Quantum workspace.
examples:
- name: Delete an Azure Quantum workspace by name and group.
- name: Delete an Azure Quantum workspace by resource group and workspace name. If a default workspace has been set, the -g and -w parameters are not required.
text: |-
az quantum workspace delete -g MyResourceGroup -w MyWorkspace
- name: Delete and clear the default Azure Quantum workspace (if one has been set).
text: |-
az quantum workspace delete
"""

helps['quantum workspace list'] = """
Expand All @@ -256,10 +253,7 @@
type: command
short-summary: List the quotas for the given (or current) Azure Quantum workspace.
examples:
- name: List the quota information of the default workspace if set.
text: |-
az quantum workspace quotas
- name: List the quota information of a specified Azure Quantum workspace.
- name: List the quota information of a specified Azure Quantum workspace. If a default workspace has been set, the -g, -w, and -l parameters are not required.
text: |-
az quantum workspace quotas -g MyResourceGroup -w MyWorkspace -l MyLocation
"""
Expand Down
8 changes: 6 additions & 2 deletions src/quantum/azext_quantum/_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ def get_action(self, values, option_string):


def load_arguments(self, _):
workspace_name_type = CLIArgumentType(options_list=['--workspace-name', '-w'], help='Name of the Quantum Workspace. You can configure the default workspace using `az quantum workspace set`.', id_part=None, required=False)
workspace_name_type = CLIArgumentType(options_list=['--workspace-name', '-w'], help='Name of the Quantum Workspace. You can configure the default workspace using `az quantum workspace set`.', configured_default='workspace', id_part=None)
storage_account_name_type = CLIArgumentType(options_list=['--storage-account', '-a'], help='Name of the storage account to be used by a quantum workspace.')
program_args_type = CLIArgumentType(nargs='*', help='List of arguments expected by the Q# operation specified as --name=value after `--`.')
target_id_type = CLIArgumentType(options_list=['--target-id', '-t'], help='Execution engine for quantum computing jobs. When a workspace is configured with a set of provider, they each enable one or more targets. You can configure the default target using `az quantum target set`.')
target_id_type = CLIArgumentType(options_list=['--target-id', '-t'], help='Execution engine for quantum computing jobs. When a workspace is configured with a set of providers, they each enable one or more targets. You can configure the default target using `az quantum target set`.', configured_default='target_id')
project_type = CLIArgumentType(help='The location of the Q# project to submit. Defaults to current folder.')
job_name_type = CLIArgumentType(help='A friendly name to give to this run of the program.')
job_id_type = CLIArgumentType(options_list=['--job-id', '-j'], help='Job unique identifier in GUID format.')
Expand Down Expand Up @@ -60,6 +60,10 @@ def load_arguments(self, _):
c.argument('workspace_name', workspace_name_type)
c.argument('target_id', target_id_type)

with self.argument_context('quantum target show') as c:
c.argument('workspace_name', workspace_name_type)
c.argument('target_id', target_id_type, required=False)

with self.argument_context('quantum job') as c:
c.argument('workspace_name', workspace_name_type)
c.argument('job_id', job_id_type)
Expand Down
3 changes: 2 additions & 1 deletion src/quantum/azext_quantum/_validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ def validate_target_info(cmd, namespace):
target = TargetInfo(cmd, target_id)

if not target.target_id:
raise ValueError("Missing target-id argument")
# raise ValueError("Missing target-id argument. Use `az quantum target set -t MyTarget` to set a default Target ID.")
raise ValueError("No default Target ID has been saved. Use `az quantum target set -t MyTarget` to set a default Target ID.")


def validate_workspace_and_target_info(cmd, namespace):
Expand Down
4 changes: 2 additions & 2 deletions src/quantum/azext_quantum/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,13 +132,13 @@ def load_command_table(self, _):

with self.command_group('quantum target', target_ops) as t:
t.command('list', 'list', validator=validate_workspace_info, table_transformer=transform_targets)
t.show_command('show', validator=validate_target_info)
t.show_command('show', 'target_show', validator=validate_target_info)
t.command('set', 'set', validator=validate_target_info)
t.command('clear', 'clear')

with self.command_group('quantum job', job_ops) as j:
j.command('list', 'list', validator=validate_workspace_info, table_transformer=transform_jobs)
j.show_command('show', validator=validate_workspace_info, table_transformer=transform_job)
j.show_command('show', 'job_show', validator=validate_workspace_info, table_transformer=transform_job)
j.command('submit', 'submit', validator=validate_workspace_and_target_info, table_transformer=transform_job)
j.command('wait', 'wait', validator=validate_workspace_info, table_transformer=transform_job)
j.command('output', 'output', validator=validate_workspace_info, table_transformer=transform_output)
Expand Down
24 changes: 17 additions & 7 deletions src/quantum/azext_quantum/operations/job.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
knack_logger = knack.log.get_logger(__name__)


def list(cmd, resource_group_name=None, workspace_name=None, location=None):
def list(cmd, resource_group_name, workspace_name, location):
"""
Get the list of jobs in a Quantum Workspace.
"""
Expand Down Expand Up @@ -168,7 +168,7 @@ def _has_completed(job):
return job.status in ("Succeeded", "Failed", "Cancelled")


def submit(cmd, program_args, resource_group_name=None, workspace_name=None, location=None, target_id=None,
def submit(cmd, program_args, resource_group_name, workspace_name, location, target_id,
project=None, job_name=None, shots=None, storage=None, no_build=False, job_params=None,
target_capability=None):
"""
Expand Down Expand Up @@ -203,7 +203,7 @@ def submit(cmd, program_args, resource_group_name=None, workspace_name=None, loc
# Query for the job and return status to caller.
return get(cmd, job_id, resource_group_name, workspace_name, location)

# The program compiled succesfully, but executing the stand-alone .exe failed to run.
# The program compiled successfully, but executing the stand-alone .exe failed to run.
logger.error("Submission of job failed with error code %s", result.returncode)
print(result.stdout.decode('ascii'))
raise AzureInternalError("Failed to submit job.")
Expand All @@ -229,7 +229,7 @@ def _parse_blob_url(url):
}


def output(cmd, job_id, resource_group_name=None, workspace_name=None, location=None):
def output(cmd, job_id, resource_group_name, workspace_name, location):
"""
Get the results of running a Q# job.
"""
Expand Down Expand Up @@ -305,7 +305,7 @@ def _validate_max_poll_wait_secs(max_poll_wait_secs):
return valid_max_poll_wait_secs


def wait(cmd, job_id, resource_group_name=None, workspace_name=None, location=None, max_poll_wait_secs=5):
def wait(cmd, job_id, resource_group_name, workspace_name, location, max_poll_wait_secs=5):
"""
Place the CLI in a waiting state until the job finishes running.
"""
Expand Down Expand Up @@ -334,7 +334,17 @@ def wait(cmd, job_id, resource_group_name=None, workspace_name=None, location=No
return job


def run(cmd, program_args, resource_group_name=None, workspace_name=None, location=None, target_id=None,
def job_show(cmd, job_id, resource_group_name, workspace_name, location):
"""
Get the job's status and details.
"""
info = WorkspaceInfo(cmd, resource_group_name, workspace_name, location)
client = cf_jobs(cmd.cli_ctx, info.subscription, info.resource_group, info.name, info.location)
job = client.get(job_id)
return job


def run(cmd, program_args, resource_group_name, workspace_name, location, target_id,
project=None, job_name=None, shots=None, storage=None, no_build=False, job_params=None, target_capability=None):
"""
Submit a job to run on Azure Quantum, and waits for the result.
Expand All @@ -353,7 +363,7 @@ def run(cmd, program_args, resource_group_name=None, workspace_name=None, locati
return output(cmd, job.id, resource_group_name, workspace_name, location)


def cancel(cmd, job_id, resource_group_name=None, workspace_name=None, location=None):
def cancel(cmd, job_id, resource_group_name, workspace_name, location):
"""
Request to cancel a job on Azure Quantum if it hasn't completed.
"""
Expand Down
6 changes: 3 additions & 3 deletions src/quantum/azext_quantum/operations/offerings.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def _valid_publisher_and_offer(provider, publisher, offer):
return True


def list_offerings(cmd, location=None, autoadd_only=False):
def list_offerings(cmd, location, autoadd_only=False):
"""
Get the list of all provider offerings available on the given location.
"""
Expand All @@ -70,7 +70,7 @@ def list_offerings(cmd, location=None, autoadd_only=False):
return offerings


def show_terms(cmd, provider_id=None, sku=None, location=None):
def show_terms(cmd, provider_id, sku, location):
"""
Show the terms of a provider and SKU combination including license URL and acceptance status.
"""
Expand All @@ -82,7 +82,7 @@ def show_terms(cmd, provider_id=None, sku=None, location=None):
return _get_terms_from_marketplace(cmd, publisher_id, offer_id, sku)


def accept_terms(cmd, provider_id=None, sku=None, location=None):
def accept_terms(cmd, provider_id, sku, location):
"""
Accept the terms of a provider and SKU combination to enable it for workspace creation.
"""
Expand Down
20 changes: 14 additions & 6 deletions src/quantum/azext_quantum/operations/target.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@ class TargetInfo:
def __init__(self, cmd, target_id=None):

def select_value(key, value):
if value is not None:
return value
value = cmd.cli_ctx.config.get('quantum', key, None)
if value is not None:
return value
value = cmd.cli_ctx.config.get(cmd.cli_ctx.config.defaults_section_name, key, None)
Expand All @@ -30,7 +27,7 @@ def save(self, cmd):
from azure.cli.core.util import ConfiguredDefaultSetter

with ConfiguredDefaultSetter(cmd.cli_ctx.config, False):
cmd.cli_ctx.config.set_value('quantum', 'target_id', self.target_id)
cmd.cli_ctx.config.set_value(cmd.cli_ctx.config.defaults_section_name, 'target_id', self.target_id)


def get(cmd, target_id=None):
Expand All @@ -41,7 +38,7 @@ def get(cmd, target_id=None):
return info


def set(cmd, target_id=None):
def set(cmd, target_id):
"""
Select the default target to use when submitting jobs to Azure Quantum.
"""
Expand All @@ -51,7 +48,7 @@ def set(cmd, target_id=None):
return info


def list(cmd, resource_group_name=None, workspace_name=None, location=None):
def list(cmd, resource_group_name, workspace_name, location):
"""
Get the list of providers and their targets in an Azure Quantum workspace.
"""
Expand All @@ -67,3 +64,14 @@ def clear(cmd):
info = TargetInfo(cmd)
info.clear()
info.save(cmd)


# Added to fix output problem
# def show(cmd, target_id):
def target_show(cmd, target_id):
"""
Show the currently selected default target.
"""
info = TargetInfo(cmd, target_id)
info.target_id += "" # Kludge excuse: Without this the only output we ever get is "targetId": {"isDefault": true}
return info
23 changes: 10 additions & 13 deletions src/quantum/azext_quantum/operations/workspace.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

# pylint: disable=line-too-long,redefined-builtin,unnecessary-comprehension, too-many-locals, too-many-statements
# pylint: disable=line-too-long,redefined-builtin,unnecessary-comprehension, too-many-locals, too-many-statements, too-many-nested-blocks

import os.path
import json
Expand Down Expand Up @@ -50,12 +50,8 @@ def __init__(self, cmd, resource_group_name=None, workspace_name=None, location=

# Hierarchically selects the value for the given key.
# First tries the value provided as argument, as that represents the value from the command line
# then it checks if the key exists in the 'quantum' section in config, and uses that if available.
# finally, it checks in the 'global' section in the config.
# then it checks if the key exists in the [defaults] section in config, and uses that if available.
def select_value(key, value):
if value is not None:
return value
value = cmd.cli_ctx.config.get('quantum', key, None)
if value is not None:
return value
value = cmd.cli_ctx.config.get(cmd.cli_ctx.config.defaults_section_name, key, None)
Expand All @@ -75,10 +71,11 @@ def clear(self):
def save(self, cmd):
from azure.cli.core.util import ConfiguredDefaultSetter

# Save in the global [defaults] section of the .azure\config file
with ConfiguredDefaultSetter(cmd.cli_ctx.config, False):
cmd.cli_ctx.config.set_value('quantum', 'group', self.resource_group)
cmd.cli_ctx.config.set_value('quantum', 'workspace', self.name)
cmd.cli_ctx.config.set_value('quantum', 'location', self.location)
cmd.cli_ctx.config.set_value(cmd.cli_ctx.config.defaults_section_name, 'group', self.resource_group)
Comment thread
warren-jones marked this conversation as resolved.
cmd.cli_ctx.config.set_value(cmd.cli_ctx.config.defaults_section_name, 'workspace', self.name)
cmd.cli_ctx.config.set_value(cmd.cli_ctx.config.defaults_section_name, 'location', self.location)


def _show_tip(msg):
Expand Down Expand Up @@ -211,7 +208,7 @@ def _validate_storage_account(tier_or_kind_msg_text, tier_or_kind, supported_tie
f"Storage account {tier_or_kind_msg_text}{plural} currently supported: {tier_or_kind_list[:-2]}")


def create(cmd, resource_group_name=None, workspace_name=None, location=None, storage_account=None, skip_role_assignment=False, provider_sku_list=None, auto_accept=False):
def create(cmd, resource_group_name, workspace_name, location, storage_account, skip_role_assignment=False, provider_sku_list=None, auto_accept=False):
"""
Create a new Azure Quantum workspace.
"""
Expand Down Expand Up @@ -315,7 +312,7 @@ def create(cmd, resource_group_name=None, workspace_name=None, location=None, st
return quantum_workspace


def delete(cmd, resource_group_name=None, workspace_name=None):
def delete(cmd, resource_group_name, workspace_name):
"""
Delete the given (or current) Azure Quantum workspace.
"""
Expand Down Expand Up @@ -354,7 +351,7 @@ def get(cmd, resource_group_name=None, workspace_name=None):
return ws


def quotas(cmd, resource_group_name=None, workspace_name=None, location=None):
def quotas(cmd, resource_group_name, workspace_name, location):
"""
List the quotas for the given (or current) Azure Quantum workspace.
"""
Expand All @@ -363,7 +360,7 @@ def quotas(cmd, resource_group_name=None, workspace_name=None, location=None):
return client.list()


def set(cmd, workspace_name, resource_group_name=None, location=None):
def set(cmd, workspace_name, resource_group_name, location):
"""
Set the default Azure Quantum workspace.
"""
Expand Down
16 changes: 14 additions & 2 deletions src/quantum/azext_quantum/tests/latest/test_quantum_jobs.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@

import json
import os
import pytest
import unittest

from azure.cli.testsdk.scenario_tests import AllowLargeResponse, live_only
from azure.cli.testsdk import (ScenarioTest, ResourceGroupPreparer)
from azure.cli.testsdk import ScenarioTest
from azure.cli.core.azclierror import InvalidArgumentValueError, AzureInternalError

from .utils import get_test_subscription_id, get_test_resource_group, get_test_workspace, get_test_workspace_location
from .utils import get_test_subscription_id, get_test_resource_group, get_test_workspace, get_test_workspace_location, issue_cmd_with_param_missing
from ..._client_factory import _get_data_credentials
from ...commands import transform_output
from ...operations.workspace import WorkspaceInfo
Expand All @@ -31,6 +32,17 @@ def test_jobs(self):
targets = self.cmd('az quantum target list -o json').get_output_in_json()
assert len(targets) > 0

# @pytest.fixture(autouse=True)
# def _pass_fixtures(self, capsys):
# self.capsys = capsys
# # See "TODO" in issue_cmd_with_param_missing un utils.py

def test_job_errors(self):
issue_cmd_with_param_missing(self, "az quantum job cancel", "az quantum job cancel -g MyResourceGroup -w MyWorkspace -l MyLocation -j yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy\nCancel an Azure Quantum job by id.")
issue_cmd_with_param_missing(self, "az quantum job output", "az quantum job output -g MyResourceGroup -w MyWorkspace -l MyLocation -j yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy -o table\nPrint the results of a successful Azure Quantum job.")
issue_cmd_with_param_missing(self, "az quantum job show", "az quantum job show -g MyResourceGroup -w MyWorkspace -l MyLocation -j yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy --query status\nGet the status of an Azure Quantum job.")
issue_cmd_with_param_missing(self, "az quantum job wait", "az quantum job wait -g MyResourceGroup -w MyWorkspace -l MyLocation -j yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy --max-poll-wait-secs 60 -o table\nWait for completion of a job, check at 60 second intervals.")

def test_build(self):
result = build(self, target_id='ionq.simulator', project='src\\quantum\\azext_quantum\\tests\\latest\\source_for_build_test\\QuantumRNG.csproj', target_capability='BasicQuantumFunctionality')
assert result == {'result': 'ok'}
Expand Down
21 changes: 21 additions & 0 deletions src/quantum/azext_quantum/tests/latest/test_quantum_offerings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------

import pytest

from azure.cli.testsdk import ScenarioTest
from .utils import issue_cmd_with_param_missing


class QuantumOfferingsScenarioTest(ScenarioTest):

# @pytest.fixture(autouse=True)
# def _pass_fixtures(self, capsys):
# self.capsys = capsys
# # See "TODO" in issue_cmd_with_param_missing un utils.py

def test_offerings_errors(self):
issue_cmd_with_param_missing(self, "az quantum offerings accept-terms", "az quantum offerings accept-terms -p MyProviderId -k MySKU -l MyLocation\nOnce terms have been reviewed, accept the invoking this command.")
issue_cmd_with_param_missing(self, "az quantum offerings show-terms", "az quantum offerings show-terms -p MyProviderId -k MySKU -l MyLocation\nUse a Provider Id and SKU from `az quantum offerings list` to review the terms.")
Loading