I am writing a flask app and have a setup function that will initialise a list of objects and write them to a file using pickle. The setup function works fine when I run the script through the terminal, however trying to load the pickled file results in the title error:
Can’t get attribute “Preset” (custom class) on <module ‘main‘ from ‘/Users/angoose/PycharmProjects/pythonProject1/.venv/bin/Flask’.
from flask import Flask, render_template, request
import pickle
global filename
filename = "static/presets.pkl"
class Preset:
def __init__(self, name: str, displayName: str, layout: str, stringData: list):
self.name = name.upper()
self.displayName = displayName
self.layout = layout
self.stringData = stringData
def __str__(self):
return f"{self.name},{self.displayName},{self.layout},{self.stringData}"
def setup() -> None:
try:
with open(filename, "rb") as f:
presets = pickle.load(f)
if not type(presets) == list or not len(presets) == 3:
raise EOFError
else:
print("hurray!")
except EOFError:
# file is empty
six = Preset("Fender", "Stratocaster", "6", ['E', 'A', 'D', 'G', 'B', 'E'])
four = Preset("JP60", "JP60", "4+2", ['E', 'A', 'D', 'G', 'B', 'E'])
three = Preset("LPStandard", "Les Paul Standard", "3+3", ['Eb', 'Ab', 'Db', 'Gb', 'Bb', 'Eb'])
with open(filename, "wb") as f:
pickle.dump([six, three, four], f, pickle.HIGHEST_PROTOCOL)
def save(obj) -> None | int:
# File mode "ab" for "append bytes"
with open(filename, "rb") as f:
presets = pickle.load(f)
if not type(presets) == list:
return 1
with open(filename, "wb") as f:
presets.append(obj)
pickle.dump(presets, f, pickle.HIGHEST_PROTOCOL)
return None
def load():
with open(filename, "rb") as f:
return pickle.load(f)
setup()
app = Flask(__name__)
@app.route("/")
def index():
name = request.args.get("name")
return render_template("index.html", name=name)
@app.route("/tune")
def tune():
x = Preset("jp60", "Stella","4+2","['E','A','D','G','B','E']")
save(x)
y = load()
return render_template("tune.html", test=y)
@app.route("/metronome")
def metronome():
return render_template("metronome.html")
I have looked around to see if others have had this issue and it looks like most times the issue is that pickle cannot find the class to reconstruct it, as pickle does not save the class itself. I have so far tried: using dill instead, moving the class definition around, checking if Flask has the right requirements (pickle module) and none have worked. The fact that pickle can work correctly in normal python (commenting out the flask sections) makes me think that this is probably flask and pickle not mixing well, which I also searched and found little to help.