TypeError: can only concatenate str (not "bool") to str

Discuss how to use the Ren'Py engine to create visual novels and story-based games. New releases are announced in this section.
Forum rules
This is the right place for Ren'Py help. Please ask one question per thread, use a descriptive subject like 'NotFound error in option.rpy' , and include all the relevant information - especially any relevant code and traceback messages. Use the code tag to format scripts.
Post Reply
Message
Author
CSK
Newbie
Posts: 16
Joined: Sat Sep 10, 2022 2:42 pm
Contact:

TypeError: can only concatenate str (not "bool") to str

#1 Post by CSK »

The way this is intended to work is to have function that displays a list of attributes that are all set to "unknown" at first and which can be individually unlocked throughout the story. I already had another solution that worked, on the principle of having a "var3=[]" added and "var1" set to "unknown" in Output and to show "var1" as "self.var1" if "var1" is in "var3", but there were some issues during testing and when I read up about it I found it stated that Renpy has some issues with saving things like that, so I ended up trying it this way.

I already did quite a bit of testing, even to just get to this point, as my programming knowledge and skills are very close to non existent, but with this I reached a point at which I am no longer sure what to look for to solve this. What I found regarding the error statement was the last attempt, which I added in the commented line, the result of which is that the output switches from "var1 = unknown" to "var1 = True".

Is there a way to solve this in this way, because there is just a minor or major mistake on my part in the way I tried to implement it or would it be better to switch back to the other method, hoping that the saving issue doesn't exist or was something that I misunderstood - or maybe is there another way to solve this?

Code: Select all

label test:

init python:
    class TestFun:
        def __init__(self, var1, var2):
            self.var1 = var1
            self.var2 = var2

        @property
        def Output(self):
            var1 = self.var1
            var2 = self.var2

            if var1 == False:
                var1 = "unknown"
            if var1 == True:
                var1 = (self.var1)

            if var2 == False:
                var2 = "unknown"
            if var2 == True:
                var2 = self.var2

            #return "var1: " + str(var1) + "{p}" + "var2: " + var2
            return "var1: " + var1 + "{p}" + "var2: " + var2


define tfperson = TestFun("VarOneAtt"==False, "VarTwoAtt"==False)
define j = Character("Jane")

scene white

j "Test line"

j "[tfperson.Output]"

$ tfperson.var1 = True

j "test line two"

j "[tfperson.Output]"

enaielei
Veteran
Posts: 293
Joined: Fri Sep 17, 2021 2:09 am
Organization: enaielei
Tumblr: enaielei
Deviantart: enaielei
Github: enaielei
Skype: enaielei
Soundcloud: enaielei
itch: enaielei
Discord: enaielei#7487
Contact:

Re: TypeError: can only concatenate str (not "bool") to str

#2 Post by enaielei »

Code: Select all

@property
def Output(self):
    var1 = self.var1 if self.var1 else "unknown"
    var2 = self.var2 if self.var2 else "unknown"
    return "var1: %s{p}var2: %s" % (var1, var2)
Concatenations are prone to errors, you need to make sure that the values you're concatenating are all strings, if not you need to use str() function (e.g. "string" + str(True)).
Using string interpolation is much preferred and much safer.

CSK
Newbie
Posts: 16
Joined: Sat Sep 10, 2022 2:42 pm
Contact:

Re: TypeError: can only concatenate str (not "bool") to str

#3 Post by CSK »

enaielei wrote: Fri Sep 23, 2022 12:41 pm ...
Concatenations are prone to errors, you need to make sure that the values you're concatenating are all strings, if not you need to use str() function (e.g. "string" + str(True)).
Using string interpolation is much preferred and much safer.
Thanks. I changed the Output code, but the result of doing so is creating the same result I got from using the line I had commented:

Code: Select all

return "var1: " + str(var1) + "{p}" + "var2: " + var2
Which is, that when I set "$ tfperson.var1 = True", the output is:

var1: True
var2: unknown

Instead of:

var1: VarOneAtt
var2: unknown

So this:

Code: Select all

label test:

init python:
    class TestFun:
        def __init__(self, var1, var2):
            self.var1 = var1
            self.var2 = var2
        @property
        def Output(self):
            var1 = self.var1 if self.var1 else "unknown"
            var2 = self.var2 if self.var2 else "unknown"
            return "var1: %s{p}var2: %s" % (var1, var2)

define tfperson = TestFun("VarOneAtt"==False, "VarTwoAtt"==False)
define j = Character("Jane")

scene white

j "Test line New"

j "[tfperson.Output]"

$ tfperson.var1 = True

j "test line two"

