Why am I getting TypeError: unsupported operand type(s) for +: 'NoneType' and 'list'

I have an app where a user can create a project, this has 10 “global pushes” - rows in a data table that are placeholders for some sorting later on.

When the user updates an Interview, they add Push items to a push data table. I want to automatically assign new Push objects to the first global push - “Ungrouped Pushes”.

For some reason, I’m getting:

TypeError: unsupported operand type(s) for +: 'NoneType' and 'list'

Now I know this means I’m passing None as the first argument, but this is what I don’t understand:

This code works as planned:

#add a push from the interview page
@anvil.server.callable
def new_push(interview, new_push):
  app_tables.pushes.add_row(Interview=interview, Push= "When I " + new_push)
  this_push = app_tables.pushes.get(Push="When I " + new_push, Interview=interview)
  p_id = this_push.get_id()
  anvil.server.call('new_push_to_global_push', interview, p_id)

Which triggers this code:

#link a new push to the global pushes bucket
@anvil.server.callable
def new_push_to_global_push(interview, p_id):
  #automatically link this new push to the placeholder bucket row and project
  #bag the push
  this_push = app_tables.pushes.get_by_id(p_id)
  print(this_push)
  #bag the project
  this_project = interview['Project']
  #bad the Ungrouped Pushes bucket
  start_global_push = app_tables.global_push.get(Project=this_project, global_push_name= 'Ungrouped Pushes')
  print(start_global_push)
  #add this push to the ungrouped pushes bucket
  start_global_push["linked_pushes"] += [this_push]

And the final output shows that the print lines are pushing out:

<LiveObject: anvil.tables.Row>
<LiveObject: anvil.tables.Row>

If I run .search on the data table for Grouped Pushes, I can find the right row with the same parameters passed above.

So why is it returning a row from the get method, then nothing when I try to update the row with the push?

Here’s the data table:


(ignore the first two rows, they were testing the pre-build before I needed this functionality)

The other two data tables are performing as expected, but I can add them if you think it will help. I have similar code working on other parts of the site - it’s probably some stupid error, but I can’t seem to see it. Can you help?

The error literally means that you are trying to use the + operator on a string and attempting to add to it something that is not a string.
probably here:

app_tables.pushes.add_row(Interview=interview, Push= "When I " + new_push)

I am guessing new_push at some point is a None object and at some other point is is a list

If you just wanted to avoid the error and get bad information in the string you are passing you can use f-strings. (Or other, older, less used methods for string concatenation between types)

like
f"When I {new_push}"

But instead of raising this error the string will be passed looking like:

"When I None" or "When I []"

Edit: as @stefano.menci points out below, it might have nothing to do with strings, you are trying to use the + operator to add two types that are not the same, and python doesn’t implicitly know how to do that. (this is a feature, not a bug)

Perhaps start_global_push is not None, but start_global_push["linked_pushes"] is.

1 Like

Odds are, it’s this:

In a new database row, the default (initial) value for every column is None, not an empty list. As shown in the final row, above.

Thanks, @stefano.menci - start_global_push[‘linked_pushes’] will always start off looking like the row below, based on how I seed the data table with “Global Pushes” when a Project is created:

How can I update that column/row of the Global_Pushes table with the push I’ve found in my code? I was using the same syntax shown in the documentation. Is there another way to add content to a row that is “None” to begin with?

Thanks @p.colbert - in which case how can I add my Push object link to that row? I was using the syntax provided in the documentation…

One solution is to make sure to set that column value to [] every time a row is added to the database. This would also require adding empty lists to all existing rows, which can easily be done on a server console with this:

from tables import app_tables
for row in app_tables.pushes.search():
    if not row['linked_pushes']:
        row['linked_pushes'] = []

Another solution is to leave the creation of rows and current database as they are and never assuming that that column has a list, for example converting this:

start_global_push["linked_pushes"] += [this_push]

into this:

if start_global_push["linked_pushes"]:                 # if truthy (no [], None, 0, ...)
    start_global_push["linked_pushes"] += [this_push]  # add to current list
else:
    start_global_push["linked_pushes"] = [this_push]   # create new list
2 Likes

Thanks - setting the column to be an empty list works perfectly for me, because it also helps another part of the app display properly when there are no Pushes that have been added yet.

1 Like