Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
56eb415
support search param
kt474 Nov 17, 2021
792626d
add reno
kt474 Nov 17, 2021
95aaf72
add test cases
kt474 Nov 17, 2021
6461d26
Merge branch 'main' into query-programs-search
rathishcholarajan Nov 23, 2021
e1ac37f
Merge branch 'main' into query-programs-search
rathishcholarajan Nov 23, 2021
c11768d
Merge branch 'main' into query-programs-search
kt474 Nov 29, 2021
fb928de
lint
kt474 Nov 29, 2021
1ab4e95
update tests
kt474 Nov 29, 2021
a07448d
Merge branch 'main' into query-programs-search
kt474 Nov 29, 2021
b5c4627
remove print
kt474 Nov 29, 2021
d63a164
Merge branch 'query-programs-search' of https://github.com/Qiskit/qis…
kt474 Nov 29, 2021
05c7e77
update cache logic
kt474 Nov 30, 2021
cccb591
Merge branch 'main' into query-programs-search
rathishcholarajan Dec 1, 2021
d429f8a
Merge branch 'main' into query-programs-search
rathishcholarajan Dec 1, 2021
76c43da
update cache logic
kt474 Dec 2, 2021
e9bfce9
Merge branch 'main' into query-programs-search
rathishcholarajan Dec 2, 2021
33606e1
update test cases
kt474 Dec 2, 2021
28b86f7
fix lint
kt474 Dec 2, 2021
fe5072b
lint - add search param back
kt474 Dec 2, 2021
87b6ef5
Merge branch 'main' into query-programs-search
kt474 Dec 5, 2021
5f69947
update cache logic
kt474 Dec 5, 2021
ce435cd
Update qiskit_ibm_runtime/ibm_runtime_service.py
kt474 Dec 7, 2021
667bf6d
update retrieve program method
kt474 Dec 7, 2021
77704fd
Merge branch 'query-programs-search' of https://github.com/Qiskit/qis…
kt474 Dec 7, 2021
dbeadb3
Merge branch 'main' into query-programs-search
kt474 Dec 7, 2021
80a44d1
Merge branch 'main' into query-programs-search
kt474 Dec 8, 2021
0b93527
rerfactor logic
kt474 Dec 8, 2021
4184fd9
Merge branch 'main' into query-programs-search
kt474 Dec 16, 2021
b4c40a2
Merge branch 'main' into query-programs-search
kt474 Jan 4, 2022
6d1701d
Merge branch 'main' into query-programs-search
kt474 Jan 5, 2022
c190b77
add unit test back
kt474 Jan 5, 2022
ae88f75
add integration test
kt474 Jan 6, 2022
b9b0d00
Merge branch 'main' into query-programs-search
kt474 Jan 6, 2022
4d4c21f
Merge branch 'main' into query-programs-search
kt474 Jan 7, 2022
f1815fb
fix list programs test cases
kt474 Jan 7, 2022
712f812
Merge branch 'main' into query-programs-search
kt474 Jan 7, 2022
76e6bdc
Merge branch 'main' into query-programs-search
kt474 Jan 12, 2022
5d414a0
Merge branch 'main' into query-programs-search
kt474 Jan 14, 2022
698117a
Merge branch 'main' into query-programs-search
kt474 Jan 17, 2022
789c750
Merge branch 'main' into query-programs-search
kt474 Jan 31, 2022
0738419
remove whitespace
kt474 Jan 31, 2022
bf31766
Merge branch 'main' into query-programs-search
daka1510 Feb 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
7 changes: 5 additions & 2 deletions qiskit_ibm_runtime/api/clients/runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,20 @@ def __init__(
)
self._api = Runtime(self._session)

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

Args:
search: Returns programs containing search word in name or description.
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(search, limit, skip)

