Implement --exec flag and PyAutoGUI-compatible automation API
- Add --exec flag to execute multiple scripts before main program - Scripts are executed in order and share Python interpreter state - Implement full PyAutoGUI-compatible automation API in McRFPy_Automation - Add screenshot, mouse control, keyboard input capabilities - Fix Python initialization issues when multiple scripts are loaded - Update CommandLineParser to handle --exec with proper sys.argv management - Add comprehensive examples and documentation This enables automation testing by allowing test scripts to run alongside games using the same Python environment. The automation API provides event injection into the SFML render loop for UI testing. Closes #32 partially (Python interpreter emulation) References automation testing requirements
This commit is contained in:
parent
763fa201f0
commit
68c1a016b0
15 changed files with 1896 additions and 90 deletions
70
src/main.cpp
70
src/main.cpp
|
|
@ -44,15 +44,53 @@ int run_game_engine(const McRogueFaceConfig& config)
|
|||
|
||||
int run_python_interpreter(const McRogueFaceConfig& config, int argc, char* argv[])
|
||||
{
|
||||
// Create a headless game engine for automation API support
|
||||
McRogueFaceConfig engine_config = config;
|
||||
engine_config.headless = true; // Force headless mode for Python interpreter
|
||||
GameEngine* engine = new GameEngine(engine_config);
|
||||
|
||||
// Initialize Python with configuration
|
||||
McRFPy_API::init_python_with_config(config, argc, argv);
|
||||
|
||||
// Handle different Python modes
|
||||
if (!config.python_command.empty()) {
|
||||
// Execute command from -c
|
||||
int result = PyRun_SimpleString(config.python_command.c_str());
|
||||
Py_Finalize();
|
||||
return result;
|
||||
if (config.interactive_mode) {
|
||||
// Use PyRun_String to catch SystemExit
|
||||
PyObject* main_module = PyImport_AddModule("__main__");
|
||||
PyObject* main_dict = PyModule_GetDict(main_module);
|
||||
PyObject* result_obj = PyRun_String(config.python_command.c_str(),
|
||||
Py_file_input, main_dict, main_dict);
|
||||
|
||||
if (result_obj == NULL) {
|
||||
// Check if it's SystemExit
|
||||
if (PyErr_Occurred()) {
|
||||
PyObject *type, *value, *traceback;
|
||||
PyErr_Fetch(&type, &value, &traceback);
|
||||
|
||||
// If it's SystemExit and we're in interactive mode, clear it
|
||||
if (PyErr_GivenExceptionMatches(type, PyExc_SystemExit)) {
|
||||
PyErr_Clear();
|
||||
} else {
|
||||
// Re-raise other exceptions
|
||||
PyErr_Restore(type, value, traceback);
|
||||
PyErr_Print();
|
||||
}
|
||||
|
||||
Py_XDECREF(type);
|
||||
Py_XDECREF(value);
|
||||
Py_XDECREF(traceback);
|
||||
}
|
||||
} else {
|
||||
Py_DECREF(result_obj);
|
||||
}
|
||||
// Continue to interactive mode below
|
||||
} else {
|
||||
int result = PyRun_SimpleString(config.python_command.c_str());
|
||||
Py_Finalize();
|
||||
delete engine;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
else if (!config.python_module.empty()) {
|
||||
// Execute module using runpy
|
||||
|
|
@ -69,6 +107,7 @@ int run_python_interpreter(const McRogueFaceConfig& config, int argc, char* argv
|
|||
|
||||
int result = PyRun_SimpleString(run_module_code.c_str());
|
||||
Py_Finalize();
|
||||
delete engine;
|
||||
return result;
|
||||
}
|
||||
else if (!config.script_path.empty()) {
|
||||
|
|
@ -97,12 +136,33 @@ int run_python_interpreter(const McRogueFaceConfig& config, int argc, char* argv
|
|||
}
|
||||
delete[] python_argv;
|
||||
|
||||
if (config.interactive_mode && result == 0) {
|
||||
if (config.interactive_mode) {
|
||||
// Even if script had SystemExit, continue to interactive mode
|
||||
if (result != 0) {
|
||||
// Check if it was SystemExit
|
||||
if (PyErr_Occurred()) {
|
||||
PyObject *type, *value, *traceback;
|
||||
PyErr_Fetch(&type, &value, &traceback);
|
||||
|
||||
if (PyErr_GivenExceptionMatches(type, PyExc_SystemExit)) {
|
||||
PyErr_Clear();
|
||||
result = 0; // Don't exit with error
|
||||
} else {
|
||||
PyErr_Restore(type, value, traceback);
|
||||
PyErr_Print();
|
||||
}
|
||||
|
||||
Py_XDECREF(type);
|
||||
Py_XDECREF(value);
|
||||
Py_XDECREF(traceback);
|
||||
}
|
||||
}
|
||||
// Run interactive mode after script
|
||||
PyRun_InteractiveLoop(stdin, "<stdin>");
|
||||
}
|
||||
|
||||
Py_Finalize();
|
||||
delete engine;
|
||||
return result;
|
||||
}
|
||||
else if (config.interactive_mode || config.python_mode) {
|
||||
|
|
@ -110,8 +170,10 @@ int run_python_interpreter(const McRogueFaceConfig& config, int argc, char* argv
|
|||
Py_InspectFlag = 1;
|
||||
PyRun_InteractiveLoop(stdin, "<stdin>");
|
||||
Py_Finalize();
|
||||
delete engine;
|
||||
return 0;
|
||||
}
|
||||
|
||||
delete engine;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue