Ren'Py enum and "type() argument 1 must be string, not unicode"

Bip

Active Member
Donor
May 4, 2017
734
2,100
Hi there!

Since some time, I systematically convert RenPy games to the 7.4.x version (yes, I have 2 good reasons to do it, so I do it :p).
It almost always works perfectly, on rare occasions there's just a little thing to change and I'm happy.
Except that now, I'm stuck.

The game, Tales of Terrara, works fine with RenPy 7.3.5, but with RenPy 7.4.8, I have a "TypeError: type() argument 1 must be string, not unicode"

The code pointed by the error is the return type(...):
Python:
init python:
    def enum(**enums):
         return type(str('Enum'), (), enums)

    Creaturesize = enum(tiny=1, small=2, medium=3, large=4, huge=5, gargantuan=6)
...
I checked google, what I found there is code compliant. So, I don't know...
 

shark_inna_hat

Active Member
Game Developer
Dec 25, 2018
705
2,733
The code is a bit of a dirty trick to make a class that stores some values, normally one would use the Enum class, but I guess it might not be an option on python 2.x. Unless renpy is messing with the str() function, You might have a case of the Cursed Computer. Maybe you can drop the str() and just use 'Enum' or r'Enum', adding a debug print may also be a good idea, y'know, just to check if this is really the source of the problem e.g: print type(str('Enum')) should print out "<type 'str'>".
 
  • Like
Reactions: Bip

Bip

Active Member
Donor
May 4, 2017
734
2,100
shark_inna_hat
I must admit that all this is well beyond my level, but well done for the check of the str!

Code:
$ print (type(str('Enum')))   <type 'unicode'>
$ print (type(r'Enum'))       <type 'unicode'>
$ print (type('Enum'))        <type 'unicode'>

$ print (type('Enum'.encode('ascii')))   <type 'str'>            !!!!!  <mode dancingQueen ON>
However, since I get some 'tuple index out of range' (A priori not directly related to the previous stuff) now that I can start it, I'll give up and move on to another game (the configuration of my computer makes it uncomfortable to use Renpy 7.3.5 and below, especially with low resolutions games).
This is the first time, and I hope the last, that the upgrade to Renpy 7.4.8 has caused problems.

In any case, thanks for the str tip!! I'll not try to understand why, but it's useful to know...
 

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,581
2,219
I know later versions of RenPy are moving towards Python 3.

Whilst I don't know for sure, I suspect that it's going to be something to do with that. (Maybe some sort of different code compliance requirements for the two flavors of Python?)

I do seem to remember a discussion by anne O'nymous semi-recently about Python 3 treating str() differently. Though I couldn't find it when I searched. How that relates to Enum() is beyond my below basic python knowledge.

Closest reference my unqualified mind could find was that that Python 2 could cope with str() being treated as both unicode and bytecode, whereas Python 3 separated them explicitly. With luck, that will mean more to you than it does to me.
 
  • Like
Reactions: Bip

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,368
15,282
I do seem to remember a discussion by anne O'nymous semi-recently about Python 3 treating str() differently.
Basically, with Python 2.x str return a string in the current encoding, while with Python 3.x it return a string in Unicode.
Now for the current problem, there's one error, and one thing that puzzle me.

The error is in the original code, type( str('Enum'), [...] ).
Since Python 2.x type do not accept a string in Unicode, while Ren'py automatically change all strings in Unicode,
I understand the use of str. But from a human point of view str( 'Enum' ) just mean transform the string 'Enum' into the string 'Enum' ; what is somehow relatively useless.
It works because from the point of view of Python, it mean transform the string u'Enum' (UTF-8) into the string 'Enum' (locale encoding). But this is not how you should change the encoding of a string, what lead to the error once str start to return the string in another encoding than the one assumed.
If the code was right from the start, and therefore used str.encode(), the error wouldn't had appear.

This being said, everyone fall for this one when coding for Ren'py ; if I remember correctly, there were even some occurrence in the core.


As for what puzzle me, it's that type continue to not accept Unicode, while it's the default encoding for every string in Python 3.x. But this can be a side effect of the fact that Ren'py is still a mix between Python 2.x and Python 3.x ; I honestly don't remember how type react in pure Python 3.x.


In the end, the solution is to correctly change the encoding of the string:
Code:
   def enum(**enums):
         return type('Enum'.encode( "ascii" ), (), enums)
And now it works whatever the version of Ren'py.
 

Bip

Active Member
Donor
May 4, 2017
734
2,100
Basically, with Python 2.x str return a string in the current encoding, while with Python 3.x it return a string in Unicode.
Ok, so str still return a string in the current encoding, it's just that the default encoding changed with Renpy 7.4.x / Python 3.x. It's actually quite logical.

This being said, everyone fall for this one when coding for Ren'py ; if I remember correctly, there were even some occurrence in the core.
Yep, this is what I found everywhere on the net, even on Python tutorials, so I didn't even think about testing what I was sending back. It's when shark_inna_hat pointed out this possibility that I realized it and found the .encode( "ascii" ).

In the end, the solution is to correctly change the encoding of the string:
Code:
   def enum(**enums):
         return type('Enum'.encode( "ascii" ), (), enums)
And now it works whatever the version of Ren'py.
It is therefore the proper solution, I'll have to remember it! Thanks for the explanations!!!