FLAME  devel
 All Classes Functions Variables Typedefs Enumerations Pages
modmain.cpp
1 
2 #include <list>
3 #include <sstream>
4 
5 #include "flame/base.h"
6 #include "pyflame.h"
7 
8 #define PY_ARRAY_UNIQUE_SYMBOL FLAME_PyArray_API
9 #define NPY_NO_DEPRECATED_API NPY_1_6_API_VERSION
10 #include <numpy/ndarrayobject.h>
11 
12 namespace {
13 
14 #define FLAME_LOGGER_NAME "flame.machine"
15 
16 // redirect flame logging to python logger
17 // Assumes interpreter lock is held
18 struct PyLogger : public Machine::Logger
19 {
20  PyRef<> logger;
21  virtual void log(const Machine::LogRecord &r)
22  {
23  if(logger.py()) {
24  std::string msg(r.strm.str());
25  size_t pos = msg.find_last_not_of('\n');
26  if(pos!=msg.npos)
27  msg = msg.substr(0, pos);
28 
29  // name, level, function name, lineno, message, args, exc_info
30  PyRef<> rec(PyObject_CallMethod(logger.py(), "makeRecord", "sHsHsOO",
31  FLAME_LOGGER_NAME, r.level, r.fname, r.lnum,
32  msg.c_str(), Py_None, Py_None));
33  PyRef<> junk(PyObject_CallMethod(logger.py(), "handle", "O", rec.py()));
34  }
35  }
36  static void noopdtor(Machine::Logger*) {}
37  static void unreg()
38  {
39  singleton.logger.clear();
40  }
41 
42  static PyLogger singleton;
43 };
44 
45 PyLogger PyLogger::singleton;
46 
47 static
48 PyObject* py_set_log(PyObject *unused, PyObject *args)
49 {
50  unsigned short lvl;
51  if(!PyArg_ParseTuple(args, "H", &lvl))
52  return NULL;
53  // no locking here as races only result in messages being displayed (or not)
54  Machine::log_detail = lvl;
55  Py_RETURN_NONE;
56 }
57 
58 static
59 PyObject* py_get_log(PyObject *unused)
60 {
61  return PyString_FromString(FLAME_LOGGER_NAME);
62 }
63 
64 static
65 PyMethodDef modmethods[] = {
66  {"_GLPSParse", (PyCFunction)&PyGLPSParse, METH_VARARGS|METH_KEYWORDS,
67  "Parse a GLPS lattice file to AST form"},
68  {"GLPSPrinter", (PyCFunction)&PyGLPSPrint, METH_VARARGS,
69  "Print a dictionary in GLPS format to string"},
70  {"setLogLevel", (PyCFunction)&py_set_log, METH_VARARGS,
71  "Set the FLAME logging level"
72  },
73  {"getLoggerName", (PyCFunction)&py_get_log, METH_NOARGS,
74  "Returns the logger name used by the FLAME C extensions"
75  },
76  {NULL, NULL, 0, NULL}
77 };
78 
79 #if PY_MAJOR_VERSION >= 3
80 static struct PyModuleDef module = {
81  PyModuleDef_HEAD_INIT,
82  "flame._internal",
83  NULL,
84  -1,
85  modmethods
86 };
87 #endif
88 }
89 
90 PyMODINIT_FUNC
91 #if PY_MAJOR_VERSION >= 3
92 PyInit__internal(void)
93 #else
94 init_internal(void)
95 #endif
96 {
97  try {
98  if (_import_array() < 0)
99  throw std::runtime_error("Failed to import numpy");
100 
101  try {
102  PyRef<> logging(PyImport_ImportModule("logging"));
103  PyLogger::singleton.logger.reset(PyObject_CallMethod(logging.py(), "getLogger", "s", FLAME_LOGGER_NAME));
104  if(Py_AtExit(&PyLogger::unreg)){
105  std::cerr<<"Failed to add atexit PyLogger::unreg\n";
106  } else {
107  boost::shared_ptr<Machine::Logger> log(&PyLogger::singleton, &PyLogger::noopdtor);
108  Machine::set_logger(log);
109  }
110  } catch(std::runtime_error& e){
111  std::cerr<<"Failed to connect flame logging to python logging : "<<typeid(e).name()<<" : "<<e.what()<<"\n";
112  }
113 
114 #if PY_MAJOR_VERSION >= 3
115  // w/ py3 we own the module object and return NULL on import failure
116  PyRef<> modref(PyModule_Create(&module));
117  PyObject *mod = modref.py();
118 #else
119  // w/ py2 we get a borrowed ref. and indicate import
120  // failure by returning w/ a python exception set
121  PyObject *mod = Py_InitModule("flame._internal", modmethods);
122 #endif
123 
124  // python API version
125  PyModule_AddIntConstant(mod, "_pyapi_version", 0);
126  // C API version
127  PyModule_AddIntConstant(mod, "_capi_version", FLAME_API_VERSION);
128 
129  PyModule_AddIntMacro(mod, FLAME_ERROR);
130  PyModule_AddIntMacro(mod, FLAME_WARN);
131  PyModule_AddIntMacro(mod, FLAME_INFO);
132  PyModule_AddIntMacro(mod, FLAME_DEBUG);
133  PyModule_AddIntMacro(mod, FLAME_FINE);
134 
135  if(registerModMachine(mod))
136  throw std::runtime_error("Failed to initialize Machine");
137  if(registerModState(mod))
138  throw std::runtime_error("Failed to initialize State");
139 
140  // add States and Elements
141  registerLinear();
142  registerMoment();
143 
144 #if PY_MAJOR_VERSION >= 3
145  modref.release();
146  return mod;
147  }CATCH()
148 #else
149  }CATCH2V(std::exception, RuntimeError)
150 #endif
151 }