I’m storing settings to Loki logging aggregation, and Microsoft Graph to a setting file in the server, which is working fine by opening the file in servermodule :
def get_setting(key):
with open("settings.json", "r") as readfile:
settings = json.load(readfile)
value = settings[key]
if not value:
value = r"http://localhost:4444" if key == "foxpro_connection" else ""
settings[key] = value
with open("settings.json", "w") as writefile:
json.dump(settings, writefile)
return value
However, the file is inaccessible from the client.
So I tried using Static Data Files, but getting error from the client : SuspensionError: Cannot call a function that blocks or suspends here.
Anybody has suggestion on where to put a global setting file like that? I was thinking about App Secret, but it is not easy to change the value as it is changing it in text file settings.json.
Code Sample: servermodule.py
from anvil.files import data_files
@anvil.server.callable
def return_text_from_file():
# Read the contents of a file
with open(data_files['settings.json']) as f:
text = f.read()
return text
client_code\Global.py
from .LokiModule import LokiLogger
log = LokiLogger()
client_code\LokiModule.py
def get_setting(group):
# Using data_files call from server module - causing SuspensionError on anvil.server.call
file_text = anvil.server.call("return_text_from_file")
setting = dict(file_text)
class LokiLogger:
# Get settings
loki_setting = get_setting("loki")
Thank you for the quick reply. Sorry my post wasn’t that clear. I edited it to show the module name. So I have the anvil.server.call in the LokiModule.py get_setting function. But still getting the SuspensionError.
So if I understand it correctly, I cannot have the global variable log, in the Global.py, because it is calling a blocking code (anvil.files.data_files). So I have to move the log variable to the modules. Did I hit the nail on the head?
class LokiLogger:
# Get settings
setting = Setting()
loki_setting = setting.get_setting("loki") # I am a call that suspends
loki_url = loki_setting["loki_url"]
loki_user = loki_setting["loki_user"]
loki_pass = loki_setting["loki_pass"]
You need to hoist this into the module scope
setting = Setting()
loki_setting = setting.get_setting("loki") # i'm in the module scope I can susupend
class LokiLogger:
loki_url = loki_setting["loki_url"]
loki_user = loki_setting["loki_user"]
loki_pass = loki_setting["loki_pass"]
Yeap it’s also true for forms. But note we’re only talking about the class setup here. Any code inside methods can suspend just fine.
If more folks had hit this issue it’s likely something we would have prioritised (you would know if you hit it because your Form/class would never get created and you’d have hit the above error at load time). But it’s not a pattern that comes up too often.
Most of the time the top level class body definitions tend to be simple and then more complicated fetches happen in the __init__.
If the above class was a singleton where the setup happened in the __init__ then we wouldn’t be having this conversation. That’s the typical pattern for an Anvil form at least.
Ok, in class body, not just in class, I missed that.
I don’t think this is worth investing any time, other than showing an error message that clearly describes the limitation. For example replacing “here” with “in the class body” in the error message “SuspensionError: Cannot call a function that blocks or suspends here” would be good enough.