[SOLVED] Renpy has randomly decided that my list is now a string...

OhWee

Forum Fanatic
Modder
Game Developer
Jun 17, 2017
5,891
29,935
Issue resolved, leaving this here in case someone else runs itno this issue.

OK, so I'm working with lists for a project. Like so...

default profile_girls = ["Artemis", "Batgirl", "BlackCanary", "Cassie", "DonnaTroy", "Hawkgirl", "Huntress", "MissMartian", "Stargirl", "Starfire", "Supergirl", "Terra", "Vixen", "WonderWoman", "Zatanna"]

Note the default, not define.

That's my list. I THINK that I've declared this right, and in fact, Ren'Py can access these elements as if it's a list.

But when I go to do this, at some point later on in the game:
$profile_girls.append("KiteLass")

It throws me an error, saying that profile_girls is a string...

So i tried using a couple of Python functions in the console, essentially:


And the 'is str' check returns False.

I have a way to 're-compile' a list to the variable, i.e.

using a len(profile_girls) to get the list length,
and then use the len to set the 'for i in range(0, x) to get the name values out of the old list into a placeholder list individually
then append those to a 'placeholder' list,
then wipe out the contents of profile_girls, i.e. profile_girls = []
Then use the 'loop' function to append each girl in the 'placeholder' list to profile_girls one at a time...

I tried .copy, but the time I tried it the error was still there...

In any case, this works, and I can then append new names to the 'fixed' list.

So my questions are:
1) Has anyone else ran into this issue using Ren'Py,
2) If so, what' command word' works in Ren'Py to detect if my 'str' is masquerading as a list.

If I can find a 'command word' that doesn't return 'False' when I ask, then I'll know that my list isn't a 'full fledged' list and can implement the 'fix' and maybe track down at what point the 'semi-conversion' occurred.
I just don't want to have to keep re-creating the 'almost a list' each night, I'd rather keep the 'fixed' list intact instead of re-building it each time...
It 'should' transcribe perfectly each time using my method, but no sense tempting fate...

I tried:
isinstance(profile_girls, str)
That returns as False in the console.

Ren'Py 7.4.11 btw.

Any ideas?
 
Last edited:

rayminator

Engaged Member
Respected User
Sep 26, 2018
3,130
3,194
without the error code we can't really help much

but from the list that you gave it doesn't show anybody named "KiteLass"

default profile_girls = ["Artemis", "Batgirl", "BlackCanary", "Cassie", "DonnaTroy", "Hawkgirl", "Huntress", "MissMartian", "Stargirl", "Starfire", "Supergirl", "Terra", "Vixen", "WonderWoman", "Zatanna"]
 

Saki_Sliz

Well-Known Member
May 3, 2018
1,403
1,011
I'm still a noob at ren'py, leaching most of my knowledge off of Anne O'nymous.

From what I understand, when you use default myList = ['things'], the default keyword is a renpy instruction, and renpy does some magic that allows it to create a datatype (in this case a list) which renpy is able to track changes to and save as part of save file system. I don't know how this work, by I imagine that renpy some how tracks the state of this object with something external (ie a class or something), or it actually wraps the datatype in a class that masquerades as your datatype, allowing you to do certain operations on it, but the class keeps track of the commands. I need someone more knowledgeable than me on the workings of ren'py, but I suspect that its the second case, which tends to lead to the problem you would be experiencing.

You don't have permission to view the spoiler content. Log in or register now.

Or maybe its just a case that renpy just doesn't allow list.append() because that's not something renpy can keep track of for whatever reason (in most languages appending to a list does more than just mutate the data, it does what you had to manually code out, where it creates a new list with an extra slot, copies everything, copies the new entry at the end, and then return the new list, any low level unmanaged code, like hand made C code that points to these mutated lists could cause a segmentation fault, causing hard crashes)
 

OhWee

Forum Fanatic
Modder
Game Developer
Jun 17, 2017
5,891
29,935
without the error code we can't really help much

but from the list that you gave it doesn't show anybody named "KiteLass"

default profile_girls = ["Artemis", "Batgirl", "BlackCanary", "Cassie", "DonnaTroy", "Hawkgirl", "Huntress", "MissMartian", "Stargirl", "Starfire", "Supergirl", "Terra", "Vixen", "WonderWoman", "Zatanna"]
Yeah, KiteLass is being appended to that list, or that was the plan anyways. If I 're-compile' the list as I explained, I can append her just fine.

And no, the error message isn't that helpful, like I said it's a list but it's not a list...

SU_Re-Imagined_appenderror.jpg
 

Saki_Sliz

