Writing image(s) into user's desired directory on his own PC

From quiet a long time, I’m trying to write images into user’s desired directory. It works fine for me. But when people use the publish link to use my website and provide their desired path, it doesn’t work for them.

I’m unable to understand the reason. Maybe anvil is unable to write images (put images into user’s PC). If so, is there any alternative way to do this?

Can you show us that part of your code? It’s hard to tell what part is broken when we can’t even see the parts! :wink:

I doubt that it’s Anvil. Web browsers have built-in security, to protect the user’s PC. The user has to manually start and/or accept each download. For each download, they may choose where to put the resulting file, and what to call it.

If we didn’t have that manual intervention from the user, bad code could rapidly destroy the user’s existing files, and cripple their PC (or worse), before they could even blink.

1 Like

For security reasons, all web frameworks are forbided to interact directly with user files.

You can generate images in the server and make users click a button to download them to their computers

@p.colbert @Tony.Nguyen Thank you for your response.

I’m building a website for user where he can train a machine learning model, then download the model right away.

When i published my website, the downloading of model was working fine. But when i opened the project yesterday, it was working for me. But not for my friend (who was using my website from the published link). My friend got this error:

AnvilWrappedError: Failed to create a directory: C:\Users/m/; Permission denied

My code:

@anvil.server.callable
def download(path):
    if m is not None:
        m.save(path)
        

I don’t understand how can it throw an error when it was working perfectly some days earlier? :pensive:

Thinking of a solution, is there any way to ask a user for permission and then let him download the model into his PC’s folder?

This situation is also somehow related to the main question i posted.

Yes. See “Downloading” under * Uploading and downloading files.

As for

consider where your download function is running. Since it’s working fine for you, it would appear that this function is running on your computer – not your friend’s. Naturally, when this function runs, it will try to save the file on the only computer it has access to: yours.

The model which is being downloaded consists of 3 things - “variable” folder, “asset” folder, “saved_model.pb” file. How can i move them forward to anvil, then to the user?

I tried this - Anvil code:

  def button_3_click(self, **event_args):
    text_file = anvil.server.call('download' ,self.d.text)
    anvil.media.download(text_file)
    pass

Server code:

@anvil.server.callable
def download(path):
    if m is not None:
        m.save(path)

Got this error:

Exception: Argument to anvil.download() must be a Media object
at Form1, line 30

I’ve given path of folder where user wants to save the model as an argument. Taking input path is necessary to save the model. But anvil is not accepting this argument.

https://anvil.works/build#clone:EQECZML276BK6KRD=OCZH3GTIZ5XWHZ6IK2V3USW6

Is there more to the ‘download_m’ function?
It does not look like it returns anything, if not, than the result of the variable text_file in ‘text_file = anvil.server.call(‘download_m’)’ would = None

What is m in download_m() that it has a .save method? Like others have said, I think maybe that is the part that is saving to your computer and not the clients browser?

I think we might still be missing a piece of info somewhere if it works for you.

No, this is it. This function lets me download the entire model.

I think you’re right, i missed the RETURN keyword. This is my code now:

@anvil.server.callable
def download(path):
    if m is not None:
        return m.save(path)
  def button_2_click(self, **event_args):
    text_file = anvil.server.call('download' ,self.d.text)
    anvil.media.download(text_file)
    pass

and i’m still getting this error:

Exception: Argument to anvil.download() must be a Media object
at Form1, line 32

Although the model is still being saved on the path i provided but it is also throwing the above error.

Yes, that part is saving the model in my computer. I’m taking user input path from where i take images for training of model, also i take single input image to test the model after successful training.

Then i train the model using function “task” (output gets saved in variable “model”). Since i wanna use “model” variable for downloading, for simplicity i call it “m”.

Have a look at my server side code:



https://anvil.works/build#clone:EQECZML276BK6KRD=OCZH3GTIZ5XWHZ6IK2V3USW6

m.save is likely a method that doesn’t return the file object, but rather saves the file to the path you specify and returns None, so the new code snippet hasn’t changed the behaviour.

you can check by doing: print(m.save(path)) (probably None)