j "[tfperson.Output]"
When you run it in Renpy it looks the same as my code from above when switching the return line to the commented return line. Apologies if I hadn't described it well enough. From my limited understanding, when I define a variable and then set it to False, that only adds a parameter to that variable, so setting it then to True, should only change that parameter, so when it is False, show "unknown", when it is True, show the original variable, but what it does is that it shows True. Well, or the error message I used in the subject, when not defining / converting it to a string. Hoping what I wrote made sense and was more clear than the first post.

enaielei
Veteran
Posts: 293
Joined: Fri Sep 17, 2021 2:09 am
Organization: enaielei
Tumblr: enaielei
Deviantart: enaielei
Github: enaielei
Skype: enaielei
Soundcloud: enaielei
itch: enaielei
Discord: enaielei#7487
Contact:

Re: TypeError: can only concatenate str (not "bool") to str

#4 Post by enaielei »

You just need to modify a bit the ternary operation that I did.

Code: Select all

@property
def Output(self):
    var1 = "Var1Att" if self.var1 else "unknown"
    var2 = "Var2Att" if self.var2 else "unknown"
    return "var1: %s{p}var2: %s" % (var1, var2)
The way a ternary operation works...

Code: Select all

<true_value> if <condition> else <false_value>
It's just a short hand expression of doing...

Code: Select all

if <condition>:
    <true_statement>
else:
    <false_statement>

CSK
Newbie
Posts: 16
Joined: Sat Sep 10, 2022 2:42 pm
Contact:

Re: TypeError: can only concatenate str (not "bool") to str

#5 Post by CSK »

enaielei wrote: Fri Sep 23, 2022 2:51 pm You just need to modify a bit the ternary operation that I did.
Googled it as well and if I understand it correctly then ternary operation essentially means using if else. What I don't understand is. Well.

I tried this code here as well:

Code: Select all

@property
def Output(self):
    var1 = "Var1Att" if self.var1 else "unknown"
    var2 = "Var2Att" if self.var2 else "unknown"
    return "var1: %s{p}var2: %s" % (var1, var2)

It worked as I assumed it that it should. The "if self.var1" in it seems to be the same as stating if it is True, in the definition of tfperson, "VarOneAtt" is set to False and setting it to True later changes the output from "unknown" to "VarOneAtt". It shows the variable and not the state the variable has been set to. What I don't understand is why it doesn't show the variable but the state when using "self.var1" directly, why it shows True instead of "VarOneAtt" then.

I should also add that doing it this way sadly doesn't work for what I was planning, because the purpose of putting those variables into "tfperson" is so I can have any number of those, like "tfperson1", "tfperson2", ... with different "VarOneAtt" and "VarTwoAtt" and so on, and be able to change the "unknown" state on any of them by "simply" - or so I thought and hoped - setting tfpersonX.varX to True.

enaielei
Veteran
Posts: 293
Joined: Fri Sep 17, 2021 2:09 am
Organization: enaielei
Tumblr: enaielei
Deviantart: enaielei
Github: enaielei
Skype: enaielei
Soundcloud: enaielei
itch: enaielei
Discord: enaielei#7487
Contact:

Re: TypeError: can only concatenate str (not "bool") to str

#6 Post by enaielei »

in the definition of tfperson, "VarOneAtt" is set to False
Are you talking about this line?

Code: Select all

TestFun("VarOneAtt"==False, "VarTwoAtt"==False)
You're not setting any values here, you're comparing values here. Is the literal string "VarOneAtt" the same as the boolean False? No. Hence it evaluates to False.

Code: Select all

TestFun(False, False)
The above code is what exactly you're doing in that line.
It shows the variable and not the state the variable has been set to
I did not see any definition for the VarOneAtt variable in your previous code, so I assumed you're just simply trying to show the literal string "VarOneAtt". Anything that are contained within quotes "" represents a literal string. It does represent any variable value.
If you're talking about showing the value of one of your variables named "VarOneAtt", then you're doing it wrong.
What I don't understand is why it doesn't show the variable but the state when using "self.var1" directly, why it shows True instead of "VarOneAtt" then.
Because self.var1 contains whatever value that you store in it. If you print self.var1 you'll literally see the value that it holds.
I should also add that doing it this way sadly doesn't work for what I was planning, because the purpose of putting those variables into "tfperson" is so I can have any number of those, like "tfperson1", "tfperson2", ... with different "VarOneAtt" and "VarTwoAtt" and so on, and be able to change the "unknown" state on any of them by "simply" - or so I thought and hoped - setting tfpersonX.varX to True.
Well, you're on the right track on this one. OOP/Classes are meant for things like this.

User avatar
Ocelot
Lemma-Class Veteran
Posts: 2384
Joined: Tue Aug 23, 2016 10:35 am
Github: MiiNiPaa
Discord: MiiNiPaa#4384
Contact:

