Skip to content
This repository was archived by the owner on Jul 24, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all 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
11 changes: 9 additions & 2 deletions qiskit_ibm/api/clients/runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,10 @@ def jobs_get(
limit: int = None,
skip: int = None,
pending: bool = None,
program_id: str = None
program_id: str = None,
hub: str = None,
group: str = None,
project: str = None
) -> Dict:
"""Get job data for all jobs.

Expand All @@ -189,11 +192,15 @@ def jobs_get(
pending: Returns 'QUEUED' and 'RUNNING' jobs if True,
returns 'DONE', 'CANCELLED' and 'ERROR' jobs if False.
program_id: Filter by Program ID.
hub: Filter by hub - hub, group, and project must all be specified.
group: Filter by group - hub, group, and project must all be specified.
project: Filter by project - hub, group, and project must all be specified.

Returns:
JSON response.
"""
return self.api.jobs_get(limit=limit, skip=skip, pending=pending, program_id=program_id)
return self.api.jobs_get(limit=limit, skip=skip, pending=pending,
program_id=program_id, hub=hub, group=group, project=project)

def job_results(self, job_id: str) -> str:
"""Get the results of a program job.
Expand Down
10 changes: 9 additions & 1 deletion qiskit_ibm/api/rest/runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,10 @@ def jobs_get(
limit: int = None,
skip: int = None,
pending: bool = None,
program_id: str = None
program_id: str = None,
hub: str = None,
group: str = None,
project: str = None
) -> Dict:
"""Get a list of job data.

