Skip to content
This repository was archived by the owner on Jan 12, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
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
10 changes: 9 additions & 1 deletion src/AzureClient/AzureClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ public async Task<ExecutionResult> GetJobStatusAsync(IChannel channel, string jo
}

/// <inheritdoc/>
public async Task<ExecutionResult> GetJobListAsync(IChannel channel)
public async Task<ExecutionResult> GetJobListAsync(IChannel channel, string filter)
{
if (ActiveWorkspace == null)
{
Expand All @@ -373,6 +373,14 @@ public async Task<ExecutionResult> GetJobListAsync(IChannel channel)
{
channel.Stderr("No jobs found in current Azure Quantum workspace.");
}
else
{
jobs = jobs.Where(job => job.Matches(filter));
if (jobs.Count() == 0)
{
channel.Stderr($"No jobs matching \"{filter}\" found in current Azure Quantum workspace.");
}
}

return jobs.ToExecutionResult();
}
Expand Down
9 changes: 9 additions & 0 deletions src/AzureClient/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading.Tasks;
using Microsoft.Azure.Quantum;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Jupyter.Core;

Expand Down Expand Up @@ -62,5 +63,13 @@ internal static async Task<ExecutionResult> ToExecutionResult(this Task<AzureCli
source is T singleton ? new List<T> { singleton } :
source is IEnumerable<T> collection ? collection :
null;

/// <summary>
/// Determines whether the given <see cref="CloudJob"/> matches the given <c>filter</c>.
/// </summary>
internal static bool Matches(this CloudJob job, string filter) =>
(job.Id != null && job.Id.Contains(filter, StringComparison.OrdinalIgnoreCase)) ||
(job.Details.Name != null && job.Details.Name.Contains(filter, StringComparison.OrdinalIgnoreCase)) ||
(job.Details.Target != null && job.Details.Target.Contains(filter, StringComparison.OrdinalIgnoreCase));
}
}
6 changes: 4 additions & 2 deletions src/AzureClient/IAzureClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,10 @@ public Task<ExecutionResult> ConnectAsync(IChannel channel,
/// Gets a list of all jobs in the current Azure Quantum workspace.
/// </summary>
/// <returns>
/// A list of all jobs in the current workspace.
/// A list of all jobs in the current workspace, optionally filtered
/// to jobs with fields containing <c>filter</c> using a case-insensitive
/// comparison.
/// </returns>
public Task<ExecutionResult> GetJobListAsync(IChannel channel);
public Task<ExecutionResult> GetJobListAsync(IChannel channel, string filter);
}
}
23 changes: 19 additions & 4 deletions src/AzureClient/Magic/JobsMagic.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ namespace Microsoft.Quantum.IQSharp.AzureClient
/// </summary>
public class JobsMagic : AzureClientMagicBase
{
private const string ParameterNameFilter = "__filter__";

/// <summary>
/// Initializes a new instance of the <see cref="JobsMagic"/> class.
/// </summary>
Expand All @@ -33,7 +35,8 @@ public JobsMagic(IAzureClient azureClient)
Summary = "Displays a list of jobs in the current Azure Quantum workspace.",
Description = @"
This magic command allows for displaying the list of jobs in the current
Azure Quantum workspace.
Azure Quantum workspace, optionally filtering the list to jobs which
have an ID, name, or target containing the provided filter parameter.

The Azure Quantum workspace must previously have been initialized
using the %azure.connect magic command.
Expand All @@ -47,13 +50,25 @@ The Azure Quantum workspace must previously have been initialized
Out[]: <list of jobs in the workspace>
```
".Dedent(),

@"
Print the list of jobs whose ID, name, or target contains ""MyJob"":
```
In []: %azure.jobs ""MyJob""
Out[]: <list of matching jobs>
```
".Dedent(),
},
}) {}

/// <summary>
/// Lists all jobs in the active workspace.
/// Lists all jobs in the active workspace, optionally filtered by a provided parameter.
/// </summary>
public override async Task<ExecutionResult> RunAsync(string input, IChannel channel, CancellationToken cancellationToken) =>
await AzureClient.GetJobListAsync(channel);
public override async Task<ExecutionResult> RunAsync(string input, IChannel channel, CancellationToken cancellationToken)
{
var inputParameters = ParseInputParameters(input, firstParameterInferredName: ParameterNameFilter);
var filter = inputParameters.DecodeParameter<string>(ParameterNameFilter, defaultValue: string.Empty);
return await AzureClient.GetJobListAsync(channel, filter);
}
}
}
3 changes: 1 addition & 2 deletions src/AzureClient/Visualization/CloudJobEncoders.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,9 @@ internal static Table<CloudJob> ToJupyterTable(this IEnumerable<CloudJob> jobsLi
Columns = new List<(string, Func<CloudJob, string>)>
{
// TODO: add cloudJob.Uri after https://github.com/microsoft/qsharp-runtime/issues/236 is fixed.
("Job ID", cloudJob => cloudJob.Id),
("Job Name", cloudJob => cloudJob.Details.Name),
("Job ID", cloudJob => cloudJob.Id),
("Job Status", cloudJob => cloudJob.Status),
("Provider", cloudJob => cloudJob.Details.ProviderId),
("Target", cloudJob => cloudJob.Details.Target),
("Creation Time", cloudJob => cloudJob.Details.CreationTime.ToDateTime()?.ToString() ?? string.Empty),
("Begin Execution Time", cloudJob => cloudJob.Details.BeginExecutionTime.ToDateTime()?.ToString() ?? string.Empty),
Expand Down
4 changes: 2 additions & 2 deletions src/Python/qsharp/azure.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ def output(jobId : str = '', **params) -> Dict:
if "error_code" in result: raise AzureError(result)
return result

def jobs(**params) -> List[AzureJob]:
result = qsharp.client._execute_magic(f"azure.jobs", raise_on_stderr=False, **params)
def jobs(filter : str = '', **params) -> List[AzureJob]:
result = qsharp.client._execute_magic(f"azure.jobs {filter}", raise_on_stderr=False, **params)
if "error_code" in result: raise AzureError(result)
return [AzureJob(job) for job in result]
6 changes: 6 additions & 0 deletions src/Python/qsharp/tests/test_azure.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,3 +107,9 @@ def test_workspace_with_providers():
jobs = qsharp.azure.jobs()
assert isinstance(jobs, list)
assert len(jobs) == 2

# Check that job filtering works
jobs = qsharp.azure.jobs(job.id)
print(job.id)
assert isinstance(jobs, list)
assert len(jobs) == 1
8 changes: 7 additions & 1 deletion src/Tests/AzureClientMagicTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,12 @@ public void TestJobsMagic()
var jobsMagic = new JobsMagic(azureClient);
jobsMagic.Test(string.Empty);
Assert.AreEqual(AzureClientAction.GetJobList, azureClient.LastAction);

// with arguments - should still print job status
azureClient = new MockAzureClient();
jobsMagic = new JobsMagic(azureClient);
jobsMagic.Test($"{jobId}");
Assert.AreEqual(AzureClientAction.GetJobList, azureClient.LastAction);
}

[TestMethod]
Expand Down Expand Up @@ -255,7 +261,7 @@ public async Task<ExecutionResult> GetConnectionStatusAsync(IChannel channel)
return ExecuteStatus.Ok.ToExecutionResult();
}

public async Task<ExecutionResult> GetJobListAsync(IChannel channel)
public async Task<ExecutionResult> GetJobListAsync(IChannel channel, string filter)
{
LastAction = AzureClientAction.GetJobList;
return ExecuteStatus.Ok.ToExecutionResult();
Expand Down
8 changes: 6 additions & 2 deletions src/Tests/AzureClientTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,13 @@ public void TestJobStatus()
// invalid job ID
ExpectError(AzureClientError.JobNotFound, azureClient.GetJobStatusAsync(new MockChannel(), "JOB_ID_3"));

// jobs list
var jobs = ExpectSuccess<IEnumerable<CloudJob>>(azureClient.GetJobListAsync(new MockChannel()));
// jobs list with no filter
var jobs = ExpectSuccess<IEnumerable<CloudJob>>(azureClient.GetJobListAsync(new MockChannel(), string.Empty));
Assert.AreEqual(2, jobs.Count());

// jobs list with filter
jobs = ExpectSuccess<IEnumerable<CloudJob>>(azureClient.GetJobListAsync(new MockChannel(), "JOB_ID_1"));
Assert.AreEqual(1, jobs.Count());
}

[TestMethod]
Expand Down