Whenever you work with files on the client or via anvil.server.call you should construct media objects.

Luckily the docs have a whole section on how to work with files.
https://anvil.works/docs/media/files_on_disk

Your code will probably end up as something like:

@anvil.server.callable
def download(path):
    if m is not None:
        m.save(path)
        import anvil.media
        media_obj = anvil.media.from_file(path, [content_type], [name]) 
        # where content_type and name are optional
        return media_obj # construct and return a media object
    else:
        raise Exception('model is not ready to download')

1 Like

Oh you’re right! i got None. I tried the code you provided.

@anvil.server.callable
def download(path):
    if m is not None:
        m.save(path)
        import anvil.media
        media_obj = anvil.media.from_file(path) 
        return media_obj # construct and return a media object
    else:
        raise Exception('model is not ready to download')

Since [content type] and [name] are optional, i can skip them right? But i got this error:

Exception: Argument to anvil.download() must be a Media object
at Form1, line 32

Again, the model successfully downloaded on my PC.

The doc says To read from an existing file, use anvil.media.from_file(file_name, [content_type], [name]). but here path which i’m writing as an argument, is actually path of directory where the model is going to be saved.

Have you put some debugging print statements in your code to work out what your function returns, as well as the value of variables at various points in the execution?

yes i have done this in my server code and i’m getting the same what i need.

with this same code, i ran my app again but this time i got the error:

PermissionError: [Errno 13] Permission denied: 'C:\\Users\\hiras\\Desktop'
at C:/Users/hiras/.conda/envs/TOCI_labs/lib/site-packages/anvil/media.py, line 33
  called from <ipython-input-15-6f80fd440c12>, line 53
  called from Form1, line 31

with the same code. i’m getting this error now:

Exception: model is not ready to download
at <ipython-input-3-03cadede957e>, line 53
  called from Form1, line 31

what is happening :zipper_mouth_face:

Worth noting (also mentioned in previous posts) that the path argument here doesn’t make sense from the browser perspective.

You can’t specify the path of your user’s file download from the browser.

can you rethink this logic so that you don’t need to specify a path?

Think about saving the model in server code as temporary. It just need to exist for that server call. Once the server call has finished you’ve returned the media object to the client and the user then chooses where to download it.

(What happens when you just specify a filename rather than a full path)

Thanks for the suggestion. I’ll try this soon.

Hello! i found a way to download the model without taking user path. So this is my new code:

@anvil.server.callable
def download():
    if m is not None:
        saved = m.save('my_model.h5', save_format='h5')
        import anvil.media
        media_obj = anvil.media.from_file(saved) 
        return media_obj # construct and return a media object
    else:
        raise Exception('model is not ready to download')

but i’m getting this error -
On 1st click on download button (Although i’m not providing path as an argument :neutral_face: ):

TypeError: download() missing 1 required positional argument: 'path'
at Form1, line 33

On 2nd click on download button:

Exception: model is not ready to download
at <ipython-input-3-cfd06ffc660a>, line 55
  called from Form1, line 33

You appear to have “path” specified in the function signature still which is why python is saying “path” is missing. Look carefully at your “download” function signature to see if it still expects “path”, and remove “path” as above. My guess anyway.

it looks like ‘saved’ in saved = m.save(‘my_model.h5’, save_format=‘h5’) is still going to be the result of m.save, which as stucork pointed out might be ‘None’
You seem very close, the .save method probably creates a file called ‘my_model.h5’ in the working directory (because that’s what you chose to put in as a temporary file name)

Try changing the:
media_obj = anvil.media.from_file(saved)
to:
media_obj = anvil.media.from_file(‘my_model.h5’)

I also strongly suggest you put a small delay between saving your file and turning it into a media object, aberrant behavior may be caused by disk cashing causing your ‘my_model.h5’ file to fail to be completely written before being scooped up by the anvil media object library.
something like :

from time import sleep
sleep(0.25)

after you save your model should keep this from happening (it would only fail sometimes, which can be frustrating)

You are probably very close to getting it to work.

1 Like

4 posts were split to a new topic: Model not saving