(Skulpt bug?) variables leak out of local context in nested list comprehension

Bug example

Take the following code

top_genres = [{'name': 'Adventure',
               'modified_mean_score': 8.857142857142858},
              {'name': 'Crime',
               'modified_mean_score': 8.733142857142858},
              {'name': 'Fantasy',
               'modified_mean_score': 8.608695652173912}]

movies = [
    {'movie_id': 42511,
     'title': 'Movie 1',
     'genres': [{'id': 1, 'name': 'Action'},
                {'id': 2, 'name': 'Adventure'},
                {'id': 28, 'name': 'Drama'},
                {'id': 38, 'name': 'Military'},
                {'id': 24, 'name': 'Sci-Fi'}]},
    {'movie_id': 42512,
     'title': 'Movie 2',
     'genres': [{'id': 3, 'name': 'Comedy'},
                {'id': 4, 'name': 'Fantasy'},
                {'id': 28, 'name': 'Crime'},
                {'id': 38, 'name': 'War'},
                {'id': 24, 'name': 'Science Fiction'}]},
    {'movie_id': 42513,
     'title': 'Movie 3',
     'genres': [{'id': 5, 'name': 'Crime'},
                {'id': 6, 'name': 'Horror'},
                {'id': 28, 'name': 'Mystery'},
                {'id': 38, 'name': 'Historical'},
                {'id': 24, 'name': 'Fantasy'}]},
    {'movie_id': 42514,
     'title': 'Movie 4',
     'genres': [{'id': 7, 'name': 'Documentary'},
                {'id': 8, 'name': 'Biography'},
                {'id': 28, 'name': 'Romance'},
                {'id': 38, 'name': 'Crime'},
                {'id': 24, 'name': 'Animation'}]}
]

for genre in top_genres:
  movie_list = [movie for movie in movies if genre['name'] in [genre['name'] for genre in movie['genres']]]
  print(f"{genre['name']}: {len(movie_list)}")

When I run it in a jupyter notebook I get the desired (correct) output:

Adventure: 1
Crime: 3
Fantasy: 2

However, when I run it in Anvil, I get this weird output:

Animation: 1
Animation: 0
Animation: 0

I believe that the genre variable in the inner list comprehension is escaping the context defined by the inner list comprehension.

Changing the variable name in the inner list comprehesion (for example to genre_b) solves the problem and produces the expected output.

for genre in top_genres:
  movie_list = [movie for movie in movies if genre['name'] in [genre_b['name'] for genre_b in movie['genres']]]
  print(f"{genre['name']}: {len(movie_list)}")

Output

Adventure: 1
Crime: 3
Fantasy: 2

Clone link:
Here is a minimal app that demonstrates the bug

Thanks for reporting - yes this is a bug in Skulpt’s list comprehension code.

2 Likes

I meant to say scope rather than context… but I think you got the point

2 Likes

a minor update - this looks like it’s a change from python 2 to 3.
And Skulpt didn’t keep up.

If you run this code

items = [(lambda: i) for i in range(5)]
i = 20
print([x() for x in items])

You’ll get different answers in python2 vs python3

1 Like

Same problem with dictionary comprehension

x = 'before'
a = {'test':x for x in [1, 2, 3]}
print(x) # this should print 'before' but prints '3' in Skulpt

However, the issue isn’t present with generator expressions. They seem to respect the local scope

x = 'before'
a = (x for x in [1, 2, 3])
for value in a:
    print(value)
print(x) # this prints 'before' in Skulpt as it should
1 Like

A side question, but is there any place that lists all the known skulpt bugs / deviances from python 3.7? Could be helpful for debugging.

Although I realise that in 99% of cases it’d be the programmer’s code that has a bug rather than skulpt.

There’s no one source of truth
As an anvil user - the quickest response is probably going to be on the forum.
But the skulpt github page is also useful for checking issues.

You can also compare snippets of code in python locally
(Be sure to run python 3.7 if you’re trying to determine if Skulpt differs)

Generally for bugs like this we’ll fix them and merge them upstream to the Skulpt project.

3 Likes