Well-Known Member
May 3, 2018
1,403
1,011
never mind my comment I just tested it without issue

1673314503237.png
I'm still a noob, so I don't even know how to check what version of ren'py I'm using
 

OhWee

Forum Fanatic
Modder
Game Developer
Jun 17, 2017
5,891
29,935
Saki_Sliz

Yeah, it's weird. If I could introduce a 'check profile_girls at various points in the code to see if it's still a full list' I could maybe isolate when the 'change' occurs.

I suppose that I could do an 'onerror fix the list' routine, but I'd just like to know where it's getting balled up...

Your logic may not be far off.
 

Saki_Sliz

Well-Known Member
May 3, 2018
1,403
1,011
My only other guess is maybe the list goes down to a length of 1, and python does some bs that converts it to a string since a list of 1 string and a string may look identical to python (not to other languages)
 

Alcahest

Engaged Member
Donor
Game Developer
Jul 28, 2017
3,486
4,331
What if something else is causing the issue other than what you think it is? If you want help, show the code where the error occurs (not just the line you think is the error), and the error message, otherwise we would just have to take your word for it. You might have missed something.
 
  • Like
Reactions: gojira667

rayminator

Engaged Member
Respected User
Sep 26, 2018
3,130
3,194
you want to add KiteLass to that list

renpy still thinks it a list not a string

replace [] with {}

PHP:
default profile_girls = ["Artemis", "Batgirl", "BlackCanary", "Cassie", "DonnaTroy", "Hawkgirl", "Huntress", "MissMartian", "Stargirl", "Starfire", "Supergirl", "Terra", "Vixen", "WonderWoman", "Zatanna"]
it should look like this

PHP:
default profile_girls = {"Artemis", "Batgirl", "BlackCanary", "Cassie", "DonnaTroy", "Hawkgirl", "Huntress", "MissMartian", "Stargirl", "Starfire", "Supergirl", "Terra", "Vixen", "WonderWoman", "Zatanna"}
type in
profile_girls.add("KiteLass")

then type
profile_girls

it should show like this
1673315662829.png
 

OhWee

Forum Fanatic
Modder
Game Developer
Jun 17, 2017
5,891
29,935
Alcahest

Error message is screenshotted. Doesn't matter where I put the append (at least at this point in the game, sandbox situation that jumps between labels/screens), unless I add my 're-compile list' routine the list is borked as far as append is concerned. Works fine otherwise.

See, the thing is that I CAN append other variables set up this way. It's just a couple of variables that are getting borked.
 

Alcahest

Engaged Member
Donor
Game Developer
Jul 28, 2017
3,486
4,331
Alcahest

Error message is screenshotted. Doesn't matter where I put the append (at least at this point in the game, sandbox situation that jumps between labels/screens), unless I add my 're-compile list' routine the list is borked as far as append is concerned. Works fine otherwise.

See, the thing is that I CAN append other variables set up this way. It's just a couple of variables that are getting borked.
Yeah, but you're basically saying that there is a huge bug with lists in renpy, which seems unlikely. Seems more likely that it's something else messing things up. I don't know much about renpy or python, but if I try to append something to a string in renpy 7.4.11, I don't get that error message, I get this: AttributeError: 'unicode' object has no attribute 'append' Which suggests, it seems to me, that there is something else going on than it seeing your list as a string.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,979
16,236
So "profile_girls" is a string, period.

And I mean a real pure native string. If it was a class that behave like a string, the error would be "AttributeError", not "TypeError", and the message that "'type of the object' has no attribute 'append'".

Since the console works on its own context, the error that change the type of "profile_girls" do not happen in the global context. This reduce the possibilities since it's either (depending of the effective context in your code) in the screen where the error happen, or in the label you called in a new context.


Edit:
I'm an idiot... The error say it, "'str' type is not callable"...

It's not "profile_girls" the problem, it's "append". The "append" method have been redefined and is now a string. Search for "profile_girls.append = " and you'll find the faulty line.
 
Last edited:

OhWee

Forum Fanatic
Modder
Game Developer
Jun 17, 2017
5,891
29,935
So explain this then...

SU_Re-Imagined_appenderror2.jpg

Note that MissMartian was successfully 'popped' out of the list at an earlier point in the code. I can pop and append girls all day long with profile_lvl3girls, and pop girls out of profile_girls, I just can't append to profile_girls, and I don't understand why...

