5 #include "flame/base.h"
9 #define NO_IMPORT_ARRAY
10 #define PY_ARRAY_UNIQUE_SYMBOL FLAME_PyArray_API
11 #include <numpy/ndarrayobject.h>
22 void List2Config(
Config& ret, PyObject *list,
unsigned depth)
25 throw std::runtime_error(
"too deep for Dict2Config");
27 PyRef<> iter(PyObject_GetIter(list));
29 PyObject *item = PyIter_Next(iter.py());
31 PyRef<> itemref(item);
34 if(!PyArg_ParseTuple(item,
"sO", &kname, &value))
35 throw std::runtime_error(
"list item is not a tuple?");
37 if(PyArray_Check(value)) {
38 PyRef<> arr(PyArray_ContiguousFromAny(value, NPY_DOUBLE, 0, 2));
39 double *buf = (
double*)PyArray_DATA(arr.py());
40 std::vector<double> temp(PyArray_SIZE(arr.py()));
41 std::copy(buf, buf+temp.size(), temp.begin());
43 ret.
swap<std::vector<double> >(kname, temp);
45 }
else if(PyNumber_Check(value)) {
46 PyRef<> dval(PyNumber_Float(value));
47 double val = PyFloat_AsDouble(dval.py());
48 ret.
set<
double>(kname, val);
50 }
else if(PyUnicode_Check(value) || (PY_MAJOR_VERSION < 3 && PyBytes_Check(value))) {
51 PyRef<> valref(value, borrow());
52 PyCString sval(valref);
53 const char *val = sval.c_str();
55 ret.
set<std::string>(kname, val);
57 }
else if(PySequence_Check(value)) {
58 Py_ssize_t N = PySequence_Size(value);
60 Config::vector_t output;
63 for(Py_ssize_t i=0; i<N; i++) {
64 PyRef<> elem(PySequence_GetItem(value, i));
66 if(PyDict_Check(elem.py())) {
67 elem.reset(PyMapping_Items(elem.py()));
69 if(!PyList_Check(elem.py())) {
70 PyTypeObject *valuetype = (PyTypeObject*)PyObject_Type(elem.py());
71 throw std::invalid_argument(SB()<<
"lists must contain only dict or list of tuples, not "<<valuetype->tp_name);
76 List2Config(output.back(), elem.py(), depth+1);
79 ret.
set<Config::vector_t>(kname, output);
82 PyTypeObject *valuetype = (PyTypeObject*)PyObject_Type(value);
83 throw std::invalid_argument(SB()<<
"Must be a dict, not "<<valuetype->tp_name);
90 PyObject* pydirname(PyObject *obj)
94 PyRef<> ospath(PyImport_ImportModule(
"os.path"));
95 return PyObject_CallMethod(ospath.py(),
"dirname",
"O", obj);
98 struct confval :
public boost::static_visitor<PyRef<> >
100 PyRef<> operator()(
double v)
const
102 return PyRef<>(PyFloat_FromDouble(v));
105 PyRef<> operator()(
const std::string& v)
const
107 return PyRef<>(PyString_FromString(v.c_str()));
110 PyRef<> operator()(
const std::vector<double>& v)
const
112 npy_intp dims[] = {(npy_intp)v.size()};
113 PyRef<> obj(PyArray_SimpleNew(1, dims, NPY_DOUBLE));
114 std::copy(v.begin(), v.end(), (
double*)PyArray_DATA(obj.py()));
118 PyRef<> operator()(
const Config::vector_t& v)
const
120 PyRef<> L(PyList_New(v.size()));
122 for(
size_t i=0, N=v.size(); i<N; i++)
124 PyList_SetItem(L.py(), i, conf2dict(&v[i]));
132 PyObject* conf2dict(
const Config *conf)
134 PyRef<> list(PyList_New(0));
139 PyRef<> val(boost::apply_visitor(confval(), it->second));
140 PyRef<> tup(Py_BuildValue(
"sO", it->first.c_str(), val.py()));
141 if(PyList_Append(list.py(), tup.py()))
142 throw std::runtime_error(
"Failed to insert into dictionary from conf2dict");
145 return list.releasePy();
148 Config* list2conf(PyObject *dict)
150 if(!PyList_Check(dict))
151 throw std::invalid_argument(
"Not a list");
152 std::auto_ptr<Config> conf(
new Config);
153 List2Config(*conf, dict);
154 return conf.release();
157 PyObject* PyGLPSPrint(PyObject *, PyObject *args)
161 if(!PyArg_ParseTuple(args,
"O", &inp))
165 if(PyDict_Check(inp)) {
166 list.reset(PyMapping_Items(inp));
169 if(!PyList_Check(inp))
170 return PyErr_Format(PyExc_ValueError,
"argument must be dict or list of tuples");
173 List2Config(conf, inp);
174 std::ostringstream strm;
175 GLPSPrint(strm, conf);
176 return PyString_FromString(strm.str().c_str());
180 #ifndef PY_SSIZE_T_CLEAN
181 #error the following assumes ssize_t is used
184 Config* PyGLPSParse2Config(PyObject *, PyObject *args, PyObject *kws)
186 PyObject *conf = NULL, *extra_defs = Py_None;
187 const char *path = NULL;
188 const char *pnames[] = {
"config",
"path",
"extra", NULL};
189 if(!PyArg_ParseTupleAndKeywords(args, kws,
"O|zO", (
char**)pnames, &conf, &path, &extra_defs))
194 if(extra_defs==Py_None) {
196 }
else if(PyDict_Check(extra_defs)) {
197 PyObject *key, *value;
200 while(PyDict_Next(extra_defs, &pos, &key, &value)) {
201 PyRef<> keyx(key, borrow());
202 PyCString keystr(keyx);
206 if(PyNumber_Check(value)) {
207 PyRef<> pyf(PyNumber_Float(value));
208 curval = PyFloat_AsDouble(pyf.py());
210 }
else if(PyString_Check(value)) {
211 PyRef<> valuex(value, borrow());
212 PyCString valstr(valuex);
214 curval = valstr.c_str();
217 PyErr_SetString(PyExc_ValueError,
"extra {} can contain only numbers or strings");
221 parser.
setVar(keystr.c_str(), curval);
224 PyErr_SetString(PyExc_ValueError,
"'extra' must be a dict");
229 std::auto_ptr<Config> C;
233 if(PyObject_HasAttrString(conf,
"read")) {
236 if(!path && PyObject_HasAttrString(conf,
"name")) {
237 path = pyname.c_str(pydirname(PyObject_GetAttrString(conf,
"name")));
240 PyRef<> pybytes(PyObject_CallMethod(conf,
"read",
""));
241 if(!buf.get(pybytes.py())) {
242 PyErr_SetString(PyExc_TypeError,
"read() must return a buffer");
245 C.reset(parser.
parse_byte((
const char*)buf.data(), buf.size(), path));
247 }
else if(buf.get(conf)) {
248 C.reset(parser.
parse_byte((
const char*)buf.data(), buf.size(), path));
250 #if PY_MAJOR_VERSION >= 3
251 }
else if(PyUnicode_Check(conf)) {
253 const char *cbuf = buf.c_str(conf);
255 C.reset(parser.
parse_byte(cbuf, strlen(cbuf), path));
259 if(PyDict_Check(conf)) {
260 listref.reset(PyMapping_Items(conf));
263 if(PyList_Check(conf)) {
264 C.reset(list2conf(conf));
267 throw std::invalid_argument(
"'config' must be dict, list of tuples, or byte buffer");
274 PyObject* PyGLPSParse(PyObject *unused, PyObject *args, PyObject *kws)
277 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.