plugins/python/sudo_python_module.c: use IntEnums instead of constants

It is a bit more code, but it is more "pythonic" and easier to debug
as the enum values also know their names.

It is also an API break, eg. sudo.RC_OK becomes sudo.RC.OK as sudo.RC will
be the "type" of the enum, but I guess that is acceptable before the
initial release.
This commit is contained in:
Robert Manner
2020-02-04 13:50:26 +01:00
committed by Todd C. Miller
parent 67ab6fd5d6
commit 21c02e1732
12 changed files with 170 additions and 79 deletions

View File

@@ -498,6 +498,44 @@ cleanup:
debug_return_ptr(py_class);
}
void
sudo_module_register_enum(PyObject *py_module, const char *enum_name, PyObject *py_constants_dict)
{
// pseudo code:
// return IntEnum('MyEnum', {'DEFINITION_NAME': DEFINITION_VALUE, ...})
debug_decl(sudo_module_register_enum, PYTHON_DEBUG_INTERNAL);
if (py_constants_dict == NULL)
return;
PyObject *py_enum_class = NULL;
{
PyObject *py_enum_module = PyImport_ImportModule("enum");
if (py_enum_module == NULL) {
Py_CLEAR(py_constants_dict);
debug_return;
}
py_enum_class = PyObject_CallMethod(py_enum_module,
"IntEnum", "sO", enum_name,
py_constants_dict);
Py_CLEAR(py_constants_dict);
Py_CLEAR(py_enum_module);
}
if (py_enum_class == NULL) {
debug_return;
}
if (PyModule_AddObject(py_module, enum_name, py_enum_class) < 0) {
Py_CLEAR(py_enum_class);
debug_return;
}
debug_return;
}
PyMODINIT_FUNC
sudo_module_init(void)
@@ -525,35 +563,41 @@ sudo_module_init(void)
MODULE_ADD_EXCEPTION(SudoException, NULL);
MODULE_ADD_EXCEPTION(ConversationInterrupted, EXC_VAR(SudoException));
#define MODULE_REGISTER_ENUM(name, key_values) \
sudo_module_register_enum(py_module, name, py_dict_create_string_int(\
sizeof(key_values) / sizeof(struct key_value_str_int), key_values))
// constants
#define MODULE_ADD_INT_CONSTANT(constant) \
do { \
if (PyModule_AddIntConstant(py_module, #constant, SUDO_ ## constant) != 0) \
goto cleanup; \
} while(0)
struct key_value_str_int constants_rc[] = {
{"OK", SUDO_RC_OK},
{"ACCEPT", SUDO_RC_ACCEPT},
{"REJECT", SUDO_RC_REJECT},
{"ERROR", SUDO_RC_ERROR},
{"USAGE_ERROR", SUDO_RC_USAGE_ERROR}
};
MODULE_REGISTER_ENUM("RC", constants_rc);
MODULE_ADD_INT_CONSTANT(RC_OK);
MODULE_ADD_INT_CONSTANT(RC_ACCEPT);
MODULE_ADD_INT_CONSTANT(RC_REJECT);
MODULE_ADD_INT_CONSTANT(RC_ERROR);
MODULE_ADD_INT_CONSTANT(RC_USAGE_ERROR);
struct key_value_str_int constants_conv[] = {
{"PROMPT_ECHO_OFF", SUDO_CONV_PROMPT_ECHO_OFF},
{"PROMPT_ECHO_ON", SUDO_CONV_PROMPT_ECHO_ON},
{"INFO_MSG", SUDO_CONV_INFO_MSG},
{"PROMPT_MASK", SUDO_CONV_PROMPT_MASK},
{"PROMPT_ECHO_OK", SUDO_CONV_PROMPT_ECHO_OK},
{"PREFER_TTY", SUDO_CONV_PREFER_TTY}
};
MODULE_REGISTER_ENUM("CONV", constants_conv);
MODULE_ADD_INT_CONSTANT(CONV_PROMPT_ECHO_OFF);
MODULE_ADD_INT_CONSTANT(CONV_PROMPT_ECHO_ON);
MODULE_ADD_INT_CONSTANT(CONV_ERROR_MSG);
MODULE_ADD_INT_CONSTANT(CONV_INFO_MSG);
MODULE_ADD_INT_CONSTANT(CONV_PROMPT_MASK);
MODULE_ADD_INT_CONSTANT(CONV_PROMPT_ECHO_OK);
MODULE_ADD_INT_CONSTANT(CONV_PREFER_TTY);
MODULE_ADD_INT_CONSTANT(DEBUG_CRIT);
MODULE_ADD_INT_CONSTANT(DEBUG_ERROR);
MODULE_ADD_INT_CONSTANT(DEBUG_WARN);
MODULE_ADD_INT_CONSTANT(DEBUG_NOTICE);
MODULE_ADD_INT_CONSTANT(DEBUG_DIAG);
MODULE_ADD_INT_CONSTANT(DEBUG_INFO);
MODULE_ADD_INT_CONSTANT(DEBUG_TRACE);
MODULE_ADD_INT_CONSTANT(DEBUG_DEBUG);
struct key_value_str_int constants_debug[] = {
{"CRIT", SUDO_DEBUG_CRIT},
{"ERROR", SUDO_DEBUG_ERROR},
{"WARN", SUDO_DEBUG_WARN},
{"NOTICE", SUDO_DEBUG_NOTICE},
{"DIAG", SUDO_DEBUG_DIAG},
{"INFO", SUDO_DEBUG_INFO},
{"TRACE", SUDO_DEBUG_TRACE},
{"DEBUG", SUDO_DEBUG_DEBUG}
};
MODULE_REGISTER_ENUM("DEBUG", constants_debug);
// classes
if (sudo_module_register_conv_message(py_module) != SUDO_RC_OK)