From e9d08e546649bc847938881c997648dd257faaf0 Mon Sep 17 00:00:00 2001 From: Blai Peidro Date: Mon, 14 Sep 2026 00:03:38 +0200 Subject: [PATCH] feat: declare the attribute contracts the cancel and test mixins rely on HasCancel and HasTest read self.page and self.resource, which the CustomAction they are mixed into supplies. AssociationMixin in the same file has carried the annotations describing that since #50, and these two arrived in #62 and #65 without them, so the type checker reported seven unresolved attributes for a contract the file already knew how to state. Annotations rather than assignments, for the reason the comment on AssociationMixin gives: an assignment would create a class attribute that shadows the real one at runtime. Verified that neither name appears in vars() on either class, and that both land in __annotations__. ty goes from 35 diagnostics to 28. The one remaining in this file, the Launchable.add_arguments override on line 260, predates all of this. --- ascenderkit/cli/custom.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/ascenderkit/cli/custom.py b/ascenderkit/cli/custom.py index dfc705d..75c3224 100644 --- a/ascenderkit/cli/custom.py +++ b/ascenderkit/cli/custom.py @@ -317,6 +317,12 @@ class AdhocCommandStdout(HasStdout, CustomAction): class HasCancel: """Stopping a job that is still pending or running.""" + # Supplied by the CustomAction this is mixed into. Annotations rather than + # assignments: they describe the contract without creating class attributes + # that would shadow the real ones. + page: 'api.pages.Page' + resource: str + action = 'cancel' def add_arguments(self, parser, resource_options_parser): @@ -410,6 +416,12 @@ def perform(self): class HasTest: """Asking the platform to exercise a thing rather than describe it.""" + # Supplied by the CustomAction this is mixed into. Annotations rather than + # assignments: they describe the contract without creating class attributes + # that would shadow the real ones. + page: 'api.pages.Page' + resource: str + action = 'test' def add_arguments(self, parser, resource_options_parser):