Again, back to my ORIGINAL question. What detection routine can I use to detect if the list is now considered a str as far as appending is concerned? i want to introduce a code check for this, not re-compile the list at the end of every day just in case...
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,979
16,236
From what I understand, when you use default myList = ['things'], the default keyword is a renpy instruction, and renpy does some magic that allows it to create a datatype (in this case a list) which renpy is able to track changes to and save as part of save file system.
It's simpler than this. Globally speaking, because it's a bit more complex due to the parser and the multi lines assignations, this happen:
  1. Ren'Py split the line in three: "[statementName] [variableName] = [value]\n" ;
  2. Ren'Py do a variableName = eval( value ) ;
  3. Ren'Py will add variableName in the list of variable that have to be saved.


I don't know how this work, by I imagine that renpy some how tracks the state of this object with something external (ie a class or something), or it actually wraps the datatype in a class that masquerades as your datatype, allowing you to do certain operations on it, but the class keeps track of the commands.
Once again it's simpler than this.
The variable is directly the variable, its type is its type, and everything is directly handled by Python.
Assignation are expressed as inline Python ($ x = 1, $ x += 5, etc) because Ren'Py directly pass the line to the interpreter to process it. As for tests, globally speaking (still the parser thing), the "if" is a Ren'Py statement, and everything else will be processed by the interpreter. Same for loops.

By itself, Ren'Py have near to no notion of variables. It know that they exist, but the only moment it effectively interact with them is during the rollback, either when it create a new "save point", because you started a new interaction, or because you are effectively rolling back to the previous "save point". Be noted that save and load are both a special way to rollback.

For lists (and more globally "structured types"), there's a bit of variation due to the rollback feature.
A list is in fact a [I]renpy.Python.RevertableList[/I] object. But this object inherit directly from list, just ensuring that it will be compliant with the rollback.
The behavior itself don't change, and the structure behave exactly like a native list. What mean that a list will not suddenly behave like a string, unless there's a really big typo in the code of [I]renpy.Python.RevertableList[/I] ; but I just looked at the code for the version 7.4.11, there isn't such typo.

Anyway, like I said Python wouldn't complain that the variable is a string if it wasn't effectively one. This is due to the fact that the exceptions are thrown directly from the objects. Therefore, if an object from the class "Whatever", that would mimic both a list and a string, had an error, Python would say that "'Whatever' object [can't do this]" ; it wouldn't talk about string.

And I need to thanks you, because writing this made me realize that there were something odd in the error message, and then find what was the effective problem.


Why I think the datatype is being wrapped rather than monitored
As you can see, it's even more simpler than this ;)
All the variables used by the game are stored as attribute of a special object named "store", and in addition to this, Ren'Py have a set (a special type of list that don't have duplication) with the list of all the variables that have to be saved.
You'll find a bit more by reading and the section that follow it.
 
  • Heart
Reactions: Saki_Sliz

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,979
16,236
So explain this then...
profile_girls is a list where the attribute "append" have been, by error, redefined by you.

It's totally, and obviously, logical that a list continue to behave like a list, and that the only error you get is when you try to use the method "append", that is now a string.


After, what you do with the information I gave you is your problem and your problem only. If you prefer to stick to the strong disliking you have for me, well, why should I care, it's you that will spend time trying to fix an error that is now totally explained.

As for me, I did what I had to do. If someone encounter this kind of issue and come to this thread, he will know why it happen.
In the same time, my answer also explain what the error "'string' is not a callable" mean, therefore it cover a larger spectrum than a list having a strange behavior. Anyone who read my answer will now know that when he get this error, it's because what he believed to be a function/method, have become a string. So, he'll know that he can fix the error in less than one minute, by searching for a line where there's a "=" instead of "(".
 
  • Like
Reactions: gojira667

KitsuneZeta

Newbie
Dec 12, 2020
20
13
OhWee: what does the console say profile_girls.append is? (note the distinct LACK of parentheses there) I suspect you're going to find that it's... Not a "bound method". Which means at some point, you assigned a value to it instead of calling it.

While Python itself prevents you from breaking the built-in List object (as I tried in IDLE), Ren'Py DOES NOT prevent you from breaking an instance of RevertableList in that way.
 

OhWee

Forum Fanatic
Modder
Game Developer
Jun 17, 2017
5,891
29,935
OhWee: what does the console say profile_girls.append is? (note the distinct LACK of parentheses there) I suspect you're going to find that it's... Not a "bound method". Which means at some point, you assigned a value to it instead of calling it.

While Python itself prevents you from breaking the built-in List object (as I tried in IDLE), Ren'Py DOES NOT prevent you from breaking an instance of RevertableList in that way.
That's my question. I tried:
isinstance(Profile_Girls, str)
and it returns False
How else can I check this?
 

OhWee

Forum Fanatic
Modder
Game Developer
Jun 17, 2017
5,891
29,935
I get:
profile_girls.append
'BlackCanary'