Python - ModuleNotFoundError when changing name of flask application to app.py. Possible solutions?

Viewed 90

I have recently changed my main flask app file from inputServer.py to app.py to increase ease of use.

My code that throws the error is as follows:

def readBackupPlayers(objectFile):
    with open(objectFile, 'rb') as openedFile:
        manager.playerList = pickle.load(openedFile)
    print('Backup of players retrieved')

^ Function that read a custom pickle file used for backing up a list stored inside a custom object

class PlayerManager:
    def __init__(self):
        self.playerList = []
        self.ID = len(self.playerList) + 1
        self.currentGame = None
        self.tournament = None


manager = PlayerManager()

^ Code that declares the class and creates an instance of it to use to store variables across the program.

Error message:

File "c:\users\simon\appdata\local\programs\python\python38-32\lib\site-packages\flask\app.py", line 1936, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "C:\Users\simon\OneDrive\Documents\AtomTesting\app.py", line 356, in setup
    readBackupPlayers('Backups/playerBackup')
  File "C:\Users\simon\OneDrive\Documents\AtomTesting\app.py", line 72, in readBackupPlayers
    manager.playerList = pickle.load(openedFile)
ModuleNotFoundError: No module named 'inputServer'

Directory:

AtomTesting -
   Backups -
      playerBackup
      tournamentBackup
   Static -
      static Flask files (not relevant)
   templates -
      Flask templates (not relevant)
   app.py (renamed from inputServer.py)
   config.py
   README.md
1 Answers

Here's what's happening. Python's pickle module serializes and deserializes (dumps and loads) Python objects based on their name. Since the name of the module where your class lives changed, Pickle can't figure out how to re-instanciate those objects.

There is, however, a solution which is detailed on the Python wiki. It involves mapping old names to new names:

import pickle


renametable = {
    'inputServer': 'app',
    }

def mapname(name):
    if name in renametable:
        return renametable[name]
    return name

def mapped_load_global(self):
    module = mapname(self.readline()[:-1])
    name = mapname(self.readline()[:-1])
    klass = self.find_class(module, name)
    self.append(klass)

def loads(str):
    file = StringIO(str)
    unpickler = pickle.Unpickler(file)
    unpickler.dispatch[pickle.GLOBAL] = mapped_load_global
    return unpickler.load()

Alternatively, and this is probably a better approach, you shouldn't use pickle for any serious data store, especially when something might be used between versions of your app.

You might consider using an ORM with a lightweight database, like SQLite.

Related