5 #include "flame/base.h"
9 #define NO_IMPORT_ARRAY
10 #define PY_ARRAY_UNIQUE_SYMBOL FLAME_PyArray_API
11 #define NPY_NO_DEPRECATED_API NPY_1_6_API_VERSION
12 #include <numpy/ndarrayobject.h>
23 void List2Config(
Config& ret, PyObject *list,
unsigned depth)
26 throw std::runtime_error(
"too deep for Dict2Config");
28 PyRef<> iter(PyObject_GetIter(list));
30 PyObject *item = PyIter_Next(iter.py());
32 PyRef<> itemref(item);
35 if(!PyArg_ParseTuple(item,
"sO", &kname, &value))
36 throw std::runtime_error(
"list item is not a tuple?");
38 if(PyArray_Check(value)) {
39 PyRef<> arr(PyArray_ContiguousFromAny(value, NPY_DOUBLE, 0, 2));
40 double *buf = (
double*)PyArray_DATA(arr.py());
41 std::vector<double> temp(PyArray_SIZE(arr.py()));
42 std::copy(buf, buf+temp.size(), temp.begin());
44 ret.
swap<std::vector<double> >(kname, temp);
46 }
else if(PyNumber_Check(value)) {
47 PyRef<> dval(PyNumber_Float(value));
48 double val = PyFloat_AsDouble(dval.py());
49 ret.
set<
double>(kname, val);
51 }
else if(PyUnicode_Check(value) || (PY_MAJOR_VERSION < 3 && PyBytes_Check(value))) {
52 PyRef<> valref(value, borrow());
53 PyCString sval(valref);
54 const char *val = sval.c_str();
56 ret.
set<std::string>(kname, val);
58 }
else if(PySequence_Check(value)) {
59 Py_ssize_t N = PySequence_Size(value);
61 Config::vector_t output;
64 for(Py_ssize_t i=0; i<N; i++) {
65 PyRef<> elem(PySequence_GetItem(value, i));
67 if(PyDict_Check(elem.py())) {
68 elem.reset(PyMapping_Items(elem.py()));
70 if(!PyList_Check(elem.py())) {
71 PyTypeObject *valuetype = (PyTypeObject*)PyObject_Type(elem.py());
72 throw std::invalid_argument(SB()<<
"lists must contain only dict or list of tuples, not "<<valuetype->tp_name);
77 List2Config(output.back(), elem.py(), depth+1);
80 ret.
set<Config::vector_t>(kname, output);
83 PyTypeObject *valuetype = (PyTypeObject*)PyObject_Type(value);
84 throw std::invalid_argument(SB()<<
"Must be a dict, not "<<valuetype->tp_name);
91 PyObject* pydirname(PyObject *obj)
95 PyRef<> ospath(PyImport_ImportModule(
"os.path"));
96 return PyObject_CallMethod(ospath.py(),
"dirname",
"O", obj);
99 struct confval :
public boost::static_visitor<PyRef<> >
101 PyRef<> operator()(
double v)
const
103 return PyRef<>(PyFloat_FromDouble(v));
106 PyRef<> operator()(
const std::string& v)
const
108 return PyRef<>(PyString_FromString(v.c_str()));
111 PyRef<> operator()(
const std::vector<double>& v)
const
113 npy_intp dims[] = {(npy_intp)v.size()};
114 PyRef<> obj(PyArray_SimpleNew(1, dims, NPY_DOUBLE));
115 std::copy(v.begin(), v.end(), (
double*)PyArray_DATA(obj.py()));
119 PyRef<> operator()(
const Config::vector_t& v)
const
121 PyRef<> L(PyList_New(v.size()));
123 for(
size_t i=0, N=v.size(); i<N; i++)
125 PyList_SetItem(L.py(), i, conf2dict(&v[i]));
133 PyObject* conf2dict(
const Config *conf)
137 PyRef<> list(PyList_New(0));
142 PyRef<> val(boost::apply_visitor(confval(), it->second));
143 PyRef<> tup(Py_BuildValue(
"sO", it->first.c_str(), val.py()));
144 if(PyList_Append(list.py(), tup.py()))
145 throw std::runtime_error(
"Failed to insert into dictionary from conf2dict");
148 return list.releasePy();
151 Config* list2conf(PyObject *dict)
153 if(!PyList_Check(dict))
154 throw std::invalid_argument(
"Not a list");
155 std::unique_ptr<Config> conf(
new Config);
156 List2Config(*conf, dict);
157 return conf.release();
160 PyObject* PyGLPSPrint(PyObject *, PyObject *args)
164 if(!PyArg_ParseTuple(args,
"O", &inp))
168 if(PyDict_Check(inp)) {
169 list.reset(PyMapping_Items(inp));
172 if(!PyList_Check(inp))
173 return PyErr_Format(PyExc_ValueError,
"argument must be dict or list of tuples");
176 List2Config(conf, inp);
177 std::ostringstream strm;
178 GLPSPrint(strm, conf);
179 return PyString_FromString(strm.str().c_str());
183 #ifndef PY_SSIZE_T_CLEAN
184 #error the following assumes ssize_t is used
187 Config* PyGLPSParse2Config(PyObject *, PyObject *args, PyObject *kws)
189 PyObject *conf = NULL, *extra_defs = Py_None;
190 const char *path = NULL;
191 const char *pnames[] = {
"config",
"path",
"extra", NULL};
192 if(!PyArg_ParseTupleAndKeywords(args, kws,
"O|zO", (
char**)pnames, &conf, &path, &extra_defs))
197 if(extra_defs==Py_None) {
199 }
else if(PyDict_Check(extra_defs)) {
200 PyObject *key, *value;
203 while(PyDict_Next(extra_defs, &pos, &key, &value)) {
204 PyRef<> keyx(key, borrow());
205 PyCString keystr(keyx);
209 if(PyNumber_Check(value)) {
210 PyRef<> pyf(PyNumber_Float(value));
211 curval = PyFloat_AsDouble(pyf.py());
213 }
else if(PyString_Check(value)) {
214 PyRef<> valuex(value, borrow());
215 PyCString valstr(valuex);
217 curval = valstr.c_str();
220 PyErr_SetString(PyExc_ValueError,
"extra {} can contain only numbers or strings");
224 parser.
setVar(keystr.c_str(), curval);
227 PyErr_SetString(PyExc_ValueError,
"'extra' must be a dict");
232 std::unique_ptr<Config> C;
236 if(PyObject_HasAttrString(conf,
"read")) {
239 if(!path && PyObject_HasAttrString(conf,
"name")) {
240 path = pyname.c_str(pydirname(PyObject_GetAttrString(conf,
"name")));
243 PyRef<> pybytes(PyObject_CallMethod(conf,
"read",
""));
244 if(!buf.get(pybytes.py())) {
245 PyErr_SetString(PyExc_TypeError,
"read() must return a buffer");
248 C.reset(parser.
parse_byte((
const char*)buf.data(), buf.size(), path));
250 }
else if(buf.get(conf)) {
251 C.reset(parser.
parse_byte((
const char*)buf.data(), buf.size(), path));
253 #if PY_MAJOR_VERSION >= 3
254 }
else if(PyUnicode_Check(conf)) {
256 const char *cbuf = buf.c_str(conf);
258 C.reset(parser.
parse_byte(cbuf, strlen(cbuf), path));
262 if(PyDict_Check(conf)) {
263 listref.reset(PyMapping_Items(conf));
266 if(PyList_Check(conf)) {
267 C.reset(list2conf(conf));
270 throw std::invalid_argument(
"'config' must be dict, list of tuples, or byte buffer");
277 PyObject* PyGLPSParse(PyObject *unused, PyObject *args, PyObject *kws)
280 return conf2dict(PyGLPSParse2Config(unused, args, kws));
void setVar(const std::string &name, const Config::value_t &v)
Pre-define variable.
void set(const std::string &name, typename boost::call_traits< typename detail::is_config_value< T >::type >::param_type val)
Interface to lattice file parser.
void swap(const std::string &name, typename boost::call_traits< typename detail::is_config_value< T >::type >::reference val)
Associative configuration container.
boost::variant< double, std::vector< double >, std::string, std::vector< Config > > value_t
An individual value (double, double[], string, or Config[])
const_iterator end() const
one after the last element
Config new_scope() const
Create a new inner scope.
values_t::const_iterator const_iterator
const_iterator
Config * parse_byte(const char *s, size_t len, const char *path=NULL)
Parse from byte buffer.
const_iterator begin() const
The first element.