Expand All @@ -149,6 +152,9 @@ def jobs_get(
pending: Returns 'QUEUED' and 'RUNNING' jobs if True,
returns 'DONE', 'CANCELLED' and 'ERROR' jobs if False.
program_id: Filter by Program ID.
hub: Filter by hub - hub, group, and project must all be specified.
group: Filter by group - hub, group, and project must all be specified.
project: Filter by project - hub, group, and project must all be specified.

Returns:
JSON response.
Expand All @@ -163,6 +169,8 @@ def jobs_get(
payload['pending'] = 'true' if pending else 'false'
if program_id:
payload['program'] = program_id
if all([hub, group, project]):
payload['provider'] = f"{hub}/{group}/{project}"
return self.session.get(url, params=payload).json()

def logout(self) -> None:
Expand Down
22 changes: 20 additions & 2 deletions qiskit_ibm/runtime/ibm_runtime_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,10 @@ def jobs(
limit: Optional[int] = 10,
skip: int = 0,
pending: bool = None,
program_id: str = None
program_id: str = None,
hub: str = None,
group: str = None,
project: str = None
) -> List[RuntimeJob]:
"""Retrieve all runtime jobs, subject to optional filtering.

Expand All @@ -537,10 +540,22 @@ def jobs(
jobs are included. If ``False``, 'DONE', 'CANCELLED' and 'ERROR' jobs
are included.
program_id: Filter by Program ID.
hub: Filter by hub - hub, group, and project must all be specified.
group: Filter by group - hub, group, and project must all be specified.
project: Filter by project - hub, group, and project must all be specified.

Returns:
A list of runtime jobs.

Raises:
IBMInputValueError: If any but not all of the parameters ``hub``, ``group``
and ``project`` are given.
"""
if any([hub, group, project]) and not all([hub, group, project]):
raise IBMInputValueError('Hub, group and project '
'parameters must all be specified. '
'hub = "{}", group = "{}", project = "{}"'
.format(hub, group, project))
job_responses = [] # type: List[Dict[str, Any]]
current_page_limit = limit or 20
offset = skip
Expand All @@ -550,7 +565,10 @@ def jobs(
limit=current_page_limit,
skip=offset,
pending=pending,
program_id=program_id)
program_id=program_id,
hub=hub,
group=group,
project=project)
job_page = jobs_response["jobs"]
# count is the total number of jobs that would be returned if
# there was no limit or skip
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
features:
- |
You can now pass ``hub``, ``group``, and ``project`` parameters to
:meth:`qiskit_ibm.runtime.IBMRuntimeService.jobs` to filter jobs.
26 changes: 22 additions & 4 deletions test/ibm/runtime/fake_runtime_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,13 +214,23 @@ def _auto_progress(self):
class BaseFakeRuntimeClient:
"""Base class for faking the runtime client."""

def __init__(self, job_classes=None, final_status=None, job_kwargs=None):
def __init__(self, job_classes=None, final_status=None, job_kwargs=None,
hub=None, group=None, project=None):
"""Initialize a fake runtime client."""
self._programs = {}
self._jobs = {}
self._job_classes = job_classes or []
self._final_status = final_status
self._job_kwargs = job_kwargs or {}
self._hub = hub
self._group = group
self._project = project

def set_hgp(self, hub, group, project):
"""Set hub, group and project"""
self._hub = hub
self._group = group
self._project = project

def set_job_classes(self, classes):
"""Set job classes to use."""
Expand Down Expand Up @@ -297,9 +307,12 @@ def program_run(
"""Run the specified program."""
job_id = uuid.uuid4().hex
job_cls = self._job_classes.pop(0) if len(self._job_classes) > 0 else BaseFakeRuntimeJob
hub = self._hub or credentials.hub
group = self._group or credentials.group
project = self._project or credentials.project
job = job_cls(job_id=job_id, program_id=program_id,
hub=credentials.hub, group=credentials.group,
project=credentials.project, backend_name=backend_name,
hub=hub, group=group,
project=project, backend_name=backend_name,
params=params, final_status=self._final_status, image=image,
**self._job_kwargs)
self._jobs[job_id] = job
Expand All @@ -315,7 +328,8 @@ def job_get(self, job_id):
"""Get the specific job."""
return self._get_job(job_id).to_dict()

def jobs_get(self, limit=None, skip=None, pending=None, program_id=None):
def jobs_get(self, limit=None, skip=None, pending=None, program_id=None,
hub=None, group=None, project=None):
"""Get all jobs."""
pending_statuses = ['QUEUED', 'RUNNING']
returned_statuses = ['COMPLETED', 'FAILED', 'CANCELLED']
Expand All @@ -330,6 +344,10 @@ def jobs_get(self, limit=None, skip=None, pending=None, program_id=None):
if program_id:
jobs = [job for job in jobs if job._program_id == program_id]
count = len(jobs)
if all([hub, group, project]):
jobs = [job for job in jobs if
job._hub == hub and job._group == group and job._project == project]
count = len(jobs)
jobs = jobs[skip:limit+skip]
return {"jobs": [job.to_dict() for job in jobs],
"count": count}
Expand Down
20 changes: 19 additions & 1 deletion test/ibm/runtime/test_runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -622,6 +622,22 @@ def test_jobs_filter_by_program_id(self):
self.assertEqual(program_id, rjobs[0].program_id)
self.assertEqual(1, len(rjobs))

def test_jobs_filter_by_provider(self):
"""Test retrieving jobs by provider."""
program_id = self._upload_program()
job = self._run_program(program_id=program_id,
hub="defaultHub", group="defaultGroup", project="defaultProject")
job.wait_for_final_state()
rjobs = self.runtime.jobs(program_id=program_id,
hub="defaultHub", group="defaultGroup", project="defaultProject")
self.assertEqual(program_id, rjobs[0].program_id)
self.assertEqual(1, len(rjobs))
rjobs = self.runtime.jobs(program_id=program_id,
hub="test", group="test", project="test")
self.assertFalse(rjobs)
with self.assertRaises(IBMInputValueError):
self.runtime.jobs(hub="defaultHub")
Comment thread
rathishcholarajan marked this conversation as resolved.

def test_cancel_job(self):
"""Test canceling a job."""
job = self._run_program(job_classes=CancelableRuntimeJob)
Expand Down Expand Up @@ -725,13 +741,15 @@ def _upload_program(self, name=None, max_execution_time=300,
return program_id

def _run_program(self, program_id=None, inputs=None, job_classes=None, final_status=None,
decoder=None, image=""):
decoder=None, image="", hub=None, group=None, project=None):
"""Run a program."""
options = {'backend_name': "some_backend"}
if final_status is not None:
self.runtime._api_client.set_final_status(final_status)
elif job_classes:
self.runtime._api_client.set_job_classes(job_classes)
elif all([hub, group, project]):
self.runtime._api_client.set_hgp(hub, group, project)
if program_id is None:
program_id = self._upload_program()
job = self.runtime.run(program_id=program_id, inputs=inputs,
Expand Down
16 changes: 16 additions & 0 deletions test/ibm/runtime/test_runtime_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,22 @@ def test_retrieve_jobs_by_program_id(self):
self.assertEqual(program_id, rjobs[0].program_id)
self.assertEqual(1, len(rjobs))

def test_jobs_filter_by_provider(self):
"""Test retrieving jobs by provider."""
hub = self.provider.credentials.hub
group = self.provider.credentials.group
project = self.provider.credentials.project
program_id = self._upload_program()
job = self._run_program(program_id=program_id)
job.wait_for_final_state()
rjobs = self.provider.runtime.jobs(program_id=program_id,
hub=hub, group=group, project=project)
self.assertEqual(program_id, rjobs[0].program_id)
self.assertEqual(1, len(rjobs))
rjobs = self.provider.runtime.jobs(program_id=program_id,
hub="test", group="test", project="test")
self.assertFalse(rjobs)

def test_cancel_job_queued(self):
"""Test canceling a queued job."""
_ = self._run_program(iterations=10)
Expand Down