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