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

feat(api): make modules aware of available fw updates in file system #4856

Merged
merged 16 commits into from
Jan 28, 2020

Conversation

b-cooper
Copy link
Contributor

@b-cooper b-cooper commented Jan 24, 2020

overview

Creates a generalized approach for determining whether an attached module is capable of being
updated, based on the module firmware artifacts bundled in the filesystem. In addition to adding
this functionality, it includes a couple of refactors to dedupe common module subclass
responsibilities. In debugging this branch, I also included some loop level error handling so
exceptions in asyncio tasks (e.g. module instance creation) don't get swallowed.

re #4575

changelog

review requests

Creates a generalized approach for determining whether an attached module is capable of being
updated, based on the module firmware artifacts bundled in the filesystem. In addition to adding
this functionality, it includes a couple of refactors to dedupe common module subclass
responsibilities. In debugging this branch, I also included some loop level error handling so
exceptions in asyncio tasks (e.g. module instance creation) don't get swallowed.

re #4575
@b-cooper b-cooper force-pushed the api_mod-fw-update-from-local-file branch from aebf2db to 5f370a2 Compare January 24, 2020 22:03
@b-cooper b-cooper changed the title Api mod fw update from local file feat(api): make modules aware of available fw updates in file system Jan 24, 2020
@b-cooper b-cooper requested review from a team January 24, 2020 22:11
@b-cooper b-cooper added api Affects the `api` project feature Ticket is a feature request / PR introduces a feature labels Jan 24, 2020
@codecov
Copy link

codecov bot commented Jan 24, 2020

Codecov Report

Merging #4856 into edge will decrease coverage by 0.18%.
The diff coverage is n/a.

Impacted file tree graph

@@            Coverage Diff             @@
##             edge    #4856      +/-   ##
==========================================
- Coverage   57.97%   57.78%   -0.19%     
==========================================
  Files         960      962       +2     
  Lines       26311    26639     +328     
==========================================
+ Hits        15253    15393     +140     
- Misses      11058    11246     +188
Impacted Files Coverage Δ
opentrons/hardware_control/modules/types.py 87.5% <0%> (-12.5%) ⬇️
opentrons/main.py 34.61% <0%> (-0.63%) ⬇️
opentrons/hardware_control/modules/tempdeck.py 80.31% <0%> (-0.61%) ⬇️
opentrons/hardware_control/modules/magdeck.py 87.5% <0%> (-0.47%) ⬇️
opentrons/hardware_control/modules/thermocycler.py 90.04% <0%> (-0.19%) ⬇️
opentrons/config/__init__.py 58.11% <0%> (-0.09%) ⬇️
...er/src/components/modals/EditModulesModal/index.js 0% <0%> (ø) ⬆️
shared-data/js/constants.js 100% <0%> (ø) ⬆️
...list/formLevel/getNextDefaultMagnetAction/index.js 100% <0%> (ø) ⬆️
...ol-designer/src/components/modules/CrashInfoBox.js 0% <0%> (ø) ⬆️
... and 13 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update b388c4e...e648312. Read the comment docs.

Copy link
Member

@sfoster1 sfoster1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Early thoughts on the draft. Structurally it looks ok but there's some inline comments

def use_or_initialize_loop(loop: Optional[asyncio.AbstractEventLoop]):
checked_loop = loop or asyncio.get_event_loop()

# TODO: BC 2020-01-24 use loop.add_signal_handler for proper cleanup
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i give this a big maybe - signal handlers have to be added from the main thread every time, and some signals can't be handled anyway.

@@ -44,6 +44,19 @@ def _log_call_inner(*args, **kwargs):
return _log_call_inner


def handle_loop_exception(loop: asyncio.AbstractEventLoop, context):
msg = context.get("exception", context["message"])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bit of a nitpick but we should really log both the exception and the message. Per the docs, neither is optional so we shouldn't have to use get here.

@@ -44,6 +44,19 @@ def _log_call_inner(*args, **kwargs):
return _log_call_inner


def handle_loop_exception(loop: asyncio.AbstractEventLoop, context):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

context could probably be typed as Dict[str, Any]

mod_log.error(f"Caught exception: {msg}")


def use_or_initialize_loop(loop: Optional[asyncio.AbstractEventLoop]):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Annotate return type as asyncio.AbstractEventLoop

simulating: bool = False,
loop: asyncio.AbstractEventLoop = None) -> None:
self._port = port
if None is loop:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can use that helper function here

fw_dir = CONFIG['robot_firmware_dir']
fw_resources = [fw_dir / item for item in os.listdir(fw_dir)]
for fw_resource in fw_resources:
matches = MODULE_FW_RE.search(str(fw_resource))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could and probably should do a match on fw_resource.name

def has_available_update(self) -> bool:
""" Return whether a newer firmware file is available """
if self._device_info is not None:
raw_device_version = self._device_info.get('version', None)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In what conditions do we expect device_info to be valid but not have a version? Also we can just do .get('version'), returning None on key miss is implicit

else:
self._loop = loop
self._device_info = None
self._available_update_version: Optional[str] = None
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO we should bundle these two into a named tuple or something and have a function that returns Optional[ModuleFirmware] so we can't possibly be in a one-but-not-the-other situation

resources.extend([ROBOT_FIRMWARE_DIR / item
for item in os.listdir(ROBOT_FIRMWARE_DIR)])
fw_dir = CONFIG['robot_firmware_dir']
resources.extend([fw_dir / item for item in os.listdir(fw_dir)])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can be resources.extend(fw_dir.iterdir()) (or resources.extend(list(fw_dir.iterdir())) if extend doesn't iterate)

@@ -402,6 +395,10 @@ def set_loop(self, newLoop):
def port(self):
return self._port

@property
def available_update_path(self):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needs a return value annotation

Copy link
Member

@sfoster1 sfoster1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking really good!

@b-cooper b-cooper marked this pull request as ready for review January 28, 2020 19:54
@b-cooper b-cooper merged commit 4ede522 into edge Jan 28, 2020
@b-cooper b-cooper deleted the api_mod-fw-update-from-local-file branch January 28, 2020 21:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api Affects the `api` project feature Ticket is a feature request / PR introduces a feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants