1 /***************************************
2 ** Tsunagari Tile Engine **
3 ** python-importer.cpp **
4 ** Copyright 2011-2013 PariahSoft LLC **
5 ***************************************/
8 // Permission is hereby granted, free of charge, to any person obtaining a copy
9 // of this software and associated documentation files (the "Software"), to
10 // deal in the Software without restriction, including without limitation the
11 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
12 // sell copies of the Software, and to permit persons to whom the Software is
13 // furnished to do so, subject to the following conditions:
15 // The above copyright notice and this permission notice shall be included in
16 // all copies or substantial portions of the Software.
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
30 #include "formatter.h"
33 #include "python-importer.h"
36 //! List of known safe Python modules allowed for importing.
37 static const char* module_whitelist
[] = {
45 static bool wi_in_whitelist(const char* name
)
47 for (int i
= 0; module_whitelist
[i
]; i
++)
48 if (!strcmp(name
, module_whitelist
[i
]))
53 static PyObject
* wi_find_module(PyObject
* /*self*/, PyObject
* args
)
55 PyObject
* fullname
= NULL
;
56 PyObject
* path
= NULL
; // dummy
58 if (!PyArg_UnpackTuple(args
, "find_module", 1, 2, &fullname
, &path
)) {
62 if (!PyString_Check(fullname
)) {
63 PyErr_Format(PyExc_TypeError
, "expected string, got %.200s",
64 fullname
->ob_type
->tp_name
);
68 const char* dotname
= PyString_AsString(fullname
); // "foo.bar"
69 std::string
slashname(dotname
); // "foo/bar.py"
70 std::replace(slashname
.begin(), slashname
.end(), '.', '/');
72 Log::info("PyWorldImporter", Formatter("%: requested") % dotname
);
74 // Returning Py_None allows the import to continue. NULL stops it.
75 if (wi_in_whitelist(dotname
)) {
79 else if (Reader::directoryExists(slashname
) && Reader::fileExists(slashname
+ "/__init__.py")) {
83 else if (Reader::resourceExists(slashname
+ ".py")) {
88 PyErr_Format(PyExc_ImportError
, "No module name %.200s", dotname
);
95 } worldimporterobject
;
97 static PyMethodDef pyworldimporter_methods
[] = {
98 {"find_module", (PyCFunction
)wi_find_module
, METH_VARARGS
, NULL
},
99 {NULL
, NULL
, 0, NULL
},
102 static bool initted
= false;
103 static PyTypeObject worldimporter_type
= {
104 PyObject_HEAD_INIT(&PyType_Type
)
107 static bool wi_init_type()
112 worldimporter_type
.tp_name
= "worldimporter";
113 worldimporter_type
.tp_basicsize
= sizeof(worldimporterobject
);
114 worldimporter_type
.tp_getattro
= PyObject_GenericGetAttr
;
115 worldimporter_type
.tp_flags
= Py_TPFLAGS_DEFAULT
;
116 worldimporter_type
.tp_methods
= pyworldimporter_methods
;
118 if (PyType_Ready(&worldimporter_type
) < 0) {
119 Py_FatalError("Can't initialize worldimporter type");
126 static PyObject
* wi_worldimporter_new()
129 return (PyObject
*)PyObject_New(worldimporterobject
, &worldimporter_type
);
133 /** Public functions **/
135 bool pythonImporterInstall()
137 PyObject
* meta_path
= NULL
;
138 PyObject
* importer
= NULL
;
141 /* meta_path is a borrowed reference; no decref */
142 meta_path
= PySys_GetObject((char*)"meta_path");
143 if (meta_path
== NULL
|| !PyList_Check(meta_path
)) {
144 Log::fatal("Python Importer",
145 "sys.meta_path must be a list of import hooks");
149 importer
= wi_worldimporter_new();
150 if (importer
== NULL
) {
151 Log::fatal("Python Importer",
152 "failed to create PyWorldImporter object");
156 idx
= PyList_Append(meta_path
, importer
);
158 Log::fatal("Python Importer", "failed to append to sys.meta_path");
166 Py_XDECREF(importer
);