Okay, you may be onto something. While the code is in a Client Module, and not within Python function, it gets kicked off like this from the Backend (because it’s part of a portable class implementation):
# In a Server Module:
from ..utils_frontend.anvil_portable_classes import MyRow
[ ... snip ... ]
MyRow(**d) # Where 'd' is a simple dict()
(Note: I updated my original question with an additional statement).
So it’s more involved than I originally explained (not realizing). There’s some back-and-front interaction involved.
Is this module level code, executed when the module is imported?
Then making it lazy should work.
Something like this:
_col_names = {}
def col_names(table_name):
if table_name not in _col_names:
table = getattr(app_tables, table_name)
columns = list(table.list_columns())
col_names = [column['name'] for column in columns]
_col_names[table_name] = col_names
return _col_names[table_name]
This version can be used with any table. You can simplify it and make it work only with one table.
The point is (I think) you can’t execute blocking code during the import. Making it lazy you delay the execution of the blocking code at a later point, after the import has been completed.
My generic version could have a negative impact on the performance if you plan to call it multiple times with multiple tables, because it will trigger one round trip per table.
If that is the case, then it’s better to make one get_all_tables_columns server function that collects all the columns for all the tables that you are going to eventually need in one round trip.
Or a client side function that accepts a list of table names, calls a server function, the server function collects all the columns for all the tables and returns them all in one shot.
Paying so much attention to performance is a little bit against the Anvil philosophy, where being productive is more important than having the best performance possible, but I think it’s a piece information that can turn useful the day the performance become the bottleneck.
First, thanks for the philosophy note. It makes sense to me – I’ve not been able to quickly make inroads on a high-value app until I discovered Anvil.
The lazy load approach as well as one-round-trip to collect all table-column names needed are good strategies. Let me work on this (in a few days), and post back. Thank you!
Just jumping in here to say this isn’t true! Ordinary imports can block. Likewise, that code all seems fairly normal, so I’d suggest @nmvega work a bit more to narrow down where exactly the SuspensionError is occurring. Which line is it thrown from? What happens if you separate out each operation (eg make an intermediate variable for the namedtuple)? What is triggering the import and/or calling that code?
Best, of course, would be if you could produce a cut-down clonable example that illustrates the problem, so we can see for ourselves.
I’ll work on it perhaps tomorrow and provide just some essential code to reproduce the exception (if I don’t narrow it down before then). Either way, I’ll report back.
# ===========================
# In: MyForm
# ===========================
from ._anvil_designer import MyFormTemplate
import numbers # This is fine here. But not later on.
class MyForm(MyFormTemplate):
# =====================================================
from ..runtime_event_handlers import an_event_handler
# =====================================================
def __init__(self, **properties):
self.init_components(**properties)
and:
# ===========================
# In: runtime_event_handlers
# ===========================
from collections import namedtuple # This is fine.
import numbers # <---- Emits SuspensionError.
def an_event_handler(self, **event_args): # Never reached.
pass
Set MyForm as the Startup Form and launch it. You should arrive at a SuspensionError.
I have workarounds to avoid using import numbers, but I feel this should work.
NotImplementedImportError: locale is not yet implemented in Skulpt
I only need locale so float() doesn’t complain about commas when trying to convert. But this is for a strictly U.S. use-case, so I can cheat (with a TODO note) and just remove the commas.
Is there a page listing what Python packages / modules are supported in Skulpt? This way I know not to try something. I did a quick search, but nothing immediately pops up.
EDIT: @stucork Per your below suggestion, I submitted the request here.
Might be best to ask the other questions in new threads as we’re moving off topic here.
The list of available skulpt packages would be a good feature request.