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

test: add type hints to test_framework #1025

Merged
merged 14 commits into from
Oct 3, 2023

Conversation

tonyandrewmeyer
Copy link
Contributor

@tonyandrewmeyer tonyandrewmeyer commented Oct 2, 2023

  • Change the type of Handle's key (in __init__ and nest() and the property) to explicitly allow `None
  • Add a CHANGES.md file to document changes (backfilled only to 2.7)
  • Tidy up the type hinting of BoundStoredState.__getattr__ - multiple overloads need to be provided, and once that's done the ignores can be removed (and a bunch of type issues in the tests get resolved)
  • Ignore type where creating an object that's only partially complete, but the test only requires that much and fully creating it would be a lot of extra code for no real gain
  • Where's it's simple to do, pass the required attributes rather than None
  • Ignore types where we're checking handling of invalid types
  • Add casts around the very dynamic snapshot/restore functionality
  • For a couple of the "list of test cases" situations, move the documentation of what each element in the test case is to a new type definition that covers both what was there before and the (rough) expected type
  • Sprinkle type hints where required for pyright to be happy

Partially addresses #1007

Copy link
Collaborator

@benhoyt benhoyt left a comment

Choose a reason for hiding this comment

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

Looks good, thanks. A couple of questions and a few small changes requested.

ops/framework.py Show resolved Hide resolved
self.assertIn(
"WARNING:ops.framework:deprecated: Framework now takes a Storage not a path",
cm.output)
self.assertIsInstance(framework._storage, SQLiteStorage)

def test_handle_path(self):
cases = [
(ops.Handle(None, "root", None), "root"),
(ops.Handle(None, "root", 'test1'), "root[test1]"),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Unless I'm missing something, I'm a bit nervous that we're changing / removing these test cases. If anything I think we should keep the existing ones (changing the typing shouldn't change them) and add a couple of new ones testing the additional cases.

Copy link
Contributor Author

@tonyandrewmeyer tonyandrewmeyer Oct 2, 2023

Choose a reason for hiding this comment

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

The Handle.__init__ code is like this:

    def __init__(self, parent: Optional[Union['Handle', 'Object']], kind: str, key: str):
        ...
        self._key = key
        ...
            if key:
                self._path = f"{parent}/{kind}[{key}]"
            else:
                self._path = f"{parent}/{kind}"

The docs say (my emphasis):

The handle key is a string uniquely identifying the object.

The key is also used for hashing and equality checks (None is fine in either of those situations, but so are other non-string things). It's also a public member, and I don't have the experience to know how that's generally used, however, it does claim to be a string as well:

    @property
    def key(self) -> str:

This seems messy to me. Shouldn't we either have the type signature and documentation match the behaviour and accept str|None (the docs could say that this should not be done), or have the implementation match the type signature and documentation and reject None as an invalid value for key (maybe this is tricky with backwards compatibility?)?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Hmm, yeah. From looking at the code, I think key should have been an Optional[str] all along -- the fact that is was typed as str was I think an oversight. The if key would handle empty string as well, but I think None would be the intention.

I've found one charm that passes None as the key argument to Handle.

So I think we should change Handle's key arg to Optional[str], and same for nest's key argument. Those should be perfectly backwards-compatible changes, as we're expanding the type.

I also think we should change the key property's type to be Optional[str]. That isn't quite a backward-compatible change (typing-wise), because code that accesses the property will then have to assert key is not None to type check. But I've done a quick search and I can't see any charms using that property (it's a bit advanced/arcane to use Handle directly in the first place, let alone access handle.key).

So I think it's safe to change and we should do it. If you want, we could start a file CHANGES.txt that we use to record notes and breaking changes for the upcoming release, so we remember.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done - lmk if you'd prefer a particular format for the changes file.

test/test_framework.py Show resolved Hide resolved
test/test_framework.py Outdated Show resolved Hide resolved
test/test_framework.py Outdated Show resolved Hide resolved
test/test_framework.py Show resolved Hide resolved
test/test_framework.py Show resolved Hide resolved
test/test_framework.py Outdated Show resolved Hide resolved
Copy link
Collaborator

@benhoyt benhoyt left a comment

Choose a reason for hiding this comment

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

All looks good, thanks!

@benhoyt benhoyt merged commit 2794449 into canonical:main Oct 3, 2023
20 checks passed
@tonyandrewmeyer tonyandrewmeyer deleted the pyright-test_framework-1007 branch October 3, 2023 20:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants