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.

Asked By: Lumo

||

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)
Answered By: di.bezrukov

Fix how you import a Python source file directly.

  1. 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

    ...
  1. 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
Answered By: aaron
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.