Cannot import package - from uplink server

What I’m trying to do:
I am trying to write code for the uplink server in a structured way like;

Screenshot 2022-10-03 15.02.26

So I am using subdirectories to keep things organized.

My main code is simply;

import anvil.server
from dotenv import load_dotenv
import os

from functions import *

load_dotenv()
UPLINK_KEY = os.getenv("UPLINK_KEY")
anvil.server.connect(UPLINK_KEY)
anvil.server.wait_forever()

What I’ve tried and what’s not working:
No matter how I organize the files I keep getting things like ‘module is not found’. I am sure that the file structure is correct on the server because I can import all the stuff I need and I run tests to make sure that the code works. So it runs on the server but it does not run if I call it from the anvil app. I have been looking at this for 2 days now… I hope someone has answer or an example that does work.

Code Sample:

reference_line, error = anvil.server.call('DO_upload_reference_line', self.project.epsg, file)

throws

ModuleNotFoundError: No module named ‘points’

  1. What is dotenv? (Is not listed in your snippet)
  2. What do you mean by “it runs on the server”?
  3. What do you mean by “it does not run if I call it from the anvil app”?
  1. dotenv is available from the python-dotenv package and will load the environment file for the uplink key
  2. if I run this code on the server where the code is hosted it will run without any problems. I would have expected the same import error if this was a problem of my code on the server
  3. if I call the function that is hosted on the server from an anvil app, the app will complain that it cannot find (for example) the points module. This seems to be weird since it is no problem to run that code on the server (for example in a test file where I call exactly the same function → no complaints about missing modules) but the anvil app keeps telling me that the points package is not found…

I hope this clears up my previous message :slight_smile:

Should all the code on the server mabe be in just one file?

The confusion increases…

You are talking about two servers here… what are those two servers?

If it’s the app complaining, then the problem is in the app, not in the uplink… what am I missing?

Ok, this took some time and was hard to explain but I found a solution. What I tried to do is make structured code on a Digital Ocean droplet that serves callable functions. I kept getting errors like missing package X or missing package __main__. I still do not know what exactly causes the problems but it will happen if you place code like

@anvil.server.portable_class
class ReferenceLine:
    def __init__(self, points=[]):
        """
        Args:
        points: List[ReferenceLinePoint]
        """
        self.points = points

between anvil.server.connect("your key") and anvil.server.wait_forever()

If you put it before anvil.server.connect("your key") there are no problems.

So I guess it all boils down to only define callable functions between anvil.server.connect("your key") and anvil.server.wait_forever()

I am using Python3.10 beta so maybe it is because of this but I am glad that I found a way around the error eventhough I still do not get the reason of the error.

This is dangerous, and it may be the cause of your problem.

Using a list (or any mutable) as default value for a function argument creates the list once and uses it on every call. That list is shared across all the calls that don’t provide that argument, so, if one execution changes the content of that list, the next execution runs with that content, not with an empty list as you would expect.

Sharing the content of the list across multiple calls is already bad enough in normal conditions, but here you are sharing it across calls running in different threads, and very likely your code is not thread safe, so… :boom:

One correct way would be this:

def __init__(self, points=None):
    if points is None:
        points = []
3 Likes