Anvil Serialization Error

In form code, I have the lines:

          response = anvil.http.request(self.cp_QIS.tag['url'])
          csv_string_QIS = response.get_bytes()
          self.cur_QIS = anvil.server.call('parse_QIS_data',csv_string_QIS)

In the last statement I get the error

AnvilSerializationError: Cannot pass bytes object to a server function: arguments[0]

The same form code worked in Python 2.7 (basic), now I’ve upgraded to Python 3 (basic).
Can you help me to understand what’s under this error?
Is there any difference in the implementation of request, response or server.call I should take into account?

Thanks

I think this is a problem with the bytes object being a string in the 2.7 and being a bytes object in 3.x. Anvil’s documentation for this is still geared towards python 2.7 and so I don’t think it is particularly well documented…

try using: csv_string_QIS = response.get_bytes().decode()

in short - when you need a string object from bytes in python 3 use bytes_object.decode() and when you need a bytes object from string use str_object.encode()

2 Likes

Hi sc549 and thanks for your time and help.
Tyring to convert the byte array to string gives me an:

UnicodeEncodeError: UTF-8 decoding failed

on the row:

csv_string_QIS = response.get_bytes().decode()

I’m trying to figure out why, googling and looking on stackoverflow but I haven’t found anything useful by now.
I cannot even "debug print" the bytes array variable since it gives the same error.
(BTW this stuff on bytesarray and string encoding looks to me to be the most messy stuff in Python, which usually has practical and simple solutions to almost any coding task)

To be honest I had already tried the bytesarray-to-string conversion before my first post, getting this same error.
Then I decided to post here about the serialization error because, in my understanding, Anvil should be able to pass any type of variable from client to server code, or at least I haven’t found anything in the docs stating that bytesarray cannot be passed.

EDIT: in the docs IS actually stated that arguments passed from client to server may only be strings, numbers, lists, dicts, datetime.date , datetime.datetime , None , Media objects, or rows from a data table.
My fault not to have found this!

So, converting to string before calling server code is the right path, and fixing the conversion error is the focus.
Any suggestion?

Thanks!

1 Like

try the argument ‘utf-8’

so do .decode('utf-8')

if not drop me a clone link and i can have a play around…

Hi sc549
here’s a clone link.
https://anvil.works/build#clone:YDELN7TJZEPYXP22=5UU25LA7444LZDLFDTTJPEBI
Very simple, 10 lines of code.
In the meantime, I’m keeping searching a solution.

Thanks again.

1 Like

Don’t know if it helps, but it works if you push it all server side :

import anvil.http
...
@anvil.server.callable
def dave():
    my_url="https://docs.google.com/spreadsheets/d/e/2PACX-1vSkZycfePF5Fqn7d1Ht6GN-xinRHlmeKV7efD2hxSprRN4h7m3KEbd8EXKW7UBBn1my-5KS0U2eFM7M/pub?output=csv&gid=784986591"
    response = anvil.http.request(my_url)
    a = response.get_bytes()
    return str(a)
1 Like

Thanks David
it sure helps with the problem I have right now, but:

  1. it involves some major code review, I’d prefer to avoid. However I’ll switch all to server if I’m forced to.
  2. I’m interested in understanding the string converison problem. It could arise in other cases too and I need to work it out thoroughly.

Thanks!

I have a feeling it’s a skulpt javascript str bytes issue. Since moving the client-side code from your clone link to the server-side worked as expected without any decode failures.

@meredydd is probably the best person to help with this…

Hi @aldo.ercolani,

This is coming about because you’re trying to pass binary data (a bytes object) to a server function. Server functions can only accept (or return) strings, numbers, None, and a few other types (see here for the full list). If you want to pass binary data, you should pass it as a Media object.

(Your code was mostly working in Python 2, because Python 2 also represents bytes as strings – so it would work as long as that string happened to contain a valid UTF-8 byte sequence. Python 3 is much more strict about separating str and bytes types.)

The good news is that anvil.http.request() returns a Media object already! So you can just pass your response value into your server function, without calling get_bytes() on it – and then you can call get_bytes() to get the contents in your server function :slight_smile:

2 Likes

Thanks Meredydd
this:

The good news is that anvil.http.request() returns a Media object already! So you can just pass your response value into your server function, without calling get_bytes() on it – and then you can call get_bytes() to get the contents in your server function

is indeed the solution to my case.
I still don’t understand why the attempt (see cloned app) to convert the decoding in utf-8 gives error:

csv_string_QIS = response.get_bytes().decode('utf-8')

UnicodeEncodeError: UTF-8 decoding failed

Thanks!

nice solution @meredydd.

and agree - the question remains - why might .decode break client-side but not server-side.