def program_create(
self,
Expand Down
9 changes: 7 additions & 2 deletions qiskit_ibm_runtime/api/rest/runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,18 +56,23 @@ 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, search: str = "", limit: int = None, skip: int = None
) -> Dict[str, Any]:
"""Return a list of runtime programs.

Args:
search: Returns programs containing search word in name or description.
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 search:
payload["search"] = search
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 @@ -641,6 +641,7 @@ def pprint_programs(
self,
refresh: bool = False,
detailed: bool = False,
search: Optional[str] = "",
limit: int = 20,
skip: int = 0,
) -> None:
Expand All @@ -650,11 +651,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.
search: Returns programs containing search word in name or description.
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, search, limit, skip)
for prog in programs:
print("=" * 50)
if detailed:
Expand All @@ -667,7 +669,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,
search: Optional[str] = "",
limit: int = 20,
skip: int = 0,
) -> List[RuntimeProgram]:
"""Return available runtime programs.

Expand All @@ -676,35 +682,30 @@ def programs(
Args:
refresh: If ``True``, re-query the server for the programs. Otherwise
return the cached value.
search: Returns programs containing search word in name or description.
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 search):
self._programs = self._retrieve_programs()
already_retrieved = True
if limit is None:
limit = len(self._programs)
if search:
matched_programs = []
if refresh and not already_retrieved:
matched_programs = list(self._retrieve_programs(search).values())
else:
for program in list(self._programs.values()):
if search in program.name or search in program.description:
matched_programs.append(program)
return matched_programs[skip : limit + skip]
return list(self._programs.values())[skip : limit + skip]

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

return self._programs[program_id]

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

Args:
search: Search query for program name and description.

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(
search=search, 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/program-search-query-675455e48d0a5f0a.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
upgrade:
- |
The ``search`` parameter has been added to
:meth:`qiskit_ibm_runtime.IBMRuntimeService.programs` and
:meth:`qiskit_ibm_runtime.IBMRuntimeService.pprint_programs`
which can be used to query programs containing the
search word in its name or description.
10 changes: 8 additions & 2 deletions test/mock/fake_runtime_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,11 +271,17 @@ 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, search, limit, skip):
"""List all programs."""
programs = []
for prog in self._programs.values():
programs.append(prog.to_dict())
if not search:
programs.append(prog.to_dict())
if (
search in prog.to_dict()["name"].lower()
or search in prog.to_dict()["description"].lower()
):
programs.append(prog.to_dict())
return {"programs": programs[skip : limit + skip], "count": len(self._programs)}

def program_create(
Expand Down
13 changes: 12 additions & 1 deletion test/test_integration_program.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class TestIntegrationProgram(IBMIntegrationTestCase):
def test_list_programs(self, service):
"""Test listing programs."""
program_id = self._upload_program(service)
programs = service.programs()
programs = service.programs(refresh=True)
self.assertTrue(programs)
found = False
for prog in programs:
Expand All @@ -58,6 +58,17 @@ def test_list_programs_with_limit_skip(self, service):
self.assertIn(all_ids[1], some_ids)
self.assertIn(all_ids[2], some_ids)

@run_integration_test
def test_filter_programs_with_search(self, service):
"""Test filtering programs with the search parameter"""
program_id = self._upload_program(service)
programs = service.programs(search="test program")
all_ids = [prog.program_id for prog in programs]
self.assertIn(program_id, all_ids)
programs = service.programs(search="test sample")
all_ids = [prog.program_id for prog in programs]
self.assertNotIn(program_id, all_ids)

@run_integration_test
def test_list_program(self, service):
"""Test listing a single program."""
Expand Down
11 changes: 11 additions & 0 deletions test/test_programs.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,17 @@ def test_list_programs_with_limit_skip(self, service):
all_ids = [prog.program_id for prog in programs]
self.assertIn(program_ids[0], all_ids)

@run_legacy_and_cloud_fake
def test_filter_programs_with_search(self, service):
"""Test filtering programs with the search parameter"""
program_id = upload_program(service)
programs = service.programs(search="Test program")
all_ids = [prog.program_id for prog in programs]
self.assertIn(program_id, all_ids)
programs = service.programs(search="Test sample")
all_ids = [prog.program_id for prog in programs]
self.assertNotIn(program_id, all_ids)

@run_legacy_and_cloud_fake
def test_list_program(self, service):
"""Test listing a single program."""
Expand Down