Re: TypeError: can only concatenate str (not "bool") to str

#7 Post by Ocelot »

Slightly changed code:

Code: Select all

@property
def Output(self):
    potato = "Var1Att" if self.var1 else "unknown"
    butterflies = "Var2Att" if self.var2 else "unknown"
    return "var1: %s{p}var2: %s" % (potato, butterflies)
Does that makes it more clear? var1 and var2 in that function wele local variables of the Output function and not related to self.var1 and self.var2 instance variables of tfperson object.

You can store both value and if it was revealed yet inside your class, it can be as simple or complex, as you like:

Code: Select all

@property
def output(self):
    strangeness = self.strangeness if self.strangeness_unlocked else 'unknown'
    charm = self.charm if self.charm_unlocked else 'unknown'
    beauty = self.beauty if self.beauty_unlocked else 'unknown'
    truth = self.truth if self.truth_unlocked else 'unknown'
    return 'Strangeness: {}\nCharm: {}\nBeauty: {}\nTruth: {}'.format(strangeness, charm, beauty, truth)

# or even:
@property
def output(self):
    result = ''
    for attribute in self.revealed_attributes:
        result += '{}: {}\n'.format(attribute, self.attributes[attribute])
    return result
(both code snippets are not intended to give identical results)
< < insert Rick Cook quote here > >

CSK
Newbie
Posts: 16
Joined: Sat Sep 10, 2022 2:42 pm
Contact:

Re: TypeError: can only concatenate str (not "bool") to str

#8 Post by CSK »

Thanks enaielei and Ocelot, things are bit more clear now.

"Well, you're on the right track on this one. OOP/Classes are meant for things like this."

That's encouraging, thanks. I have started to learn Python from courses and such on the side, but mainly I learn from actively doing, even if that involves sitting in front of it for hours with only small incremental progress, as I did before I got to the problem I posted, as I no longer understood enough to know what to search for. Which actually isn't really necessary for the project I am working on, as I figured out enough to know how to make it work without using a function, but my take is that even if I don't end up using it I will have learned something and if I manage it then it will be a lot more elegant.

After some more trying around I managed to make it work as I thought it should, thanks to both your help:

Code: Select all

label test:

init python:
    class TestFun:
        def __init__(self, var1a, var1b):
            self.var1a = var1a
            self.var1b = var1b

        @property
        def Output(self):
            var1b = self.var1b
            var1a = self.var1a
            self.var1a = var1a

            if var1b == False:
                var1a = "unknown"
            if var1b == True:
                var1a = (self.var1a)

            return "var1a: " + str(var1a)

define tfperson = TestFun("VarOneAttA", False)
define j = Character("Jane")

scene white

j "Test line New"

j "[tfperson.Output]"

$ tfperson.var1b = True

j "test line two"

j "[tfperson.Output]"
The main two things were having to make an additional variable to use for the True/False and to use False directly in "define tfperson".

I played around a bit with it already and didn't manage to make it any shorter for now. What I came across that I am not sure of is when trying it this way:

Code: Select all

def __init__(self, var1a, var1b=False):
...
define tfperson = TestFun("VarOneAttA", "VarOneAttB")
There was no error message so, the way I understand it, var1b should be set to False and given that "VarOneAttA" even showed as True when using the other code, I don't know why it's not working just the same.

This is the code I had before, which also works:

Code: Select all

label test2:

init python:
    class TestFun:
        def __init__(self, var1, show_details = []):
            self.var1 = var1
            self.show_details = show_details

        @property
        def Output(self):
            var1 = "unknown"
            if "var1" in self.show_details:
                var1 = self.var1
            return "VarOne: " + var1

define tfperson = TestFun("VarOneAtt")
define j = Character("Jane")

scene white
j "Test line New"

j "[tfperson.Output]"

$ tfperson.show_details.append("var1")

j "test line two"

j "[tfperson.Output]"

$ tfperson.show_details.remove("var1")

j "test line three"

j "[tfperson.Output]"
Here it works right away, but in my project the output is, well, I added something like a character screen and either there already, but sure in a subscreen of it which is accessed inside of it, it took several lines to take, as in, line, append, line, no change, line, line, then it changed. That and finding something about Renpy having a problem with saving things lead to going for the other one. Hoping all of this is okay with the whole one question per thing, especially since the OP was already a mess, but since I had that in the OP already as well, is it fine to use a function that works like that in Renpy (even if certain additional things need to be taken care of for it) or is it better to stay away from it?

Well, just in case someone reads this and is inclined to answer, as my main issue is solved and this thread can be declared as such, if that's not something I would have to do.

Post Reply

Who is online

Users browsing this forum: No registered users