Can't pickle <class>: import of module failed
Question:
I am using https://github.com/ekonda/kutana.
plugins/test.py:
from kutana import Plugin
import pickle
plugin = Plugin(name="Tictactoe",
description="Tictactoe Game",
invites={},
games=[])
@plugin.on_start()
async def _():
plugin.games = [Game()]
# Backup games when bot is shutting down
@plugin.on_shutdown()
async def _():
try:
with open("games.pickle", "wb") as f:
pickle.dump(plugin.games, f)
except Exception as e:
print(e)
class Game:
def __init__(self):
pass
run.py:
from kutana import Kutana, load_plugins
# Create application
app = Kutana()
# Load and register plugins
app.add_plugins(load_plugins("plugins/"))
if __name__ == "__main__":
# Run application
app.run()
When plugin.games
is empty, pickle
dumps without errors. But if I put any created object of class Game
here, I get an error when trying to backup:
Traceback (most recent call last):
File "C:UsersrootDesktopCelestianapluginsgamestictactoe.py", line 17, in _
pickle.dump(pl.games, f)
_pickle.PicklingError: Can't pickle <class 'plugins/gamestictactoe.py.Game'>: import of module 'plugins/games\tictactoe.py' failed
How can I fix it? I try to do something like pickle.dump(plugin.games, f, fix_imports=True)
but it does not work.
Answers:
Try it
game = Game(ctx, chat_id, players)
# Add the game to the list of games
pl.games.append(game)
# Backup the games when shutting down
@pl.on_shutdown()
async def _():
try:
with open("games.pickle", "wb") as f:
pickle.dump(pl.games, f)
except Exception as e:
print(e)
Fix how you import a Python source file directly.
- In
load_plugins_from_file
, specify the correct name.
def load_plugins_from_file(path, verbose=False):
...
# mod = import_module(path, path) # Change this
name = path.split(".py")[0].replace("/", ".") # to these
mod = import_module(name, path) # two lines
...
- In your custom
import_module
, insert the module into sys.modules
as shown in the recipe https://docs.python.org/3/library/importlib.html#importing-a-source-file-directly.
def import_module(name, path):
...
spec = importlib.util.spec_from_file_location(name, os.path.abspath(path))
module = importlib.util.module_from_spec(spec)
sys.modules[name] = module # Add this
spec.loader.exec_module(module)
return module
I am using https://github.com/ekonda/kutana.
plugins/test.py:
from kutana import Plugin
import pickle
plugin = Plugin(name="Tictactoe",
description="Tictactoe Game",
invites={},
games=[])
@plugin.on_start()
async def _():
plugin.games = [Game()]
# Backup games when bot is shutting down
@plugin.on_shutdown()
async def _():
try:
with open("games.pickle", "wb") as f:
pickle.dump(plugin.games, f)
except Exception as e:
print(e)
class Game:
def __init__(self):
pass
run.py:
from kutana import Kutana, load_plugins
# Create application
app = Kutana()
# Load and register plugins
app.add_plugins(load_plugins("plugins/"))
if __name__ == "__main__":
# Run application
app.run()
When plugin.games
is empty, pickle
dumps without errors. But if I put any created object of class Game
here, I get an error when trying to backup:
Traceback (most recent call last):
File "C:UsersrootDesktopCelestianapluginsgamestictactoe.py", line 17, in _
pickle.dump(pl.games, f)
_pickle.PicklingError: Can't pickle <class 'plugins/gamestictactoe.py.Game'>: import of module 'plugins/games\tictactoe.py' failed
How can I fix it? I try to do something like pickle.dump(plugin.games, f, fix_imports=True)
but it does not work.
Try it
game = Game(ctx, chat_id, players)
# Add the game to the list of games
pl.games.append(game)
# Backup the games when shutting down
@pl.on_shutdown()
async def _():
try:
with open("games.pickle", "wb") as f:
pickle.dump(pl.games, f)
except Exception as e:
print(e)
Fix how you import a Python source file directly.
- In
load_plugins_from_file
, specify the correct name.
def load_plugins_from_file(path, verbose=False):
...
# mod = import_module(path, path) # Change this
name = path.split(".py")[0].replace("/", ".") # to these
mod = import_module(name, path) # two lines
...
- In your custom
import_module
, insert the module intosys.modules
as shown in the recipe https://docs.python.org/3/library/importlib.html#importing-a-source-file-directly.
def import_module(name, path):
...
spec = importlib.util.spec_from_file_location(name, os.path.abspath(path))
module = importlib.util.module_from_spec(spec)
sys.modules[name] = module # Add this
spec.loader.exec_module(module)
return module