How to replace anvil.server.callable

Hi all,

This is going to sound incredibly hacky, but hey, I’m a hack…

I want to replace the @anvil.server.callable with my own version of @anvil.server.callable (that adds some other bits).

Ideally I’d like to do this wherever a server module is importing anvil.server (so all my existing functions/methods are affected).

Is there some way of doing this without going through each module to import my own overriding version and remembering to do that every time I create a new one?

Thanks.

I don’t think there is a way in the online editor, but alot of offline editors (I use zed) have a search all files / replace all function.

1 Like

What about creating your own decorator @masikh_server_callable that wraps the official one and adds your functionality?

I got it with a metaclass that has a __getattr__ method in a Module:

import anvil.server


class Meta(type):
  def __getattr__(cls, name):
    return getattr(anvil.server, name)


class alternate_server(metaclass=Meta):
  @classmethod
  def callable(cls, *args, **kwargs):
    return anvil.server.call(args[0])

Not exactly what you were asking for, but it basically allows find and replace the whole code base to replace anvil.server imports with yours.

1 Like

I had considered this but as I add more devs I wanted to be certain that the anvil.server.callable was not being used directly. I think I’m over optimising. I know I can override the object and just import the module at the top of each page so that if anvil.server.callable is used it is my version but I’m trying to manipulate the anvil.server module/import in some way so that callable is always my version of callable wherever I am in the server code.

Thanks. I’ve already found a way to replace the anvil.server.callable within a server module and then just import that into any module that I have (after importing anvil.server). However I’m trying to manipulate the anvil.server import itself so that my version of callable is always imported/triggered wherever anvil.server is imported and anvil.server.callable is used.

I know it’s over the top and I will just do it another way if needed but hoped there was some way.

Have you tried setting anvil.server.callable = my_new_decorator? You’d need to do that after importing anvil.server in all your server modules, so it’s nowhere near automatic, but sounds like what you’re trying to do.

Personally, I’d create a new decorator and use that so it’s obvious that it isn’t the vanilla decorate being used, but Python does support patching things like this if you feel the need.

Yes, I actually made a separate module so all I have to do is import and it will replace anvil.server.callable but again that doesn’t completely solve my problem.

Hmm… this kind of monkey patching is usually direct path to bad maintainability, and changing the behavior of official tools without telling new devs is just bad practice.

I see two issues here:

  1. How to add features to the server callable decorator
    Solution: create a wrapper decorator that adds those features

  2. How to make sure new devs use the custom decorator
    Solution: training, communication and audit tools. A script that nightly scans all the source code of all the apps and sends you/the boss an email when a transgressor is found. This will prompt an additional training session to ensure developers understand that they are using a custom decorator instead of the official one and what enhancements it provides.

1 Like

You’re right of course.

I guess my monkey patching will have to wait for another opportunity.