In my app, I am passing error reasons in my JSON API like this: {"ok": false, "reason": "EMAIL_ALREADY_REGISTERED"}
. However, using plain strings like this is very vulnerable to errors like typing just "EMAIL_REGISTERED"
, or various typos.
So I thought about creating some util to only allow fixed set of values. My first idea was Enum:
from enum import Enum
class ErrorReason(Enum):
EXCEPTION = 1
EMAIL_ALREADY_REGISTERED = 2
PASSWORD_TOO_SHORT = 3
This is great that IDE (PyCharm) automatically suggests me possible values when I type ErrorReason.E
and checks if the given value is valid, however, it has drawbacks too:
- there are unnecessary numeric values that I don't ever need
- serializing this value when passing it around:
str
creates"ErrorReason.EXCEPTION"
, but I can also doErrorReason.EXCEPTION.name
, or.value
(getting the numeric value), andflask.jsonify
doesn't support it by default, so I need to set a JSON serializer subclass - it also feels to me that this isn't a correct/intended use of Enum
One other way to do this could be this:
class ErrorReason:
EXCEPTION = "EXCEPTION"
EMAIL_ALREADY_REGISTERED = "EMAIL_ALREADY_REGISTERED"
PASSWORD_TOO_SHORT = "PASSWORD_TOO_SHORT"
This looks a bit cleaner, and ErrorReason.EXCEPTION
evaluates to simple string, but it feels wrong too – I have to write every possible value twice, and object with this sole purpose feels overkill to me.
What is the best way to achieve this? Or at least, what's the best way to create the "dumb" simple object in the last example without typing everything twice, while keeping smart IDE suggestions?
Edit 1: I found a way to generate the given class. However, even though I generate annotations, PyCharm still doesn't do any autocomplete suggesting.
_attrs = {"__annotations__": {}}
for reason in ("EXCEPTION", "PASSWORD_TOO_SHORT", "EMAIL_ALREADY_REGISTERED"):
_attrs[reason] = reason
_attrs["__annotations__"][reason] = str
ErrorReason = type("ErrorReason", (), _attrs)
See beginning of this answer for how are classes dynamically created.