Unexpected behavior from pickle.dump

Please post any questions about developing your plugin here. Please use the search function before posting!
arawra
Senior Member
Posts: 149
Joined: Fri Jun 21, 2013 6:51 am

Unexpected behavior from pickle.dump

Postby arawra » Wed May 23, 2018 6:03 am

Code: Select all

sp plugin reload rpgo
[SP] Unloading plugin 'rpgo'...
D:\csgo\csgo/addons/source-python/plugins/rpgo/player_database.db
<_io.BufferedWriter name=Path('D:\\csgo\\csgo/addons/source-python/plugins/rpgo/player_database.db')>
<built-in function dump>
WARNING: __getstate__ ADDED AS A DATABASE ATTRIBUTE

[SP] Caught an Exception:
Traceback (most recent call last):
  File "..\addons\source-python\packages\source-python\plugins\manager.py", line 217, in unload
    plugin._unload()
  File "..\addons\source-python\packages\source-python\plugins\instance.py", line 81, in _unload
    self.module.unload()
  File "..\addons\source-python\plugins\rpgo\rpgo.py", line 376, in unload
    pickle.dump(playerList, databaseFile)

TypeError: 'int' object is not callable


[SP] Successfully unloaded plugin 'rpgo'.
[SP] Loading plugin 'rpgo'...
[SP] Successfully loaded plugin 'rpgo'.


Syntax: Select all

def unload():
with open(database, 'wb') as databaseFile:
print(database)
print(databaseFile)
print(pickle.dump)
pickle.dump(playerList, databaseFile)
with open(jsonDatabase, 'w') as f:
json.dump(json.dumps(playerList), f)
message(messages['mod unloaded'])


This is only happening when playerList is populated with some data.
User avatar
quartata
Member
Posts: 77
Joined: Wed Jun 22, 2016 11:49 pm

Re: Unexpected behavior from pickle.dump

Postby quartata » Thu May 24, 2018 3:22 am

What's in playerList?
arawra
Senior Member
Posts: 149
Joined: Fri Jun 21, 2013 6:51 am

Re: Unexpected behavior from pickle.dump

Postby arawra » Thu May 24, 2018 3:48 am

Syntax: Select all

class PlayerData(dict):
def __init__(self):
self.kills = 0
self.spree = 0
self.gold = 0
self.rpgClass = messages['default class']
self.cooldown = False
self.stunTimer = None
self.speedTimer = None
self.baseSpeed = 1.0
self.pounces = 0

for eachClass in CLASSES:
self['%s'%eachClass] = {
'Level' :1,
'XP' :0
}

playerList = _PlayerList()
str_path = GAME_PATH + '/addons/source-python/plugins/rpgo/'
database = os.path.normpath(str_path + 'player_database.db')
jsonDatabase = os.path.normpath(str_path + 'player_database.json')
if os.path.isfile(database):
if not os.stat(database).st_size == 0:
with open(database, 'rb') as databaseFile:
playerList = pickle.load(databaseFile)

class _PlayerList(dict):
def __missing__(self, steamid):
index = index_from_steamid(steamid)
player = Player(index)
if steamid == 'BOT':
steamid += "_" + player.name
value = self[steamid] = PlayerData()
playerList[steamid].rpgClass = messages['default class']
if not player.is_bot():
message(messages['default class message'], player.index)
message(player.name + messages['new player'])
return value
User avatar
quartata
Member
Posts: 77
Joined: Wed Jun 22, 2016 11:49 pm

Re: Unexpected behavior from pickle.dump

Postby quartata » Thu May 24, 2018 4:14 am

Inheriting from dict is tricky, I suspect that's what's causing the error (perhaps one of your fields in PlayerData is shadowing something). I would replace inheriting dict for PlayerData with a data field containing the dict.
User avatar
Ayuto
Project Leader
Posts: 1846
Joined: Sat Jul 07, 2012 8:17 am
Location: Germany

Re: Unexpected behavior from pickle.dump

Postby Ayuto » Thu May 24, 2018 5:06 am

It could also be a missing super().__init__() call.
arawra
Senior Member
Posts: 149
Joined: Fri Jun 21, 2013 6:51 am

Re: Unexpected behavior from pickle.dump

Postby arawra » Tue May 29, 2018 1:42 am

Yeah I still have no idea whats causing this.

Code: Select all

