Ren'Py Trying to call a function as part of the Renpy say section

Alfius

Engaged Member
Modder
Sep 30, 2017
2,346
4,915
Sorry if something like this has been asked before:

So I want to do the following at the Renpy say section:

Code:
screen say(who, what):
        style_prefix "say"
        $ setpersonchat(who)     
        window:
            id "window"
            if who is not None:
                window:
                    id "namebox"
                    style "namebox"
                    text who id "who"
            text what id "what"
        ## If there's a side image, display it above the text. Do not display on the
        ## phone variant - there's no room.
        if not renpy.variant("small"):
            add SideImage() xoffset 20 xalign 0.0 yalign 1.0

This calls the following function:
Code:
    def setpersonchat(name):
        TPersonchat = "T"+name.lower()     
        getattr(store, TPersonchat ).top = 1
        renpy.show_screen("topbar")

The error I'm getting are
File "game/Z updatecharstats.rpy", line 1102, in setpersonchat
TPersonchat = "T"+name#.lower()
TypeError: coercing to Unicode: need string or buffer, NoneType found

(OK, I commented out the lower() function... Ignore that please)


I'm pretty sure it's something dumb, by not casting the who as a string.
 

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,607
2,256
TypeError: coercing to Unicode: need string or buffer, NoneType found

I think guest1492 nailed it. If you had a line of dialogue spoken by the narrator rather than a Character(), then who would be None.

I'm pretty sure it's something dumb, by not casting the who as a string.

If you want to remove all doubt, you could use str(who) instead of who.

Python:
screen say(who, what):
        style_prefix "say"

        window:
            id "window"
            if who is not None:
                $ setpersonchat(str(who))     
                window:
                    id "namebox"
                    style "namebox"
                    text who id "who"
            text what id "what"
        ## If there's a side image, display it above the text. Do not display on the
        ## phone variant - there's no room.
        if not renpy.variant("small"):
            add SideImage() xoffset 20 xalign 0.0 yalign 1.0

Only you will know what the consequences of not invoking something similar for narrator dialogue.

(OK, I commented out the lower() function... Ignore that please)

In my opinion, lower() is the right choice here. But that really depends on whether your TPersonchat variables are named something like TJanice or Tjanice.

Alternatively, you could leave the existing $ setpersonchat(str(who)) where it is and code something like:

Python:
    def setpersonchat(name):
        if isinstance(name, str):        # is it a string?
            TPersonchat = "T"+name.lower()  
            getattr(store, TPersonchat ).top = 1
            renpy.show_screen("topbar")
        else:
            # do something else when it's not a character.

Edit: Completely unrelated... but getattr(store, TPersonchat ).top = 1 works?

I suppose I was expecting something like that to be a setattr(), when changing a value. Just looks odd to my newbie mind.
 
Last edited:
  • Like
Reactions: Alfius

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,957
16,188
If you want to remove all doubt, you could use str(who) instead of who.
Starting his function with if who is None: return would be better. Just forcing who to become a string will lead to another error saying something along the line of "'TNone' attribue do not exist".



Edit: Completely unrelated... but getattr(store, TPersonchat ).top = 1 works?
Yes it works. getattr( store, Tpersonchat ) will return the object, then Ren'py will assign the value to the top attribute of this object.
 
  • Like
Reactions: Alfius

Alfius

Engaged Member
Modder
Sep 30, 2017
2,346
4,915
In my opinion, lower() is the right choice here. But that really depends on whether your TPersonchat variables are named something like TJanice or Tjanice.

Alternatively, you could leave the existing $ setpersonchat(str(who)) where it is and code something like:

Python:
    def setpersonchat(name):
        if isinstance(name, str):        # is it a string?
            TPersonchat = "T"+name.lower() 
            getattr(store, TPersonchat ).top = 1
            renpy.show_screen("topbar")
        else:
            # do something else when it's not a character.

Edit: Completely unrelated... but getattr(store, TPersonchat ).top = 1 works?

I suppose I was expecting something like that to be a setattr(), when changing a value. Just looks odd to my newbie mind.
lol, I won't call you a noob. Although I can code, my Renpy skills are pre-basic to be honest. I have seen you post in this section and I consider your knowledge quite good to be honest. I'm definitely a Renpy noob and borrow a LOT of code to get my stuff to work.


Thanks, I will try tonight, I think it should solve my problems.

getattr(store, TPersonchat ).top = 1
works like a charm.
 

Alfius

Engaged Member
Modder
Sep 30, 2017
2,346
4,915
Just some feedack.

So I managed to get it working, thanks to everyone!

For some reason the following did not work :(
Code:
    def setpersonchat(name):
        if isinstance(name, str):          
            TPersonchat = "T"+name.lower()
            getattr(store, TPersonchat ).top = 1
            renpy.show_screen("topbar")
        return
This worked. To be hones, not sure why the onw would work and the other not. (That's why I'm the noob)
Code:
    def setpersonchat(name):
        if name is None:
            return
        else:           
            TPersonchat = "T"+name.lower()
            getattr(store, TPersonchat ).top = 1
            renpy.show_screen("topbar")
        return
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,957
16,188
For some reason the following did not work :(
Code:
    def setpersonchat(name):
        if isinstance(name, str):         
            TPersonchat = "T"+name.lower()
            getattr(store, TPersonchat ).top = 1
            renpy.show_screen("topbar")
        return
It's because the str type is specific to Python 3. Either replace it by basestring, or use the last version of Ren'py and enable the support for Python 3 ; right now I don't remember how, but it should be in the changelog for the 7.4.4 or 7.4.5.
 
  • Like
Reactions: Alfius

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,607
2,256
For some reason the following did not work :(
Code:
        if isinstance(name, str):

The other thing I noticed when I was playing around with it originally was that who without being cast as something else, was flagged as being unicode.

I could be that isinstance() is very specific about the type of object that is passed to the function. To the point where name being unicode means it fails the "is string?" test, even though it behaves like a string (at least, to my limited understanding).
 
  • Like
Reactions: Alfius

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,957
16,188
I could be that isinstance() is very specific about the type of object that is passed to the function. To the point where name being unicode means it fails the "is string?"
As far as I remember, unicode is a subclass to str. What mean that isinstance( myString, unicode ) can eventually return False because it's another kind of string, but isinstance( myString, str ) (or basestring for Python 2) will always return True whatever the kind of string.

As a side note, all strings in Ren'py are unicode, this whatever the original encoding of the "rpy" files. The two exceptions are strings explicitly declared with another type (like r"my string" by example) and strings declared in a "py" file.
 
  • Like
Reactions: 79flavors