Skip to content

Commit d1483ce

Browse files
authored
ENH Add job_id and run_id property attributes to CivisFuture (#290)
* ENH job_id and run_id as property attrs at CivisFuture * TST CivisFuture job_id and run_id * DOC explain why CivisFuture run_id can be None * DOC demo job_id and run_id in CivisFuture docstring * MAINT update change log * TST ensure no change to ContainerFuture's job_id and run_id * DOC job_id and run_id under Attributes of CivisFuture's docstring * DOC clearer example for run_id in CivisFuture's docstring * DOC add back example reminder in CivisFuture's docstring
1 parent 577544b commit d1483ce

File tree

3 files changed

+56
-12
lines changed

3 files changed

+56
-12
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ All notable changes to this project will be documented in this file.
33
This project adheres to [Semantic Versioning](http://semver.org/).
44

55
## Unreleased
6+
### Added
7+
- `CivisFuture` has the `job_id` and `run_id` property attributes. (#290)
8+
69
### Fixed
710
- Polling will treat `None` responses generated by spotty internet connections
811
like responses with a non-DONE state. (#289)

civis/futures.py

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,14 @@ class CivisFuture(PollableResult):
8787
first time. If ``False``, it will wait the number of seconds specified
8888
in `polling_interval` from object creation before polling.
8989
90+
Attributes
91+
----------
92+
job_id : int
93+
First element of the tuple given to `poller_args`
94+
run_id : int or None
95+
Second element of the tuple given to `poller_args`
96+
(`None` if the poller function does not require a run ID)
97+
9098
Examples
9199
--------
92100
This example is provided as a function at :func:`~civis.io.query_civis`.
@@ -98,12 +106,15 @@ class CivisFuture(PollableResult):
98106
>>> preview_rows = 10
99107
>>> response = client.queries.post(database_id, sql, preview_rows,
100108
>>> credential=cred_id)
101-
>>> job_id = response.id
102109
>>>
103-
>>> poller = client.queries.get
104-
>>> poller_args = (job_id, ) # (job_id, run_id) if poller requires run_id
110+
>>> poller = client.queries.get_runs
111+
>>> poller_args = response.id, response.last_run_id
105112
>>> polling_interval = 10
106113
>>> future = CivisFuture(poller, poller_args, polling_interval)
114+
>>> future.job_id == response.id
115+
True
116+
>>> future.run_id == response.last_run_id
117+
True
107118
"""
108119
def __init__(self, poller, poller_args,
109120
polling_interval=None, api_key=None, client=None,
@@ -136,6 +147,18 @@ def subscribed(self):
136147
return (hasattr(self, '_pubnub') and
137148
len(self._pubnub.get_subscribed_channels()) > 0)
138149

150+
@property
151+
def job_id(self):
152+
return self.poller_args[0]
153+
154+
@property
155+
def run_id(self):
156+
try:
157+
return self.poller_args[1]
158+
except IndexError:
159+
# when poller function has job_id only but not run_id
160+
return None
161+
139162
def cleanup(self):
140163
with self._condition:
141164
super().cleanup()
@@ -249,14 +272,6 @@ def __init__(self, job_id, run_id,
249272
poll_on_creation=poll_on_creation)
250273
self._max_n_retries = max_n_retries
251274

252-
@property
253-
def job_id(self):
254-
return self.poller_args[0]
255-
256-
@property
257-
def run_id(self):
258-
return self.poller_args[1]
259-
260275
def _set_api_exception(self, exc, result=None):
261276
# Catch attempts to set an exception. If there's retries
262277
# remaining, retry the run instead of erroring.

civis/tests/test_futures.py

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from civis.futures import (CivisFuture,
1717
JobCompleteListener,
1818
_LONG_POLLING_INTERVAL)
19-
from civis.tests import TEST_SPEC
19+
from civis.tests import TEST_SPEC, create_client_mock
2020
from pubnub.enums import PNStatusCategory
2121

2222
from civis.tests.testcase import CivisVCRTestCase
@@ -280,6 +280,32 @@ def _check_executor(from_template_id=None):
280280
return c
281281

282282

283+
@pytest.mark.parametrize(
284+
'poller_args,expected_job_id,expected_run_id',
285+
[((123, 456), 123, 456),
286+
((123,), 123, None)]
287+
)
288+
def test_future_job_id_run_id(poller_args, expected_job_id, expected_run_id):
289+
result = CivisFuture(
290+
poller=lambda x: x,
291+
poller_args=poller_args,
292+
client=create_client_mock(),
293+
)
294+
assert result.job_id == expected_job_id
295+
assert result.run_id == expected_run_id
296+
297+
298+
def test_container_future_job_id_run_id():
299+
job_id, run_id = 123, 456
300+
result = ContainerFuture(
301+
job_id=job_id,
302+
run_id=run_id,
303+
client=create_client_mock(),
304+
)
305+
assert result.job_id == job_id
306+
assert result.run_id == run_id
307+
308+
283309
def test_container_scripts():
284310
c = _check_executor()
285311
assert c.scripts.post_custom.call_count == 0

0 commit comments

Comments
 (0)