[SP] Unloading plugin 'rpgo'...
[('__class__', <class 'rpgo.rpgo._PlayerList'>),
 ('__contains__',
  <built-in method __contains__ of _PlayerList object at 0x02D164C8>),
 ('__delattr__',
  <method-wrapper '__delattr__' of _PlayerList object at 0x02D164C8>),
 ('__delitem__',
  <method-wrapper '__delitem__' of _PlayerList object at 0x02D164C8>),
 ('__dict__', {}),
 ('__dir__', <built-in method __dir__ of _PlayerList object at 0x02D164C8>),
 ('__doc__', None),
 ('__eq__', <method-wrapper '__eq__' of _PlayerList object at 0x02D164C8>),
 ('__format__',
  <built-in method __format__ of _PlayerList object at 0x02D164C8>),
 ('__ge__', <method-wrapper '__ge__' of _PlayerList object at 0x02D164C8>),
 ('__getattribute__',
  <method-wrapper '__getattribute__' of _PlayerList object at 0x02D164C8>),
 ('__getitem__',
  <built-in method __getitem__ of _PlayerList object at 0x02D164C8>),
 ('__gt__', <method-wrapper '__gt__' of _PlayerList object at 0x02D164C8>),
 ('__hash__', None),
 ('__init__', <method-wrapper '__init__' of _PlayerList object at 0x02D164C8>),
 ('__init_subclass__',
  <built-in method __init_subclass__ of type object at 0x02CAC790>),
 ('__iter__', <method-wrapper '__iter__' of _PlayerList object at 0x02D164C8>),
 ('__le__', <method-wrapper '__le__' of _PlayerList object at 0x02D164C8>),
 ('__len__', <method-wrapper '__len__' of _PlayerList object at 0x02D164C8>),
 ('__lt__', <method-wrapper '__lt__' of _PlayerList object at 0x02D164C8>),
 ('__missing__',
  <bound method _PlayerList.__missing__ of {'STEAM_1:1:45055382': {'kills': 0, 'spree': 0, 'gold': 0, 'rpgClass': 'Warrior', 'cooldown': False, 'stunTimer': None, 'speedTimer': None, 'baseSpeed': 1.0, 'pounces': 0, 'Warrior': {'Level': 1, 'XP': 560}, 'Rogue': {'Level': 1, 'XP': 0}, 'Priest': {'Level': 1, 'XP': 0}, 'Warlock': {'Level': 1, 'XP': 0}, 'Mage': {'Level': 1, 'XP': 0}, 'Ranger': {'Level': 1, 'XP': 0}, 'Druid': {'Level': 1, 'XP': 0}, 'attr': 0}, 'BOT_Scott': {'kills': 0, 'spree': 0, 'gold': 0, 'rpgClass': 'Warrior', 'cooldown': False, 'stunTimer': None, 'speedTimer': None, 'baseSpeed': 1.0, 'pounces': 0, 'Warrior': {'Level': 1, 'XP': 0}, 'Rogue': {'Level': 1, 'XP': 0}, 'Priest': {'Level': 1, 'XP': 0}, 'Warlock': {'Level': 1, 'XP': 0}, 'Mage': {'Level': 1, 'XP': 0}, 'Ranger': {'Level': 1, 'XP': 0}, 'Druid': {'Level': 1, 'XP': 0}}, 'STEAM_1:1:22252686': {'kills': 0, 'spree': 0, 'gold': 0, 'rpgClass': 'Warrior', 'cooldown': False, 'stunTimer': None, 'speedTimer': None, 'baseSpeed': 1.0, 'pounces': 0, 'Warrior': {'Level': 1, 'XP': 280}, 'Rogue': {'Level': 1, 'XP': 0}, 'Priest': {'Level': 1, 'XP': 0}, 'Warlock': {'Level': 1, 'XP': 0}, 'Mage': {'Level': 1, 'XP': 0}, 'Ranger': {'Level': 1, 'XP': 0}, 'Druid': {'Level': 1, 'XP': 0}}, 'BOT_Tim': {'kills': 0, 'spree': 0, 'gold': 0, 'rpgClass': 'Warrior', 'cooldown': False, 'stunTimer': None, 'speedTimer': None, 'baseSpeed': 1.0, 'pounces': 0, 'Warrior': {'Level': 1, 'XP': 0}, 'Rogue': {'Level': 1, 'XP': 0}, 'Priest': {'Level': 1, 'XP': 0}, 'Warlock': {'Level': 1, 'XP': 0}, 'Mage': {'Level': 1, 'XP': 0}, 'Ranger': {'Level': 1, 'XP': 0}, 'Druid': {'Level': 1, 'XP': 0}}}>),
 ('__module__', 'rpgo.rpgo'),
 ('__ne__', <method-wrapper '__ne__' of _PlayerList object at 0x02D164C8>),
 ('__new__', <built-in method __new__ of type object at 0x1E2CF728>),
 ('__reduce__',
  <built-in method __reduce__ of _PlayerList object at 0x02D164C8>),
 ('__reduce_ex__',
  <built-in method __reduce_ex__ of _PlayerList object at 0x02D164C8>),
 ('__repr__', <method-wrapper '__repr__' of _PlayerList object at 0x02D164C8>),
 ('__setattr__',
  <method-wrapper '__setattr__' of _PlayerList object at 0x02D164C8>),
 ('__setitem__',
  <method-wrapper '__setitem__' of _PlayerList object at 0x02D164C8>),
 ('__sizeof__',
  <built-in method __sizeof__ of _PlayerList object at 0x02D164C8>),
 ('__slotnames__', []),
 ('__str__', <method-wrapper '__str__' of _PlayerList object at 0x02D164C8>),
 ('__subclasshook__',
  <built-in method __subclasshook__ of type object at 0x02CAC790>),
 ('__weakref__', None),
 ('clear', <built-in method clear of _PlayerList object at 0x02D164C8>),
 ('copy', <built-in method copy of _PlayerList object at 0x02D164C8>),
 ('fromkeys', <built-in method fromkeys of type object at 0x02CAC790>),
 ('get', <built-in method get of _PlayerList object at 0x02D164C8>),
 ('items', <built-in method items of _PlayerList object at 0x02D164C8>),
 ('keys', <built-in method keys of _PlayerList object at 0x02D164C8>),
 ('pop', <built-in method pop of _PlayerList object at 0x02D164C8>),
 ('popitem', <built-in method popitem of _PlayerList object at 0x02D164C8>),
 ('setdefault',
  <built-in method setdefault of _PlayerList object at 0x02D164C8>),
 ('update', <built-in method update of _PlayerList object at 0x02D164C8>),
 ('values', <built-in method values of _PlayerList object at 0x02D164C8>)]
