Advertisement
Guest User

Untitled

a guest
May 15th, 2019
87
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Diff 9.93 KB | None | 0 0
  1. diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c
  2. index b34a41b5af6..2164d3d2d71 100644
  3. --- a/source/blender/python/intern/bpy_interface.c
  4. +++ b/source/blender/python/intern/bpy_interface.c
  5. @@ -236,6 +236,305 @@ static struct _inittab bpy_internal_modules[] = {
  6.      {NULL, NULL},
  7.  };
  8.  
  9. +static ListBase bpy_import_main_list;
  10. +
  11. +/* returns a dummy filename for a textblock so we can tell what file a text block comes from */
  12. +void bpy_text_filename_get(char *fn, size_t fn_len, Text *text)
  13. +{
  14. +   BLI_snprintf(fn, fn_len, "%s%c%s", ID_BLEND_PATH(G_MAIN, &text->id), SEP, text->id.name + 2);
  15. +}
  16. +
  17. +static void free_compiled_text(Text *text)
  18. +{
  19. +   if (text->compiled) {
  20. +       Py_DECREF((PyObject *)text->compiled);
  21. +   }
  22. +   text->compiled = NULL;
  23. +}
  24. +
  25. +bool bpy_text_compile(Text *text)
  26. +{
  27. +   char fn_dummy[FILE_MAX];
  28. +   PyObject *fn_dummy_py;
  29. +   char *buf;
  30. +
  31. +   bpy_text_filename_get(fn_dummy, sizeof(fn_dummy), text);
  32. +
  33. +   /* if previously compiled, free the object */
  34. +   free_compiled_text(text);
  35. +
  36. +   fn_dummy_py = PyC_UnicodeFromByte(fn_dummy);
  37. +
  38. +   buf = txt_to_buf(text);
  39. +   text->compiled = Py_CompileStringObject(buf, fn_dummy_py, Py_file_input, NULL, -1);
  40. +   MEM_freeN(buf);
  41. +
  42. +   Py_DECREF(fn_dummy_py);
  43. +
  44. +   if (PyErr_Occurred()) {
  45. +       PyErr_Print();
  46. +       PyErr_Clear();
  47. +       PySys_SetObject("last_traceback", NULL);
  48. +       free_compiled_text(text);
  49. +       return false;
  50. +   }
  51. +   else {
  52. +       return true;
  53. +   }
  54. +}
  55. +
  56. +PyObject *bpy_text_import(Text *text)
  57. +{
  58. +   char modulename[MAX_ID_NAME + 2];
  59. +   int len;
  60. +
  61. +   if (!text->compiled) {
  62. +       if (bpy_text_compile(text) == false) {
  63. +           return NULL;
  64. +       }
  65. +   }
  66. +
  67. +   len = strlen(text->id.name + 2);
  68. +   BLI_strncpy(modulename, text->id.name + 2, len);
  69. +   modulename[len - 3] = '\0'; /* remove .py */
  70. +   return PyImport_ExecCodeModule(modulename, text->compiled);
  71. +}
  72. +
  73. +PyObject *bpy_text_import_name(const char *name, int *found)
  74. +{
  75. +   Text *text;
  76. +   char txtname[MAX_ID_NAME - 2];
  77. +   int namelen = strlen(name);
  78. +//XXX  Main *maggie = bpy_import_main ? bpy_import_main : G_MAIN;
  79. +   Main *maggie = G_MAIN;
  80. +
  81. +   *found = 0;
  82. +
  83. +   if (!maggie) {
  84. +       printf("ERROR: bpy_import_main_set() was not called before running python. this is a bug.\n");
  85. +       return NULL;
  86. +   }
  87. +
  88. +   /* we know this cant be importable, the name is too long for blender! */
  89. +   if (namelen >= (MAX_ID_NAME - 2) - 3)
  90. +       return NULL;
  91. +
  92. +   memcpy(txtname, name, namelen);
  93. +   memcpy(&txtname[namelen], ".py", 4);
  94. +
  95. +   text = BLI_findstring(&maggie->texts, txtname, offsetof(ID, name) + 2);
  96. +
  97. +   if (text) {
  98. +       *found = 1;
  99. +       return bpy_text_import(text);
  100. +   }
  101. +
  102. +   /* If we still haven't found the module try additional modules form bpy_import_main_list */
  103. +   maggie = bpy_import_main_list.first;
  104. +   while (maggie && !text) {
  105. +       text = BLI_findstring(&maggie->texts, txtname, offsetof(ID, name) + 2);
  106. +       maggie = maggie->next;
  107. +   }
  108. +
  109. +   if (!text)
  110. +       return NULL;
  111. +   else
  112. +       *found = 1;
  113. +
  114. +   return bpy_text_import(text);
  115. +}
  116. +
  117. +static PyObject *blender_import(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
  118. +{
  119. +   PyObject *exception, *err, *tb;
  120. +   const char *name;
  121. +   int found = 0;
  122. +   PyObject *globals = NULL, *locals = NULL, *fromlist = NULL;
  123. +   int level = 0; /* relative imports */
  124. +   PyObject *newmodule;
  125. +
  126. +   static const char *_keywords[] = {"name", "globals", "locals", "fromlist", "level", NULL};
  127. +   static _PyArg_Parser _parser = {"s|OOOi:bpy_import_meth", _keywords, 0};
  128. +   if (!_PyArg_ParseTupleAndKeywordsFast(
  129. +           args, kw, &_parser,
  130. +           &name, &globals, &locals, &fromlist, &level))
  131. +   {
  132. +       return NULL;
  133. +   }
  134. +
  135. +   /* import existing builtin modules or modules that have been imported already */
  136. +   newmodule = PyImport_ImportModuleLevel(name, globals, locals, fromlist, level);
  137. +
  138. +   if (newmodule)
  139. +       return newmodule;
  140. +
  141. +   PyErr_Fetch(&exception, &err, &tb); /* get the python error in case we cant import as blender text either */
  142. +
  143. +   /* importing from existing modules failed, see if we have this module as blender text */
  144. +   newmodule = bpy_text_import_name(name, &found);
  145. +
  146. +   if (newmodule) { /* found module as blender text, ignore above exception */
  147. +       PyErr_Clear();
  148. +       Py_XDECREF(exception);
  149. +       Py_XDECREF(err);
  150. +       Py_XDECREF(tb);
  151. +       /* printf("imported from text buffer...\n"); */
  152. +   }
  153. +   else if (found == 1) { /* blender text module failed to execute but was found, use its error message */
  154. +       Py_XDECREF(exception);
  155. +       Py_XDECREF(err);
  156. +       Py_XDECREF(tb);
  157. +       return NULL;
  158. +   }
  159. +   else {
  160. +       /* no blender text was found that could import the module
  161. +        * reuse the original error from PyImport_ImportModuleEx */
  162. +       PyErr_Restore(exception, err, tb);
  163. +   }
  164. +   return newmodule;
  165. +}
  166. +
  167. +
  168. +/*
  169. + * our reload() module, to handle reloading in-memory scripts
  170. + */
  171. +
  172. +static PyObject   *imp_reload_orig = NULL;
  173. +
  174. +/*
  175. + * find in-memory module and recompile
  176. + */
  177. +
  178. +PyObject *bpy_text_reimport(PyObject *module, int *found)
  179. +{
  180. +   Text *text;
  181. +   const char *name;
  182. +   const char *filepath;
  183. +//XXX  Main *maggie = bpy_import_main ? bpy_import_main : G_MAIN;
  184. +   Main *maggie = G_MAIN;
  185. +
  186. +   if (!maggie) {
  187. +       printf("ERROR: bpy_import_main_set() was not called before running python. this is a bug.\n");
  188. +       return NULL;
  189. +   }
  190. +
  191. +   *found = 0;
  192. +
  193. +   /* get name, filename from the module itself */
  194. +   if ((name = PyModule_GetName(module)) == NULL)
  195. +       return NULL;
  196. +
  197. +   {
  198. +       PyObject *module_file = PyModule_GetFilenameObject(module);
  199. +       if (module_file == NULL) {
  200. +           return NULL;
  201. +       }
  202. +       filepath = _PyUnicode_AsString(module_file);
  203. +       Py_DECREF(module_file);
  204. +       if (filepath == NULL) {
  205. +           return NULL;
  206. +       }
  207. +   }
  208. +
  209. +   /* look up the text object */
  210. +   text = BLI_findstring(&maggie->texts, BLI_path_basename(filepath), offsetof(ID, name) + 2);
  211. +
  212. +   /* uh-oh.... didn't find it */
  213. +   if (!text)
  214. +       return NULL;
  215. +   else
  216. +       *found = 1;
  217. +
  218. +   if (bpy_text_compile(text) == false) {
  219. +       return NULL;
  220. +   }
  221. +
  222. +   /* make into a module */
  223. +   return PyImport_ExecCodeModule(name, text->compiled);
  224. +}
  225. +
  226. +static PyObject *blender_reload(PyObject *UNUSED(self), PyObject *module)
  227. +{
  228. +   PyObject *exception, *err, *tb;
  229. +   PyObject *newmodule = NULL;
  230. +   int found = 0;
  231. +
  232. +   /* try reimporting from file */
  233. +
  234. +   /* in Py3.3 this just calls imp.reload() which we overwrite, causing recursive calls */
  235. +   //newmodule = PyImport_ReloadModule(module);
  236. +
  237. +   newmodule = PyObject_CallFunctionObjArgs(imp_reload_orig, module, NULL);
  238. +
  239. +   if (newmodule)
  240. +       return newmodule;
  241. +
  242. +   /* no file, try importing from memory */
  243. +   PyErr_Fetch(&exception, &err, &tb); /*restore for probable later use */
  244. +
  245. +   newmodule = bpy_text_reimport(module, &found);
  246. +   if (newmodule) { /* found module as blender text, ignore above exception */
  247. +       PyErr_Clear();
  248. +       Py_XDECREF(exception);
  249. +       Py_XDECREF(err);
  250. +       Py_XDECREF(tb);
  251. +       /* printf("imported from text buffer...\n"); */
  252. +   }
  253. +   else if (found == 1) { /* blender text module failed to execute but was found, use its error message */
  254. +       Py_XDECREF(exception);
  255. +       Py_XDECREF(err);
  256. +       Py_XDECREF(tb);
  257. +       return NULL;
  258. +   }
  259. +   else {
  260. +       /* no blender text was found that could import the module
  261. +        * reuse the original error from PyImport_ImportModuleEx */
  262. +       PyErr_Restore(exception, err, tb);
  263. +   }
  264. +
  265. +   return newmodule;
  266. +}
  267. +
  268. +static PyMethodDef bpy_import_meth = {"bpy_import_meth", (PyCFunction)blender_import, METH_VARARGS | METH_KEYWORDS, "blenders import"};
  269. +static PyMethodDef bpy_reload_meth = {"bpy_reload_meth", (PyCFunction)blender_reload, METH_O, "blenders reload"};
  270. +
  271. +/**
  272. + * \note to the discerning developer, yes - this is nasty
  273. + * monkey-patching our own import into Python's builtin 'imp' module.
  274. + *
  275. + * However Python's alternative is to use import hooks,
  276. + * which are implemented in a way that we can't use our own importer as a
  277. + * fall-back (instead we must try and fail - raise an exception every time).
  278. + * Since importing from blenders text-blocks is not the common case
  279. + * I prefer to use Pythons import by default and fall-back to
  280. + * Blenders - which we can only do by intercepting import calls I'm afraid.
  281. + * - Campbell
  282. + */
  283. +void bpy_import_init(PyObject *builtins)
  284. +{
  285. +   PyObject *item;
  286. +   PyObject *mod;
  287. +
  288. +   PyDict_SetItemString(builtins, "__import__", item = PyCFunction_New(&bpy_import_meth, NULL)); Py_DECREF(item);
  289. +
  290. +   /* move reload here
  291. +    * XXX, use import hooks */
  292. +   mod = PyImport_ImportModuleLevel("importlib", NULL, NULL, NULL, 0);
  293. +   if (mod) {
  294. +       PyObject *mod_dict = PyModule_GetDict(mod);
  295. +
  296. +       /* blender owns the function */
  297. +       imp_reload_orig = PyDict_GetItemString(mod_dict, "reload");
  298. +       Py_INCREF(imp_reload_orig);
  299. +
  300. +       PyDict_SetItemString(mod_dict, "reload", item = PyCFunction_New(&bpy_reload_meth, NULL)); Py_DECREF(item);
  301. +       Py_DECREF(mod);
  302. +   }
  303. +   else {
  304. +       BLI_assert(!"unable to load 'importlib' module.");
  305. +   }
  306. +}
  307. +
  308.  /* call BPY_context_set first */
  309.  void BPY_python_start(int argc, const char **argv)
  310.  {
  311. @@ -327,6 +626,8 @@ void BPY_python_start(int argc, const char **argv)
  312.    /* bpy.* and lets us import it */
  313.    BPy_init_modules();
  314.  
  315. +  bpy_import_init(PyEval_GetBuiltins());
  316. +
  317.    pyrna_alloc_types();
  318.  
  319.  #ifndef WITH_PYTHON_MODULE
  320. @@ -423,12 +724,6 @@ typedef struct {
  321.  } PyModuleObject;
  322.  #endif
  323.  
  324. -/* returns a dummy filename for a textblock so we can tell what file a text block comes from */
  325. -static void bpy_text_filename_get(char *fn, const Main *bmain, size_t fn_len, const Text *text)
  326. -{
  327. -  BLI_snprintf(fn, fn_len, "%s%c%s", ID_BLEND_PATH(bmain, &text->id), SEP, text->id.name + 2);
  328. -}
  329. -
  330.  static bool python_script_exec(
  331.      bContext *C, const char *fn, struct Text *text, struct ReportList *reports, const bool do_jump)
  332.  {
  333. @@ -449,7 +744,7 @@ static bool python_script_exec(
  334.  
  335.    if (text) {
  336.      char fn_dummy[FILE_MAXDIR];
  337. -    bpy_text_filename_get(fn_dummy, bmain_old, sizeof(fn_dummy), text);
  338. +    bpy_text_filename_get(fn_dummy, /*bmain_old,*/ sizeof(fn_dummy), text);
  339.  
  340.      if (text->compiled == NULL) { /* if it wasn't already compiled, do it now */
  341.        char *buf;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement