-
Notifications
You must be signed in to change notification settings - Fork 68
Remove ability to reference methods as Functions directly on Cls #3648
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -863,18 +863,28 @@ def __call__(self, *args, **kwargs) -> _Obj: | |
) | ||
|
||
def __getattr__(self, k): | ||
# TODO: remove this method - access to attributes on classes (not instances) should be discouraged | ||
if not self._is_local() or k in self._method_partials: | ||
# if not local (== k *could* be a method) or it is local and we know k is a method | ||
deprecation_warning( | ||
(2025, 1, 13), | ||
"Calling a method on an uninstantiated class will soon be deprecated; " | ||
"update your code to instantiate the class first, i.e.:\n" | ||
f"{self._name}().{k} instead of {self._name}.{k}", | ||
if self._user_cls is not None: | ||
# local class, we can check if there are static attributes and let the user access them | ||
# except if they are PartialFunction (i.e. methods) | ||
v = getattr(self._user_cls, k) | ||
if not isinstance(v, modal.partial_function.PartialFunction): | ||
return v | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bug: AttributeError and Import Issue in Local ClassesWhen accessing attributes on local classes, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Intentional, we want a regular AttributeError in those cases |
||
|
||
# We create a synthetic dummy Function that is guaranteed to raise an AttributeError when | ||
# a user tries to use any of its "live methods" - this lets us raise exceptions for users | ||
# only if they try to access methods on a Cls as if they were methods on the instance. | ||
async def method_loader(fun: _Function, resolver: Resolver, existing_object_id: Optional[str]): | ||
raise AttributeError( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure what the right exception type is. Something to clean up eventually? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure I'm still not sure exactly what error type to captures the modal-specific issue. It turns out that |
||
"You can't access methods on a Cls directly - Did you forget to instantiate the class first?\n" | ||
"e.g. instead of MyClass.method.remote(), do MyClass().method.remote()" | ||
) | ||
return getattr(self(), k) | ||
# non-method attribute access on local class - arguably shouldn't be used either: | ||
return getattr(self._user_cls, k) | ||
|
||
return _Function._from_loader( | ||
method_loader, | ||
rep=f"UnboundMethod({self._name}.{k})", | ||
deps=lambda: [], | ||
hydrate_lazily=True, | ||
) | ||
|
||
def _is_local(self) -> bool: | ||
return self._user_cls is not 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.
😵💫 double checking that we wouldn't expect these to be the internal
_PartialFunction
type here.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.
Yeah this is a bit tbh 😵 But
@method
is itself a synchronicity-wrapped method, so it will output wrapped types (PartialFunction in this case) that will be part of the class namespace of the underlying class, which is what we're getting here. It would break the tests if this wasn't so, so even if this was to change we would detect it in CI :)