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

Query programs by name #14

Closed
wants to merge 29 commits into from
Closed
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
07460d7
query programs by name
kt474 Nov 17, 2021
85be645
refactor cache logic
kt474 Nov 17, 2021
7413496
Merge branch 'main' into query-program-name
rathishcholarajan Nov 23, 2021
3c282e1
Merge branch 'main' into query-program-name
rathishcholarajan Nov 23, 2021
d2cc513
Merge branch 'main' into query-program-name
kt474 Nov 29, 2021
f733ee0
fix lint
kt474 Nov 29, 2021
b26f544
update tests
kt474 Nov 29, 2021
17d1f47
Merge branch 'main' into query-program-name
rathishcholarajan Nov 29, 2021
610e8a0
refactor programs cache
kt474 Nov 30, 2021
ad53714
fix lint
kt474 Nov 30, 2021
7be7a77
Merge branch 'main' into query-program-name
kt474 Nov 30, 2021
bf87cae
unrelated lint fix
kt474 Nov 30, 2021
5a1d7c2
Merge branch 'query-program-name' of https://github.com/Qiskit/qiskit…
kt474 Nov 30, 2021
b9933c9
Merge branch 'main' into query-program-name
rathishcholarajan Dec 1, 2021
830ddfc
Merge branch 'main' into query-program-name
rathishcholarajan Dec 1, 2021
ebacbee
update cache logic
kt474 Dec 2, 2021
d48e892
Merge branch 'main' into query-program-name
rathishcholarajan Dec 2, 2021
0ab06e6
update cache logic
kt474 Dec 5, 2021
c188a14
Merge branch 'main' into query-program-name
kt474 Dec 5, 2021
8d287d9
Update qiskit_ibm_runtime/ibm_runtime_service.py
kt474 Dec 7, 2021
861cf00
update retrieve programs method
kt474 Dec 7, 2021
af309c7
refactor logic
kt474 Dec 8, 2021
ea04aa8
Merge branch 'main' into query-program-name
kt474 Dec 16, 2021
fca5a98
Merge branch 'main' into query-program-name
kt474 Jan 4, 2022
0bc0bca
Merge branch 'main' into query-program-name
kt474 Jan 5, 2022
6671b7d
add tests back in
kt474 Jan 5, 2022
851caa2
Merge branch 'main' into query-program-name
kt474 Jan 6, 2022
d33595e
Merge branch 'main' into query-program-name
kt474 Jan 7, 2022
5e827fe
fix list programs test
kt474 Jan 7, 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
8 changes: 5 additions & 3 deletions qiskit_ibm_runtime/api/clients/runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,19 @@ def __init__(
)
self.api = Runtime(self._session)

def list_programs(self, limit: int = None, skip: int = None) -> Dict[str, Any]:
def list_programs(
self, name: str = "", limit: int = None, skip: int = None
) -> Dict[str, Any]:
"""Return a list of runtime programs.

Args:
name: Name of the program.
limit: The number of programs to return.
skip: The number of programs to skip.

Returns:
A list of runtime programs.
"""
return self.api.list_programs(limit, skip)
return self.api.list_programs(name, limit, skip)

