-
Notifications
You must be signed in to change notification settings - Fork 2
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
refactor: disallow calling service methods directly #124
Conversation
Codecov Report
Additional details and impacted files
☔ View full report in Codecov by Sentry. |
) -> Callable[[C, ServiceMethodArg], T_ServiceType]: ... | ||
|
||
|
||
def autoid_service(fn: Any) -> Any: |
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.
is this functionally the same as a single function with a Union
or the two types above, or is this falling back to allowing all types for fn
? or is it something else?
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.
- It's not falling back to allowing all types for
fn
. Only calls toautoid_service
that match one of the overloads will be allowed by the static analyser. - I did not try
Union
instead of overloading in this case. But, before switchingservice
to class, I tried the following, and it created problems with inferringT_ServiceType
. Switching to class + overloading solved them
def service(
service_id: ServiceId[T_ServiceType],
) -> Callable[[Callable[[C], T_ServiceType] | Callable[[C, ServiceType], T_ServiceType]], Callable[P, T_ServiceType]]
@@ -48,4 +49,5 @@ | |||
"group", | |||
"method_service_id", | |||
"service", | |||
"ServiceMethodArg", |
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.
does this have to be exposed?
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.
If we want to allow external packages to add decorators that interact with the service decorators, then I think it needs to be exposed.
It's needed in order to type the additional decorators I add in rats-processors (task
and pipeline
).
as far as the general idea of this pr goes, i'm unsure of the value in this since it can be so easily ignored and we're using a trick to try and prevent calling the decorated function. i'm also not a fan of the decorators turning into classes, i think it makes reading them a bit more difficult. could we sit on this for a bit and see what patterns we develop for the services layer? i don't yet have a clear view of what changes to the apis will help us scale to new use cases but i imagine we will find the rough edges over the next ~3 months while we try to use these things in more places. |
If we decide that it is wrong to call methods decorated by
@service
and similar decorators directly, this PR would enforce that both statically and dynamically.It does so by having the decorators add a dummy argument of type
ServiceMethodArg
to the methods.ServiceMethodArg
is exposed publicly so downstream packages can wrap over these decorators with decorators of their own (e.g.@task
and@pipeline
). However, the constructor ofServiceMethodArg
takes a dummy parameter of type_ServiceMethodArgArg
which is private, so only the_annotations
module can create aServiceMethodArg
, and therefore only that module can call the annotated methods. I think.Not sure we actually want to go this way.