Skip to content
This repository was archived by the owner on Jul 28, 2023. It is now read-only.

Fix job date filtering for between #452

Merged
merged 17 commits into from
Nov 18, 2019
15 changes: 13 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@ The format is based on [Keep a Changelog].
> - **Security**: in case of vulnerabilities.


## [0.4.2] - 2019-11-18

### Fixed

- Fixed `IBMQBackendService.jobs()` to correctly return jobs when
both `start_datetime` and `end_datetime` are specified. Now, when the
two parameters are specified, the function will return the jobs after
(greater than or equal to) and before (less than or equal to) the
two given datetimes. (\#452)

## [0.4.1] - 2019-11-14

### Fixed
Expand All @@ -27,7 +37,7 @@ The format is based on [Keep a Changelog].
optional parameters `start_datetime` and `end_datetime`. If one is
specified, it is used to find jobs whose creation date is after
(greater than) or before (less than) the given the date/time,
respectively. If both are specified, they are used to find jobs
respectively. If both are specified, they are used to find jobs
whose creation date is between the two dates. (\#443)

## [0.4.0] - 2019-11-12
Expand Down Expand Up @@ -230,7 +240,8 @@ The format is based on [Keep a Changelog].
- Support for non-qobj format has been removed. (\#26, \#28)


[UNRELEASED]: https://github.com/Qiskit/qiskit-ibmq-provider/compare/0.4.1...HEAD
[UNRELEASED]: https://github.com/Qiskit/qiskit-ibmq-provider/compare/0.4.2...HEAD
[0.4.2]: https://github.com/Qiskit/qiskit-ibmq-provider/compare/0.4.1...0.4.2
[0.4.1]: https://github.com/Qiskit/qiskit-ibmq-provider/compare/0.4.0...0.4.1
[0.4.0]: https://github.com/Qiskit/qiskit-ibmq-provider/compare/0.3.3...0.4.0
[0.3.3]: https://github.com/Qiskit/qiskit-ibmq-provider/compare/0.3.2...0.3.3
Expand Down
2 changes: 1 addition & 1 deletion qiskit/providers/ibmq/VERSION.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.4.1
0.4.2
10 changes: 2 additions & 8 deletions qiskit/providers/ibmq/ibmqbackend.py
Original file line number Diff line number Diff line change
Expand Up @@ -276,9 +276,9 @@ def jobs(
<https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions>
`_ can be used.
start_datetime: filter by start date. This is used to find jobs
whose creation dates are after (greater than) this date/time.
whose creation dates are after (greater than or equal to) this date/time.
end_datetime: filter by end date. This is used to find jobs
whose creation dates are before (less than) this date/time.
whose creation dates are before (less than or equal to) this date/time.
db_filter: `loopback-based filter
<https://loopback.io/doc/en/lb2/Querying-data.html>`_.
This is an interface to a database ``where`` filter. Some
Expand All @@ -296,12 +296,6 @@ def jobs(
'qasms.result.data.counts.11': {'gt': 400}}
job_list = backend.jobs(limit=5, db_filter=cnts_filter)

Filter last five jobs from 30 days ago::

past_date = datetime.datetime.now() - datetime.timedelta(days=30)
date_filter = {'creationDate': {'lt': past_date.isoformat()}}
job_list = backend.jobs(limit=5, db_filter=date_filter)

Returns:
list of IBMQJob instances

Expand Down
29 changes: 11 additions & 18 deletions qiskit/providers/ibmq/ibmqbackendservice.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,9 @@ def jobs(
<https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions>
`_ can be used.
start_datetime: filter by start date. This is used to find jobs
whose creation dates are after (greater than) this date/time.
whose creation dates are after (greater than or equal to) this date/time.
end_datetime: filter by end date. This is used to find jobs
whose creation dates are before (less than) this date/time.
whose creation dates are before (less than or equal to) this date/time.
db_filter: `loopback-based filter
<https://loopback.io/doc/en/lb2/Querying-data.html>`_.
This is an interface to a database ``where`` filter. Some
Expand All @@ -146,12 +146,6 @@ def jobs(
'qasms.result.data.counts.11': {'gt': 400}}
job_list = backend.jobs(limit=5, db_filter=cnts_filter)

Filter last five jobs from 30 days ago::

past_date = datetime.datetime.now() - datetime.timedelta(days=30)
date_filter = {'creationDate': {'lt': past_date.isoformat()}}
job_list = backend.jobs(limit=5, db_filter=date_filter)

Returns:
list of IBMQJob instances

Expand Down Expand Up @@ -187,18 +181,17 @@ def jobs(
if job_name:
api_filter['name'] = {"regexp": job_name}

# Create the date query according to the parameters specified.
if start_datetime or end_datetime:
date_filter = {'creationDate': {}} # type: ignore[var-annotated]
if start_datetime:
date_filter['creationDate'].update({'gt': start_datetime.isoformat()})
if end_datetime:
date_filter['creationDate'].update({'lt': end_datetime.isoformat()})

api_filter.update(date_filter)
if start_datetime and end_datetime:
api_filter['creationDate'] = {
'between': [start_datetime.isoformat(), end_datetime.isoformat()]
}
elif start_datetime:
api_filter['creationDate'] = {'gte': start_datetime.isoformat()}
elif end_datetime:
api_filter['creationDate'] = {'lte': end_datetime.isoformat()}

if db_filter:
# status takes precedence over db_filter for same keys
# Argument filters takes precedence over db_filter for same keys
api_filter = {**db_filter, **api_filter}

# Retrieve the requested number of jobs, using pagination. The API
Expand Down
109 changes: 73 additions & 36 deletions test/ibmq/test_ibmq_job.py
Original file line number Diff line number Diff line change
Expand Up @@ -313,39 +313,85 @@ def test_get_jobs_filter_job_status_backend_service(self, backend, provider):
for job in job_list:
self.assertTrue(job.status() is JobStatus.DONE)

@requires_device
@requires_provider
def test_get_jobs_filter_job_start_datetime(self, backend, provider):
def test_get_jobs_filter_job_start_datetime(self, provider):
"""Test retrieving jobs created after a specified datetime."""
past_date = datetime.now() - timedelta(days=10)
backend = provider.get_backend('ibmq_qasm_simulator')
past_month = datetime.now() - timedelta(days=30)
past_month_str = past_month.strftime('%Y-%m-%dT%H:%M:%S.%fZ')

job_list = provider.backends.jobs(backend_name=backend.name(),
limit=5, skip=0, start_datetime=past_date)
for job in job_list:
self.assertTrue(job.creation_date() > str(past_date))
limit=5, skip=0, start_datetime=past_month)
self.assertTrue(job_list)
for i, job in enumerate(job_list):
self.assertTrue(job.creation_date() >= past_month_str,
'{}) job creation_date {} is not '
'greater than or equal to past month: {}'
.format(i, job.creation_date(), past_month_str))

@requires_device
@requires_provider
def test_get_jobs_filter_job_end_datetime(self, backend, provider):
def test_get_jobs_filter_job_end_datetime(self, provider):
"""Test retrieving jobs created before a specified datetime."""
date_today = datetime.now()
backend = provider.get_backend('ibmq_qasm_simulator')
past_month = datetime.now() - timedelta(days=30)
past_month_str = past_month.strftime('%Y-%m-%dT%H:%M:%S.%fZ')

job_list = provider.backends.jobs(backend_name=backend.name(),
limit=5, skip=0, end_datetime=date_today)
for job in job_list:
self.assertTrue(job.creation_date() < str(date_today))
limit=5, skip=0, end_datetime=past_month)
self.assertTrue(job_list)
for i, job in enumerate(job_list):
self.assertTrue(job.creation_date() <= past_month_str,
'{}) job creation_date {} is not '
'less than or equal to past month: {}'
.format(i, job.creation_date(), past_month_str))

@requires_device
@requires_provider
def test_get_jobs_filter_job_between_datetimes(self, backend, provider):
def test_get_jobs_filter_job_between_datetimes(self, provider):
"""Test retrieving jobs created between two specified datetimes."""
backend = provider.get_backend('ibmq_qasm_simulator')
date_today = datetime.now()
past_date = date_today - timedelta(days=10)

past_month = date_today - timedelta(30)
past_month_str = past_month.strftime('%Y-%m-%dT%H:%M:%S.%fZ')
past_two_month = date_today - timedelta(60)
past_two_month_str = past_two_month.strftime('%Y-%m-%dT%H:%M:%S.%fZ')

job_list = provider.backends.jobs(backend_name=backend.name(), limit=5, skip=0,
start_datetime=past_date, end_datetime=date_today)
for job in job_list:
self.assertTrue(str(past_date) < job.creation_date() < str(date_today))
start_datetime=past_two_month, end_datetime=past_month)
self.assertTrue(job_list)
for i, job in enumerate(job_list):
self.assertTrue((past_two_month_str <= job.creation_date() <= past_month_str),
'{}) job creation date {} is not '
'between past two month {} and past month {}'
.format(i, past_two_month_str, job.creation_date(), past_month_str))

@requires_provider
def test_get_jobs_filter_job_between_datetimes_not_overridden(self, provider):
"""Test retrieving jobs created between two specified datetimes
and ensure `db_filter` does not override datetime arguments."""
# pylint: disable=invalid-name
backend = provider.get_backend('ibmq_qasm_simulator')
date_today = datetime.now()

past_two_month = date_today - timedelta(30)
past_two_month_str = past_two_month.strftime('%Y-%m-%dT%H:%M:%S.%fZ')
past_three_month = date_today - timedelta(60)
past_three_month_str = past_three_month.strftime('%Y-%m-%dT%H:%M:%S.%fZ')

# Used for `db_filter`, should not override `start_datetime` and `end_datetime` arguments.
past_ten_days = date_today - timedelta(10)

job_list = provider.backends.jobs(backend_name=backend.name(), limit=5, skip=0,
start_datetime=past_three_month,
end_datetime=past_two_month,
db_filter={'creationDate': {'gt': past_ten_days}})
self.assertTrue(job_list)
for i, job in enumerate(job_list):
self.assertTrue((past_three_month_str <= job.creation_date() <= past_two_month_str),
'{}) job creation date {} is not '
'between past three month {} and past two month {}'
.format(i, past_three_month_str,
job.creation_date(), past_two_month_str))

@requires_provider
def test_get_jobs_filter_counts_backend(self, provider):
Expand Down Expand Up @@ -399,33 +445,24 @@ def test_get_jobs_filter_counts_backend_service(self, provider):
self.assertTrue(any(cresult.data.counts.to_dict()['0x0'] < 500
for cresult in result.results))

@requires_device
def test_get_jobs_filter_date_backend(self, backend):
"""Test retrieving jobs from a backend filtered by date."""
date_today = datetime.now().isoformat()
my_filter = {'creationDate': {'lt': date_today}}
job_list = backend.jobs(limit=5, db_filter=my_filter)

self.assertTrue(job_list)
self.log.info('found %s matching jobs', len(job_list))
for i, job in enumerate(job_list):
self.log.info('match #%d: %s', i, job.creation_date())
self.assertTrue(job.creation_date() < date_today)

@requires_device
@requires_provider
def test_get_jobs_filter_date_backend_service(self, backend, provider):
def test_get_jobs_filter_date_backend_service(self, provider):
"""Test retrieving jobs from backend service filtered by date."""
date_today = datetime.now().isoformat()
my_filter = {'creationDate': {'lt': date_today}}
backend = provider.get_backend('ibmq_qasm_simulator')
date_today = datetime.now()
date_today_str = date_today.strftime('%Y-%m-%dT%H:%M:%S.%fZ')

my_filter = {'creationDate': {'lt': date_today.isoformat()}}
job_list = provider.backends.jobs(backend_name=backend.name(),
limit=5, db_filter=my_filter)

self.assertTrue(job_list)
self.log.info('found %s matching jobs', len(job_list))
for i, job in enumerate(job_list):
self.log.info('match #%d: %s', i, job.creation_date())
self.assertTrue(job.creation_date() < date_today)
self.assertTrue(job.creation_date() < date_today_str,
'{}) job.creation_date: {}, date_today: {}'
.format(i, job.creation_date(), date_today_str))

@requires_provider
def test_double_submit_fails(self, provider):
Expand Down