def program_create(
self,
Expand Down
10 changes: 7 additions & 3 deletions qiskit_ibm_runtime/api/rest/runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,18 +51,22 @@ def program_job(self, job_id: str) -> "ProgramJob":
"""
return ProgramJob(self.session, job_id)

def list_programs(self, limit: int = None, skip: int = None) -> Dict[str, Any]:
def list_programs(
self, name: str = "", limit: int = None, skip: int = None
) -> Dict[str, Any]:
"""Return a list of runtime programs.

Args:
name: Name of the program.
limit: The number of programs to return.
skip: The number of programs to skip.

Returns:
A list of runtime programs.
"""
url = self.get_url("programs")
payload: Dict[str, int] = {}
payload: Dict[str, Union[int, str]] = {}
if name:
payload["name"] = name
if limit:
payload["limit"] = limit
if skip:
Expand Down
72 changes: 51 additions & 21 deletions qiskit_ibm_runtime/ibm_runtime_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -811,6 +811,7 @@ def pprint_programs(
self,
refresh: bool = False,
detailed: bool = False,
name: Optional[str] = "",
limit: int = 20,
skip: int = 0,
) -> None:
Expand All @@ -820,11 +821,12 @@ def pprint_programs(
refresh: If ``True``, re-query the server for the programs. Otherwise
return the cached value.
detailed: If ``True`` print all details about available runtime programs.
name: Only retrieve programs with the exact program name given.
limit: The number of programs returned at a time. Default and maximum
value of 20.
skip: The number of programs to skip.
"""
programs = self.programs(refresh, limit, skip)
programs = self.programs(refresh, name, limit, skip)
for prog in programs:
print("=" * 50)
if detailed:
Expand All @@ -837,7 +839,11 @@ def pprint_programs(
print(f" Description: {prog.description}")

def programs(
self, refresh: bool = False, limit: int = 20, skip: int = 0
self,
refresh: bool = False,
name: Optional[str] = "",
limit: int = 20,
skip: int = 0,
) -> List[RuntimeProgram]:
"""Return available runtime programs.

Expand All @@ -846,35 +852,30 @@ def programs(
Args:
refresh: If ``True``, re-query the server for the programs. Otherwise
return the cached value.
name: Only retrieve programs with the exact program name given.
limit: The number of programs returned at a time. ``None`` means no limit.
skip: The number of programs to skip.

Returns:
A list of runtime programs.
"""
already_retrieved = False
if skip is None:
skip = 0
if not self._programs or refresh:
self._programs = {}
current_page_limit = 20
offset = 0
while True:
response = self._api_client.list_programs(
limit=current_page_limit, skip=offset
)
program_page = response.get("programs", [])
# count is the total number of programs that would be returned if
# there was no limit or skip
count = response.get("count", 0)
for prog_dict in program_page:
program = self._to_program(prog_dict)
self._programs[program.program_id] = program
if len(self._programs) == count:
# Stop if there are no more programs returned by the server.
break
offset += len(program_page)
if not self._programs or (refresh and not name):
self._programs = self._retrieve_programs()
already_retrieved = True
if limit is None:
limit = len(self._programs)
if name:
if refresh and not already_retrieved:
temp_programs = self._retrieve_programs(name)
return list(temp_programs.values())[skip : limit + skip]
matched_programs = []
for program in list(self._programs.values()):
if program.name == name:
matched_programs.append(program)
return matched_programs[skip : limit + skip]
kt474 marked this conversation as resolved.
Show resolved Hide resolved
return list(self._programs.values())[skip : limit + skip]

def program(self, program_id: str, refresh: bool = False) -> RuntimeProgram:
Expand Down Expand Up @@ -908,6 +909,35 @@ def program(self, program_id: str, refresh: bool = False) -> RuntimeProgram:

return self._programs[program_id]

def _retrieve_programs(self, name: str = "") -> Dict[str, RuntimeProgram]:
"""Make an API call to fetch programs.

Args:
name: Name of the program.

Returns:
A dict of ``RuntimeProgram`` instances, keyed by program name.
"""
programs = {}
current_page_limit = 20
offset = 0
while True:
response = self._api_client.list_programs(
name=name, limit=current_page_limit, skip=offset
)
program_page = response.get("programs", [])
# count is the total number of programs that would be returned if
# there was no limit or skip
count = response.get("count", 0)
for prog_dict in program_page:
program = self._to_program(prog_dict)
programs[program.program_id] = program
if len(programs) == count:
# Stop if there are no more programs returned by the server.
break
offset += len(program_page)
return programs

def _to_program(self, response: Dict) -> RuntimeProgram:
"""Convert server response to ``RuntimeProgram`` instances.

Expand Down
8 changes: 8 additions & 0 deletions releasenotes/notes/query-program-name-22b97d6b4c5731d2.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
upgrade:
- |
The ``name`` parameter has been added to
:meth:`qiskit_ibm_runtime.IBMRuntimeService.programs` and
:meth:`qiskit_ibm_runtime.IBMRuntimeService.pprint_programs`
which can be used to filter by a specific program name. The
``name`` given must be an exact match with an actual program name.
7 changes: 5 additions & 2 deletions test/ibm/runtime/fake_runtime_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -265,11 +265,14 @@ def set_final_status(self, final_status):
"""Set job status to passed in final status instantly."""
self._final_status = final_status

def list_programs(self, limit, skip):
def list_programs(self, name, limit, skip):
"""List all programs."""
programs = []
for prog in self._programs.values():
programs.append(prog.to_dict())
if not name:
programs.append(prog.to_dict())
if name == prog.to_dict()["name"]:
programs.append(prog.to_dict())
return {"programs": programs[skip : limit + skip], "count": len(self._programs)}

def program_create(
Expand Down
10 changes: 10 additions & 0 deletions test/ibm/runtime/test_runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,16 @@ def test_list_programs(self):
all_ids = [prog.program_id for prog in programs]
self.assertIn(program_id, all_ids)

def test_filter_programs_with_program_name(self):
"""Test filter programs with the program name"""
program_id = self._upload_program(name="qiskit-test-sample")
programs = self.service.programs(name="qiskit-test-sample")
all_ids = [prog.program_id for prog in programs]
self.assertIn(program_id, all_ids)
programs = self.service.programs(name="qiskit-test")
all_ids = [prog.program_id for prog in programs]
self.assertNotIn(program_id, all_ids)

def test_list_programs_with_limit_skip(self):
"""Test listing programs with limit and skip."""
program_1 = self._upload_program()
Expand Down
10 changes: 10 additions & 0 deletions test/ibm/runtime/test_runtime_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,16 @@ def test_list_programs(self):
found = True
self.assertTrue(found, f"Program {self.program_id} not found!")

def test_filter_programs_with_program_name(self):
"""Test filter programs with program name."""
program_id = self._upload_program(name="qiskit-test-sample")
programs = self.service.programs(name="qiskit-test-sample")
all_ids = [prog.program_id for prog in programs]
self.assertIn(program_id, all_ids)
programs = self.service.programs(name="qiskit-test")
all_ids = [prog.program_id for prog in programs]
self.assertNotIn(program_id, all_ids)

def test_list_programs_with_limit_skip(self):
"""Test listing programs with limit and skip."""
self._upload_program()
Expand Down