-
Notifications
You must be signed in to change notification settings - Fork 53
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
DATAUP-765: add user and wsid to job output #3386
Conversation
# run_id (str): unique run ID for the job | ||
# status (str): EE2 job status |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no idea why this pretty important attribute was omitted!
extra_data: dict[str, Any] | None = None, | ||
children: list["Job"] | None = None, | ||
): | ||
state = cls.query_ee2_states([job_id], init=True) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use the plural form, query_ee2_states
, so that the singular form can be removed.
@staticmethod | ||
def _trim_ee2_state(state: dict, exclude_fields: list) -> None: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
moved down the file a bit
@staticmethod | ||
def _trim_ee2_state( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
moved (but not changed)
# TODO | ||
# Only batch container jobs have a child_jobs field | ||
# and need the state refresh. | ||
# But KBParallel/KB Batch App jobs may not have the | ||
# batch_job field | ||
self.refresh_state(force_refresh=True).get( | ||
self.refresh_state(force_refresh=force_refresh).get( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is deeply annoying to me. Why have a refresh_state
method if you're not going to refresh the state?!
""" | ||
Returns the parameters used to start the job. Job tries to use its params field, but | ||
if that's None, then it makes a call to EE2. | ||
|
||
If no exception is raised, this only returns the list of parameters, NOT the whole | ||
object fetched from ee2.check_job | ||
""" | ||
if self.params is not None: | ||
return self.params | ||
if self.params is None: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
slight rearrangement of the logic
state = self.query_ee2_states([self.job_id], init=False) | ||
self.update_state(state[self.job_id]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use plural form, query_ee2_states
if self._acc_state is None: | ||
self._acc_state = {} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
self._acc_state
is set during __init__()
so will never be None
"""Wrapper for self._acc_state""" | ||
state = copy.deepcopy(self._acc_state) | ||
self._trim_ee2_state(state, exclude_fields) | ||
return state | ||
|
||
def output_state(self, state=None, no_refresh=False) -> dict: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
change output_state
so that it no longer merges in a fetched state; now the state merge is done by running update_state
beforehand
self.update_state(state) | ||
state = self.cached_state() | ||
|
||
if state is None: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No way that state can be None with the new logic as self.cached_state()
fetches self._acc_state
, which always has something populated.
src/biokbase/narrative/jobs/job.py
Outdated
# calling child_jobs may force an undesired data refresh even if | ||
# refresh is set to False |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is a bug in the current implementation
@@ -67,7 +67,7 @@ class JobRequest: | |||
|
|||
INPUT_TYPES = [PARAM["JOB_ID"], PARAM["JOB_ID_LIST"], PARAM["BATCH_ID"]] | |||
|
|||
def __init__(self, rq: dict): | |||
def __init__(self: "JobRequest", rq: dict): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
all edits to this file are adding typing
Codecov Report
Additional details and impacted files@@ Coverage Diff @@
## develop #3386 +/- ##
===========================================
+ Coverage 29.34% 29.35% +0.01%
===========================================
Files 497 497
Lines 50580 50569 -11
===========================================
+ Hits 14841 14843 +2
+ Misses 35739 35726 -13
... and 2 files with indirect coverage changes Continue to review full report in Codecov by Sentry.
|
job.update_state(states[job_id]) | ||
output_states[job_id] = job.output_state(refresh=False) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
update the job state and then retrieve the version suitable for output
9583b66
to
66788fe
Compare
@@ -6,7 +6,8 @@ | |||
import random | |||
import re | |||
import traceback | |||
from typing import Callable, Optional | |||
from collections.abc import Callable |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
all changes in this file are adding typing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why the switch from using Optional
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ruff likes type | None
rather than Optional[type]
del state[field] | ||
|
||
@staticmethod | ||
def query_ee2_state( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
delete this method, replace all uses with query_ee2_states
@@ -193,52 +188,59 @@ def __getattr__(self, name): | |||
"cell_id": lambda: self._acc_state.get("job_input", {}) | |||
.get("narrative_cell_info", {}) | |||
.get("cell_id", JOB_ATTR_DEFAULTS["cell_id"]), | |||
"child_jobs": lambda: copy.deepcopy( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
moved down
"job_id": lambda: self._acc_state.get("job_id"), | ||
"params": lambda: copy.deepcopy( | ||
self._acc_state.get("job_input", {}).get( | ||
"params", JOB_ATTR_DEFAULTS["params"] | ||
) | ||
), | ||
"retry_ids": lambda: copy.deepcopy( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
moved down
"retry_ids", JOB_ATTR_DEFAULTS["retry_ids"] | ||
) | ||
), | ||
"status": lambda force_refresh=True: copy.deepcopy( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
new
return "batch" if self.batch_job else self.app_spec()["info"]["name"] | ||
|
||
def was_terminal(self): | ||
def in_terminal_state(self: "Job") -> bool: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
renamed method
if "child_jobs" not in state: | ||
state["child_jobs"] = JOB_ATTR_DEFAULTS["child_jobs"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
access via JOB_ATTR_DEFAULTS
or otherwise there'll be an unnecessary call to ee2
from typing import List, Union | ||
|
||
from ipykernel.comm import Comm | ||
from typing import Union |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nearly all typing additions; there are a few minor edits which I will comment on.
@@ -21,6 +20,8 @@ | |||
|
|||
LOOKUP_TIMER_INTERVAL = 5 | |||
|
|||
INPUT_TYPES = [PARAM["JOB_ID"], PARAM["JOB_ID_LIST"], PARAM["BATCH_ID"]] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
move out of the JobRequest class
if job.in_terminal_state(): | ||
# job is already finished, will not change | ||
output_states[job_id] = job.output_state() | ||
elif job_id in states: | ||
job.update_state(states[job_id]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
edit this to update the job state and then call output_state()
job.update_state(fetched_states[job_id]) | ||
output_states[job_id] = job.output_state() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
again, update the state and then get the output state
jobs_to_lookup = [ | ||
job_id | ||
for job_id in self._running_jobs | ||
if self._running_jobs[job_id]["refresh"] or ignore_refresh_flag | ||
] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use a list comprehension
@@ -518,27 +535,27 @@ def get_job_logs( | |||
logs = logs[first_line:] | |||
else: | |||
(max_lines, logs) = job.log(first_line=first_line, num_lines=num_lines) | |||
|
|||
except Exception as e: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor reorganisation of logic
}, | ||
"wsid": 10538 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add the WSIDs into these results
lines.append({"is_error": 0, "line": f"This is line {str(i+1)}"}) | ||
return lines | ||
def log_gen(n_lines: int) -> list[dict[str, int | str]]: | ||
return [{"is_error": 0, "line": f"This is line {i+1}"} for i in range(n_lines)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use list comprehension
job_state = self.job_state_data.get( | ||
job_id, {"job_id": job_id, "status": "unmocked"} | ||
) | ||
job_state = self.job_state_data.get(job_id, {"job_id": job_id}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a default is supplied for "status", so we don't need the "unmocked" status value any more
job.refresh_state() | ||
|
||
def test_refresh_state__returns_none(self): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is no longer relevant as there's no way to provoke this error.
@@ -248,6 +242,12 @@ def mock_check_jobs(params): | |||
# expect there to be an error message added | |||
expected[job_id]["error"] = exc_msg | |||
|
|||
def mock_check_jobs(params): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
moved this code down a bit
8e6aef5
to
4faae24
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if the GenericSetViewer code changes were intended in this PR, but there's a couple minor things with them.
this.genericClient = new GenericClient(Config.url('service_wizard'), { | ||
token: this.authToken(), | ||
}); | ||
|
||
const bare_type = this.options._obj_info.bare_type[0]; | ||
const method = this.methodMap[bare_type]; | ||
const method = this.methodMap[bare_type] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
semicolon?
@@ -6,7 +6,8 @@ | |||
import random | |||
import re | |||
import traceback | |||
from typing import Callable, Optional | |||
from collections.abc import Callable |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why the switch from using Optional
?
console.warn('no _obj_info: input was') | ||
console.warn(options) | ||
return | ||
// if (options.obj_ref && options.wsName) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can probably be removed, as it's basically there below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was an accidental commit from something else I was troubleshooting. Not sure why I didn't see it when I was reviewing the PR! I'll remove it.
Removing some comments and an extraneous method; general tidying
4faae24
to
b982e48
Compare
Kudos, SonarCloud Quality Gate passed! 0 Bugs No Coverage information |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
Looks like the upload to codecov failed. AGAIN. |
Description of PR purpose/changes
This PR adds the user and wsid to the job objects returned by the narrative backend.
I added typing to quite a few of the methods so the diff looks bigger than it really is.
There's still some dodgy stuff going on with the job methods, but whatever. That can go in the next PR!
Jira Ticket / Issue
Related Jira ticket: https://kbase-jira.atlassian.net/browse/DATAUP-765
DATAUP-69 Adds a PR template
)Testing Instructions
Dev Checklist:
Updating Version and Release Notes (if applicable)