WARNING: __getstate__ ADDED AS A DATABASE ATTRIBUTE

[SP] Caught an Exception:
Traceback (most recent call last):
  File "..\addons\source-python\packages\source-python\plugins\manager.py", line 217, in unload
    plugin._unload()
  File "..\addons\source-python\packages\source-python\plugins\instance.py", line 81, in _unload
    self.module.unload()
  File "..\addons\source-python\plugins\rpgo\rpgo.py", line 379, in unload
    pickle.dump(playerList, file)

TypeError: 'int' object is not callable


[SP] Successfully unloaded plugin 'rpgo'.


Syntax: Select all

def unload():
pprint(getmembers(playerList))
file = open(database, 'wb')
pickle.dump(playerList, file)
file.close()
with open(jsonDatabase, 'w') as f:
json.dump(json.dumps(playerList), f)
message(messages['mod unloaded'])
User avatar
satoon101
Project Leader
Posts: 2558
Joined: Sat Jul 07, 2012 1:59 am

Re: Unexpected behavior from pickle.dump

Postby satoon101 » Tue May 29, 2018 1:45 am

Did you do this?
Ayuto wrote:It could also be a missing super().__init__() call.

If you override dict's __init__ method, you need to call super().__init__() to fully initialize the dictionary. If you don't, it can and will lead to errors like the one you are experiencing.
Image
arawra
Senior Member
Posts: 149
Joined: Fri Jun 21, 2013 6:51 am

Re: Unexpected behavior from pickle.dump

Postby arawra » Tue May 29, 2018 2:08 am

I did find the issue.

super().__init__() had little effect. The issue was trying to override missing properties of the object.

This works fine.

Syntax: Select all

def __getattr__(self, attr):
# Redirect to __getitem__
# Can also use:
# return self[attr]
try:
return self[attr]
except KeyError:
raise AttributeError('Attribute "{0}" not found'.format(attr))


This does not.

Syntax: Select all

def __getattr__(self, attr):
# Redirect to __getitem__
# Can also use:
# return self[attr]
try:
return self[attr]
except KeyError:
if attr in CLASSES:
self['%s'%attr] = {
'Level' :1,
'XP' :0
}
else:
#print("WARNING: %s ADDED AS A DATABASE ATTRIBUTE"%attr)
self.attr = 0
return self.attr


This would set __getstate__ as an integer, which isn't what I want XD. Currently doing a solution.
User avatar
satoon101
Project Leader
Posts: 2558
Joined: Sat Jul 07, 2012 1:59 am

Re: Unexpected behavior from pickle.dump

Postby satoon101 » Tue May 29, 2018 3:19 am

That's code that was not posted previously in this thread. It's a little difficult for us to answer questions if you don't supply all relevant code.

Also, in your except/if you aren't returning anything.

Edit: I am also unsure what you are trying to do in the 'else'. You are NOT setting the given attribute to 0. You are literally setting the attribute 'attr' to 0. If you want to create the given attribute and set it (completely arbitrarily) to 0, you will want to either call self.__setattr__ or use the setattr built-in.
Image

Return to “Plugin Development Support”

Who is online

Users browsing this forum: No registered users and 2 guests