Add decorator hint to default comment in Server modules

Hi all - I was happy to find the solution to my problem with decorators here today.

I think you could help future users solve/avert this same problem even more rapidly by simply updating the default comment block for new server modules, something like this (maybe without the example, if you think it’s too much):

# This is a server module. It runs on the Anvil server,
# rather than in the user's browser.
#
# To allow anvil.server.call() to call functions here, we mark
# them with @anvil.server.callable.
# Here is an example - you can replace it with your own:
#
# @anvil.server.callable
# def say_hello(name):
#   print("Hello, " + name + "!")
#   return 42
#
# If you want to add your own decorators, for example to restrict a
# particular function to a permitted group of users, you'll need to add
# the name of the function explicitly as an argument e.g.
#
# @anvil.server.callable("say_hello")
# @my_decorator
# def say_hello(name):
#   print("Hello, " + name + "!")
#   return 42
#
# And here's an example for restricting access, in case you were
# wondering about that:
#
# def admin(func):
#   def wrapper(*args, **kwargs):
#       if not anvil.users.get_user()['admin']:
#         return
#       else:
#         return (func(*args, **kwargs))
#   return wrapper
#
# @anvil.server.callable("say_hello")
# @admin
# def say_hello(name):
#   print("Hello, " + name + "!")
#   return 42
#
# To make this work you'll also need to create a True/False type
# column in your Users table, call it "admin", and set it to True as needed.
3 Likes

I mean - I think this is overkill… one of the first things I do, whenever I open a new module, is delete the comments…

For new users that seems too much to me. Especially since they might not have met decorators yet…
IMO those comments should be enough to get started.
Perhaps a better place would be to add them to the docs in the advanced section…

https://anvil.works/docs/server#calling-server-functions-from-client-code

Which is linked whenever you click the top level of the server module…

Screen Shot 2020-04-28 at 08.07.48


As a note I also prefer using

from functools import wraps

on my server wrappers.
This way the name is preserved without having to pass an argument to @anvil.server.callable

Your example would become:

from functools import wraps
def admin(func):
  @wraps
  def wrapper(*args, **kwargs):
      if not anvil.users.get_user()['admin']:
        return
      else:
        return (func(*args, **kwargs))
  return wrapper

# no need to tell callable what the name is. @wraps preserves it
@anvil.server.callable 
@admin
def say_hello(name):
  print("Hello, " + name + "!")
  return 42

hidden away at the bottom of the link you posted

2 Likes

Hi Stu - yes functools is in my normal template for decorators too actually and gets round the problem entirely…

I think the reason I’ve suggested a couple of “in your face” Feature Requests recently is that for me they fall into the category of “I don’t know what I don’t know” for newcomers. I think some questions like restricting server functions to user groups, or setting up Git synchronisation back to Anvil are likely to apply to so many users, that if Anvil can do it in a simple (but non-guessable) way, it’s worth maybe shouting it from the rooftops rather than leave it to the user to diligently search through the Forums and hopefully find, understand, and/or choose from amongst the solutions(s) they find there.

Your suggestion of adding to the docs may be the most appropriate thing and would would give a user a better chance of stumbling on it and having that positive “Aha! Didn’t know you could do that so easily” moment :grinning: