From 714d0b02a19517c2b66126d7bbcbcaf739000ce9 Mon Sep 17 00:00:00 2001 From: Alessandro Bacchini Date: Thu, 11 Jun 2015 08:51:44 +0200 Subject: [PATCH 1/2] Initial implementation of section read in Python wrapper. --- .gitignore | 1 + pyerg/pyerg.cpp | 23 +++++++++++++++-------- pyerg/pyerg.h | 4 ++-- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index c8d48c5..2be9081 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ data/* build/* +*.user diff --git a/pyerg/pyerg.cpp b/pyerg/pyerg.cpp index 68c1619..b63fcea 100644 --- a/pyerg/pyerg.cpp +++ b/pyerg/pyerg.cpp @@ -340,35 +340,42 @@ PyFUNC Parser_readAll(Reader* self) return map; } -PyFUNC Parser_read(Reader* self, PyObject* arg) +PyFUNC Parser_read(Reader* self, PyObject* args, PyObject* keywds) { - size_t qindex = indexFromPyObject(self->parser, arg); + PyObject* objIndex = nullptr; + size_t from = 0; + size_t to = self->parser->records(); + static char* kwlist[] = {"from", "to", nullptr}; + if(!PyArg_ParseTupleAndKeywords(args, keywds, "O|ii", kwlist, &objIndex, &from, &to)) + return nullptr; + + const size_t qindex = indexFromPyObject(self->parser, objIndex); if(PyErr_Occurred()!=nullptr) return nullptr; // Numpy array creation npy_intp rows = self->parser->records(); int type = ergType2npyType(self->parser->quantityType(qindex)); - PyObject* array = PyArray_SimpleNew(1, &rows, type); - uint8_t* outData = (uint8_t*)PyArray_DATA((PyArrayObject*)array); - npy_intp size = PyArray_NBYTES((PyArrayObject*)array); + PyArrayObject* array = (PyArrayObject*)PyArray_SimpleNew(1, &rows, type); + uint8_t* outData = (uint8_t*)PyArray_DATA(array); + const npy_intp size = PyArray_NBYTES(array); std::string error; Py_BEGIN_ALLOW_THREADS; try { - self->parser->read(qindex, outData, size); + self->parser->read(qindex, from, to, outData, size); } catch(std::runtime_error e) { error = e.what(); } Py_END_ALLOW_THREADS; if(error.length()>0) { - Py_DecRef(array); + Py_DecRef((PyObject*)array); PyErr_SetString(PyExc_NameError, error.c_str()); return nullptr; } - return array; + return (PyObject*)array; } PyFUNC Parser_quantitySize(Reader* self, PyObject* arg) diff --git a/pyerg/pyerg.h b/pyerg/pyerg.h index c4e0f59..54cb4ea 100644 --- a/pyerg/pyerg.h +++ b/pyerg/pyerg.h @@ -59,7 +59,7 @@ PyFUNC Parser_records(Reader* self); PyFUNC Parser_recordSize(Reader* self); PyFUNC Parser_numQuanities(Reader* self); PyFUNC Parser_readAll(Reader* self); -PyFUNC Parser_read(Reader* self, PyObject* arg); +PyFUNC Parser_read(Reader* self, PyObject *args, PyObject *keywds); PyFUNC Parser_quantitySize(Reader* self, PyObject* arg); PyFUNC Parser_quantityName(Reader* self, PyObject* arg); PyFUNC Parser_quantityType(Reader* self, PyObject* arg); @@ -92,7 +92,7 @@ static PyMethodDef parser_methods[] = { PYERG_PARSER_READALL_DOC }, { - "read", (PyCFunction)Parser_read, METH_O, + "read", (PyCFunction)Parser_read, METH_KEYWORDS, PYERG_PARSER_READ_DOC }, { From 8e487b5941fe61c8737827d760a139e25a2743ea Mon Sep 17 00:00:00 2001 From: Alessandro Bacchini Date: Thu, 11 Jun 2015 14:35:54 +0200 Subject: [PATCH 2/2] Version 0.5 Fixed bugs in `erg::Reader::read()` function Add ability to read only a portion of a quantity from both C++ and Python Improved pyerg.read() function: now it create a erg.Reader Python object --- Changelog.txt | 5 +++++ pyerg/pyerg.cpp | 34 ++++++++++++++++++++++++---------- pyerg/pyerg.h | 2 +- pyerg/pyerg_docstrings.h | 16 +++++++++------- setup.py | 2 +- test/test_pyerg.py | 4 ++++ 6 files changed, 44 insertions(+), 19 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 990e9c7..7a9b444 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,3 +1,8 @@ +0.5.0 +- Fixed bugs in `erg::Reader::read()` function +- Add ability to read only a portion of a quantity from both C++ and Python +- Improved pyerg.read() function: now it create a erg.Reader Python object + 0.4.1 - Improved documentation diff --git a/pyerg/pyerg.cpp b/pyerg/pyerg.cpp index b63fcea..99e5043 100644 --- a/pyerg/pyerg.cpp +++ b/pyerg/pyerg.cpp @@ -100,6 +100,21 @@ static size_t indexFromPyObject(erg::Reader* parser, PyObject* arg) PyFUNC py_read(PyObject* self, PyObject* filename) { + PyObject* args = PyTuple_New(0); + Reader* pyReader = (Reader*)PyObject_CallObject((PyObject*)&pyerg_ReaderType, args); + Py_DecRef(args); + + PyObject* ret = Parser_open(pyReader, filename); + if(ret==nullptr) + return nullptr; + + Py_DecRef(ret); + + PyObject* data = Parser_readAll(pyReader); + Py_DecRef((PyObject*)pyReader); + return data; + + /* // self is unused. if(PyString_Check(filename)==false) { PyErr_SetString(PyExc_NameError, "The input arguments must be a string"); @@ -174,6 +189,7 @@ PyFUNC py_read(PyObject* self, PyObject* filename) } return map; + */ } PyFUNC py_can_read(PyObject* self, PyObject* filename) @@ -190,7 +206,6 @@ PyFUNC py_can_read(PyObject* self, PyObject* filename) // Release the GIL because the open function is an I/O // operation that read a file. - PyThreadState *_save; // The GIL save state Py_BEGIN_ALLOW_THREADS; try { // Try to read the file: if the file is valid, @@ -229,7 +244,7 @@ PyFUNC Parser_new(PyTypeObject* type, PyObject *args, PyObject *kwds) extern "C" int Parser_init(Reader* self, PyObject *args, PyObject *kwds) { - if(PyTuple_Size(args)==1) { + if(args!=nullptr && PyTuple_Size(args)==1) { // Initialize with a filename: open the file PyObject* filename = PyTuple_GetItem(args, 0); @@ -344,9 +359,9 @@ PyFUNC Parser_read(Reader* self, PyObject* args, PyObject* keywds) { PyObject* objIndex = nullptr; size_t from = 0; - size_t to = self->parser->records(); - static char* kwlist[] = {"from", "to", nullptr}; - if(!PyArg_ParseTupleAndKeywords(args, keywds, "O|ii", kwlist, &objIndex, &from, &to)) + size_t count = self->parser->records(); + static char* kwlist[] = {"name", "start", "count", NULL}; + if(!PyArg_ParseTupleAndKeywords(args, keywds, "O|ii", kwlist, &objIndex, &from, &count)) return nullptr; const size_t qindex = indexFromPyObject(self->parser, objIndex); @@ -354,7 +369,7 @@ PyFUNC Parser_read(Reader* self, PyObject* args, PyObject* keywds) return nullptr; // Numpy array creation - npy_intp rows = self->parser->records(); + npy_intp rows = count; int type = ergType2npyType(self->parser->quantityType(qindex)); PyArrayObject* array = (PyArrayObject*)PyArray_SimpleNew(1, &rows, type); uint8_t* outData = (uint8_t*)PyArray_DATA(array); @@ -363,7 +378,7 @@ PyFUNC Parser_read(Reader* self, PyObject* args, PyObject* keywds) std::string error; Py_BEGIN_ALLOW_THREADS; try { - self->parser->read(qindex, from, to, outData, size); + self->parser->read(qindex, from, count, outData, size); } catch(std::runtime_error e) { error = e.what(); } @@ -499,12 +514,11 @@ PyMODINIT_FUNC initpyerg(void) if (PyType_Ready(&pyerg_ReaderType) < 0) return; - pyergModule = Py_InitModule3("pyerg", pyerg_methods, - "Module for loading CarMaker .erg files."); + pyergModule = Py_InitModule3("pyerg", pyerg_methods, "Module for loading CarMaker .erg files."); Py_INCREF(&pyerg_ReaderType); PyModule_AddObject(pyergModule, "Reader", (PyObject*)&pyerg_ReaderType); - PyModule_AddStringConstant(pyergModule, "__version__", "0.4.1"); + PyModule_AddStringConstant(pyergModule, "__version__", "0.5.0"); import_array(); } diff --git a/pyerg/pyerg.h b/pyerg/pyerg.h index 54cb4ea..7fee6cf 100644 --- a/pyerg/pyerg.h +++ b/pyerg/pyerg.h @@ -92,7 +92,7 @@ static PyMethodDef parser_methods[] = { PYERG_PARSER_READALL_DOC }, { - "read", (PyCFunction)Parser_read, METH_KEYWORDS, + "read", (PyCFunction)Parser_read, METH_VARARGS|METH_KEYWORDS, PYERG_PARSER_READ_DOC }, { diff --git a/pyerg/pyerg_docstrings.h b/pyerg/pyerg_docstrings.h index 463a26e..f97f300 100644 --- a/pyerg/pyerg_docstrings.h +++ b/pyerg/pyerg_docstrings.h @@ -64,7 +64,7 @@ " Dict of numpy ndarray with the datasets in the file. The names of the datasets are " \ "the keys of the Dict.\n" \ "Raises:\n" \ - " Exception if the file can't be read or is not an ERG file." + " Exception if the file can't be read or is not an ERG file." #define PYERG_CAN_READ_DOC \ "ok = can_read(filename)\n" \ @@ -81,7 +81,7 @@ "Args:\n" \ " filename: Pathname of the erg file.\n" \ "Raises:\n" \ - " Exception if the file can't be read or is not an ERG file." + " Exception if the file can't be read or is not an ERG file." #define PYERG_PARSER_RECORDS_DOC \ "Number of records/rows in th `.erg` file.\n\n" \ @@ -98,7 +98,7 @@ "The number of quantities is the number of columns that contains data in each record:\n" \ "the padding columns are ignored.\n\n" \ "Returns:\n" \ - " The number of quantities.\n" + " The number of quantities.\n" #define PYERG_PARSER_READALL_DOC \ "Read all the datasets from the file.\n\n" \ @@ -106,12 +106,14 @@ " Dict with all the datasets as numpy ndarray with the quantity names as keys." \ "See:\n" \ " quantitySize() to know the size of each dataset to known in advice the quantity of memory " \ - "that will be used." + "that will be used." #define PYERG_PARSER_READ_DOC \ "Read a single dataset from the file.\n\n" \ "Args:\n" \ - " qindex: Index or name of the dataset to read.\n" \ + " name: Index or name of the dataset to read.\n" \ + " start: Index of the row from which to start reading.\n" \ + " count: Number of rows to read.\n" \ "Returns:\n" \ " Numpy ndarray with the data.\n" \ "Raises:\n" \ @@ -170,14 +172,14 @@ #define PYERG_PARSER_ISFORTRAN_DOC \ "Version of th ERG file.\n\n" \ "Returns:\n" \ - " True if the format of the file is Fortran binary (`FORTRAN_Binary_Data`)." + " True if the format of the file is Fortran binary (`FORTRAN_Binary_Data`)." #define PYERG_PARSER_HAS_DOC \ "Test if the quantity is present in the file.\n" \ "Args:\n" \ " name: Name of the quantity.\n" \ "Returns:\n" \ - " True if the quantity is present inside the file, False otherwise." + " True if the quantity is present inside the file, False otherwise." #define PYERG_PARSER_CLOSE_DOC \ "Close the current file and clear the data." \ diff --git a/setup.py b/setup.py index d6f3640..200f95f 100644 --- a/setup.py +++ b/setup.py @@ -38,7 +38,7 @@ language='c++') setup(name='pyerg', - version='0.4', + version='0.5.0', description='Python C extension for reading IPG CarMaker ERG files.', author='Alessandro Bacchini', author_email='alessandro.bacchini@henesis.eu', diff --git a/test/test_pyerg.py b/test/test_pyerg.py index fd9b9bb..eef6de4 100644 --- a/test/test_pyerg.py +++ b/test/test_pyerg.py @@ -216,6 +216,10 @@ def test_Read(self): t = parser.read('Data_8') self.assertEquals(len(t), parser.records()) + t2 = parser.read('Data_8', start=10, count=90) + self.assertEquals(len(t2), 90) + self.assertTrue(np.all(t2 == t[10:100])) + class TestPyerg(unittest.TestCase):