You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

163 lines
4.6 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2012 NBEE Embedded Systems, Miguel Angel Ajo <miguelangel@nbee.es>
  5. * Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors.
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * as published by the Free Software Foundation; either version 2
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, you may find one here:
  19. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  20. * or you may search the http://www.gnu.org website for the version 2 license,
  21. * or you may write to the Free Software Foundation, Inc.,
  22. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  23. */
  24. /**
  25. * @file python_scripting.cpp
  26. * @brief methods to add scripting capabilities inside pcbnew
  27. */
  28. #include <python_scripting.h>
  29. #include <cstdlib>
  30. #include <cstring>
  31. #include <Python.h>
  32. #include <sstream>
  33. #include <eda_base_frame.h>
  34. #include <gal/color4d.h>
  35. #include <trace_helpers.h>
  36. #include <string_utils.h>
  37. #include <macros.h>
  38. #include <paths.h>
  39. #include <settings/settings_manager.h>
  40. #include <kiplatform/environment.h>
  41. #include <wx/app.h>
  42. #include <config.h>
  43. /**
  44. * Run a python method from the pcbnew module.
  45. *
  46. * @param aMethodName is the name of the method (like "pcbnew.myfunction" ).
  47. * @param aNames will contain the returned string.
  48. */
  49. static void pcbnewRunPythonMethodWithReturnedString( const char* aMethodName, wxString& aNames )
  50. {
  51. aNames.Clear();
  52. PyLOCK lock;
  53. PyErr_Clear();
  54. PyObject* builtins = PyImport_ImportModule( "pcbnew" );
  55. wxASSERT( builtins );
  56. if( !builtins ) // Something is wrong in pcbnew.py module (incorrect version?)
  57. return;
  58. PyObject* globals = PyDict_New();
  59. PyDict_SetItemString( globals, "pcbnew", builtins );
  60. Py_DECREF( builtins );
  61. // Build the python code
  62. char cmd[1024];
  63. snprintf( cmd, sizeof(cmd), "result = %s()", aMethodName );
  64. // Execute the python code and get the returned data
  65. PyObject* localDict = PyDict_New();
  66. PyObject* pobj = PyRun_String( cmd, Py_file_input, globals, localDict);
  67. Py_DECREF( globals );
  68. if( pobj )
  69. {
  70. PyObject* str = PyDict_GetItemString(localDict, "result" );
  71. const char* str_res = nullptr;
  72. if(str)
  73. {
  74. PyObject* temp_bytes = PyUnicode_AsEncodedString( str, "UTF-8", "strict" );
  75. if( temp_bytes != nullptr )
  76. {
  77. str_res = PyBytes_AS_STRING( temp_bytes );
  78. aNames = FROM_UTF8( str_res );
  79. Py_DECREF( temp_bytes );
  80. }
  81. else
  82. {
  83. wxLogMessage( "cannot encode Unicode python string" );
  84. }
  85. }
  86. else
  87. {
  88. aNames = wxString();
  89. }
  90. Py_DECREF( pobj );
  91. }
  92. Py_DECREF( localDict );
  93. if( PyErr_Occurred() )
  94. {
  95. if( strcmp( aMethodName, "pcbnew.GetWizardsBackTrace" ) == 0 )
  96. aNames = PyErrStringWithTraceback();
  97. else
  98. wxLogMessage( PyErrStringWithTraceback() );
  99. }
  100. }
  101. void pcbnewGetUnloadableScriptNames( wxString& aNames )
  102. {
  103. pcbnewRunPythonMethodWithReturnedString( "pcbnew.GetUnLoadableWizards", aNames );
  104. }
  105. void pcbnewGetScriptsSearchPaths( wxString& aNames )
  106. {
  107. pcbnewRunPythonMethodWithReturnedString( "pcbnew.GetWizardsSearchPaths", aNames );
  108. }
  109. void pcbnewGetWizardsBackTrace( wxString& aTrace )
  110. {
  111. pcbnewRunPythonMethodWithReturnedString( "pcbnew.GetWizardsBackTrace", aTrace );
  112. // Filter message before displaying them
  113. // a trace starts by "Traceback" and is followed by 2 useless lines
  114. // for our purpose
  115. wxArrayString traces;
  116. wxStringSplit( aTrace, traces, '\n' );
  117. // Build the filtered message (remove useless lines)
  118. aTrace.Clear();
  119. for( unsigned ii = 0; ii < traces.Count(); ++ii )
  120. {
  121. if( traces[ii].Contains( wxT( "Traceback" ) ) )
  122. {
  123. ii += 2; // Skip this line and next lines which are related to pcbnew.py module
  124. if( !aTrace.IsEmpty() ) // Add separator for the next trace block
  125. aTrace << wxT( "\n**********************************\n" );
  126. }
  127. else
  128. {
  129. aTrace += traces[ii] + wxT( "\n" );
  130. }
  131. }
  132. }