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

Fix pytest #76

Merged
merged 17 commits into from Jun 16, 2022
Merged

Fix pytest #76

merged 17 commits into from Jun 16, 2022

Conversation

kralka
Copy link
Collaborator

@kralka kralka commented Jun 8, 2022

Part of issue #38

Part of issue google#38
@kralka kralka marked this pull request as draft June 8, 2022 08:05
@kralka kralka requested a review from jmichelp June 8, 2022 10:48
@kralka kralka marked this pull request as ready for review June 8, 2022 10:48
@@ -299,7 +299,7 @@ def _dict_repr(self):
return ret


class Pico6424E(ChipWhispererCommonInterface):
class Pico6424E(cw.capture.scopes.OpenADC):
Copy link
Collaborator

Choose a reason for hiding this comment

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

OpenADC is the scope that is embedded on the Chipwhisperer board.
I don't think it's a good idea to inherit from it.

They used to have a BaseScope class, implementing the basic API that any scope is expected to have to work with their software stack (con(), dis(), arm(), capture(), get_last_trace(), __str__(), __dict_repr__()) but it seems it's gone.
So we'll have to revive it on our side :(

@@ -30,7 +30,7 @@ def __init__(self, samples: int, offset: int):
offset: Number of samples to wait after trigger event occurred before
starting recording data.
"""
self._scope: Optional[ChipWhispererCommonInterface] = None
self._scope: Optional[cw.capture.scopes.ScopeTypes] = None
Copy link
Collaborator

Choose a reason for hiding this comment

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

See my previous comment.

It seems we'll need to define our own abstract class with the API that any scope should implement to work with our capture pipeline and have a class that makes OpenADC compatible with it (we don't care about CWNano in our case)

@kralka kralka marked this pull request as draft June 8, 2022 16:58
from chipwhisperer.capture.api.cwcommon import ChipWhispererCommonInterface


class ScopeTemplate(ChipWhispererCommonInterface):
Copy link
Collaborator

Choose a reason for hiding this comment

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

Don't derive from ChipwhispererCommonInterface. The name is a bit misleading but if you look at the methods it has, they aren't related to the scope at all (firmware updates, etc.).

We should simply get our class, then have a ChipwhispererScope that derives from ScopeTemplate and OpenADC

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I am a bit lost here. I don't understand where a ChipwhispererScope that derives from ScopeTemplate and OpenADC comes into.

On the cw side: OpenADC derives from ChipwhispererCommonInterface [1]. And cw.capture_trace argument scope [2] has type ScopeTypes = Union[OpenADC, CWNano] (this is why I was afraid that mypy would consider passing any other type to be an error).

On scaaml side: We have only context managers (CWScope, DefaultCWScope, PicoScope) which have .scope property. And a single scope class acting as a ScopeTypes (Pico6424E).

@kralka kralka requested a review from jmichelp June 14, 2022 09:59
@kralka kralka marked this pull request as ready for review June 14, 2022 10:02
@@ -299,7 +301,7 @@ def _dict_repr(self):
return ret


class Pico6424E(ChipWhispererCommonInterface):
class Pico6424E(ScopeTemplate, OpenADC):
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why is the Picoscope inheriting from OpenADC? It should only inherit from ScopeTemplate.

And we should have a class, for example ChipwhispererScope which inherits from both ScopeTemplate and OpenADC. This class being used to get the scope in our API

self._scope: Optional[ChipWhispererCommonInterface] = None
self._samples = samples
self._offset = offset
self._scope: Optional[OpenADC] = None
Copy link
Collaborator

Choose a reason for hiding this comment

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

This should be typed a Optional[ScopeTemplate] or just ScopeTemplate because we may want the scope to be mandatory maybe?

@kralka kralka requested a review from jmichelp June 14, 2022 11:16
@@ -39,7 +46,7 @@ def arm(self):
"""Setup scope to begin capture when triggered."""

@abstractmethod
def capture(self):
def capture(self, poll_done: bool = False) -> bool:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same thing here regarding prototype. I don't see what poll_done would bring. Removing it from the function signature and putting the default value in Chipwhisperer.capture() should do the trick for us. It's not a value we change.
If later we need extra arguments to support a specific scope, we can revisit it by adding **kwargs to the function.

Please document return value.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Same error with incompatible definition. ChipwhispererScope inherits both OpenADC and ScopeTemplate thus the base classes must have same signatures. Am I not understanding something?

@@ -28,7 +28,8 @@ def __init__(self):
"""Initialize the base."""

@abstractmethod
def con(self,
def con(
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think that for the abstraction, def con(self, device_identifier: Optional[str] = None, **kwargs) should be an appropriate signature.
device_identifier being a way to disambiguate which scope we want it case multiple scopes from the same model are plugged id and detected. Default behavior when set to None is to connect to the first one found.
You can decide to either put **kwargs as part of the signature or simply remove it because we don't need it at the moment for the scopes we support. When we'll need it it will be easy to add it anyway.

This means that we'll have to implement def con() for ChipwhispererScope so that it passes on the correct default values to super().con().

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

With your signature I am getting error: Definition of "con" in base class "ScopeTemplate" is incompatible with definition in base class "OpenADC"

Copy link
Collaborator

Choose a reason for hiding this comment

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

Argh. Forgot that Python doesn't support overloading functions.
This means we would have to remove the inheritance from OpenADC and wrap it instead:

class ChipwhispererScope(ScopeTemplate):
  def __init__(self):
    self._openadc: OpenADC = cw.scope()  # This always returns a scope or raises an exception IIRC

  def con(self, device_identifier: Optional[str]):
    self._openadc.con(sn=device_identifier, ...)

  def capture(self) -> bool:
    return self._openadc.capture(pool_done=False)

  def arm(self):
    self._openadc.arm()
...

Hopefully mypy won't complain about it somewhere else.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I think Python supports changing the signature when inheriting (Pico6424E.con signature is different from ScopeTemplate.con signature), but when doing multiple inheritance the signatures of superclasses must match. Other thing is that cw.capture_trace expects the argument scope to be of type Union[OpenADC, CWNano].

I do not understand the role of ChipwhispererScope in your last code snippet. We have a CWScope and DefaultCWScope context managers (auto-con/dis the OpenADC) and then we have a Pico6424E which plays a role of an object that behaves as an OpenADC (and is passed to cw API instead of OpenADC), then we have a context-manager with PicoScope.scope is Pico6424E. Finally we have reimplemented ScopeTemplate which is an abstract class capturing the cw scope interface.

Over all I agree with your comments in the sense of not polluting our API with unnecessary compatibility with CW. The thing is that I am not sure how to do that and still have a working typechecking. And I also agree that typechecking is far from perfect in the current PR (my idea was fix the workflows and then slowly improve the rest).

@kralka kralka requested a review from jmichelp June 14, 2022 14:24
@kralka
Copy link
Collaborator Author

kralka commented Jun 16, 2022

I suggest to resolve the inheritance question in another PR (issue: #79)

@kralka kralka requested a review from invernizzi June 16, 2022 08:57
Copy link
Member

@invernizzi invernizzi left a comment

Choose a reason for hiding this comment

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

Thank you for all the changes, Karel!

@kralka kralka merged commit 09fb7e0 into google:master Jun 16, 2022
@kralka kralka deleted the fix_pytest branch August 24, 2022 09:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants