From 6865278ac5e5b24f787be13b883c9be73e93fb3b Mon Sep 17 00:00:00 2001 From: Steinar Foss Date: Fri, 4 Oct 2019 11:37:18 +0200 Subject: [PATCH 1/3] pyhon DeckKeyword: New constructor takes parserkeyword and list of records. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit python Deckkeyword: can init with empty records. python Deckkeyword: can record simple records, but not defaults. python deckvalue: can take defauløt values. --- python/cxx/deck_keyword.cpp | 72 +++++++++++++++++++++++++++++++++++++ python/tests/test_parser.py | 48 ++++++++++++++++++++++--- 2 files changed, 116 insertions(+), 4 deletions(-) diff --git a/python/cxx/deck_keyword.cpp b/python/cxx/deck_keyword.cpp index fe680a5c3..c1dfff51d 100644 --- a/python/cxx/deck_keyword.cpp +++ b/python/cxx/deck_keyword.cpp @@ -2,6 +2,7 @@ #include +#include #include #include #include @@ -10,6 +11,8 @@ #include "export.hpp" #include "converters.hpp" +#include + namespace { @@ -56,11 +59,80 @@ struct DeckRecordIterator } }; + +bool is_number(const std::string& s) +{ + return !s.empty() && std::find_if(s.begin(), + s.end(), [](char c) { return !std::isdigit(c); }) == s.end(); +} + + +void push_string_as_deck_value(std::vector& record, const std::string str) { + + int max_indx = str.length() - 1; + if (str[max_indx] == '*') { + int it; + + if (max_indx == 0) + it = 1; + else { + std::string substr = str.substr(0, max_indx); + if (is_number(substr)) { + it = std::stoi(substr); + } + else + throw py::type_error("DeckKeyword: string values ending in '*' can only be preceeded by a number."); + } + + for (int i = 0; i < it; i++) + record.push_back( DeckValue() ); + } + else + record.push_back( DeckValue(str) ); +} + + } void python::common::export_DeckKeyword(py::module& module) { py::class_< DeckKeyword >( module, "DeckKeyword") .def(py::init()) + + .def(py::init([](const ParserKeyword& parser_keyword, py::list record_list) { + + std::vector< std::vector > value_record_list; + + for (py::handle record_obj : record_list) { + py::list record = record_obj.cast(); + std::vector value_record; + + for (py::handle value_obj : record) { + + try { + int val_int = value_obj.cast(); + value_record.push_back( DeckValue(val_int) ); + } + catch (std::exception e_int) { + try { + double val_double = value_obj.cast(); + value_record.push_back( DeckValue(val_double) ); + } + catch(std::exception e_double) { + try { + std::string val_string = value_obj.cast(); + push_string_as_deck_value(value_record, val_string); + } + catch(std::exception e_string) { + throw py::type_error("DeckKeyword: tried to add unkown type to record."); + } + } + } + } + value_record_list.push_back( value_record ); + } + return DeckKeyword(parser_keyword, value_record_list); + } ) ) + .def( "__repr__", &DeckKeyword::name ) .def( "__str__", &str ) .def("__iter__", [] (const DeckKeyword &keyword) { return py::make_iterator(keyword.begin(), keyword.end()); }, py::keep_alive<0,1>()) diff --git a/python/tests/test_parser.py b/python/tests/test_parser.py index 0acb2d289..ab8cbc692 100644 --- a/python/tests/test_parser.py +++ b/python/tests/test_parser.py @@ -55,11 +55,51 @@ FIPNUM with self.assertRaises(ValueError): kw = parser["NOT_A_VALID_KEYWORD"] - kw = parser["FIELD"] - assert(kw.name == "FIELD") + field = parser["FIELD"] + assert(field.name == "FIELD") - dkw = DeckKeyword(kw) - assert(dkw.name == "FIELD") + dkw_field = DeckKeyword(field) + assert(dkw_field.name == "FIELD") + + DeckKeyword(parser["AQUCWFAC"], [[]]) + + with self.assertRaises(TypeError): + dkw_wrong = DeckKeyword(parser["AQUCWFAC"], [22.2, 0.25]) + + dkw_aqannc = DeckKeyword(parser["AQANNC"], [[12, 1, 2, 3, 0.89], [13, 4, 5, 6, 0.625]]) + assert( len(dkw_aqannc[0]) == 5 ) + assert( dkw_aqannc[0][2][0] == 2 ) + assert( dkw_aqannc[1][1][0] == 4 ) + assert( dkw_aqannc[1][4][0] == 0.625 ) + + dkw_aqantrc = DeckKeyword(parser["AQANTRC"], [[12, "ABC", 8]]) + assert( dkw_aqantrc[0][1][0] == "ABC" ) + assert( dkw_aqantrc[0][2][0] == 8.0 ) + + dkw1 = DeckKeyword(parser["AQUCWFAC"], [["*", 0.25]]) + assert( dkw1[0][0][0] == 0.0 ) + assert( dkw1[0][1][0] == 0.25 ) + + dkw2 = DeckKeyword(parser["AQUCWFAC"], [[0.25, "*"]]) + assert( dkw2[0][0][0] == 0.25 ) + assert( dkw2[0][1][0] == 1.0 ) + + dkw3 = DeckKeyword(parser["AQUCWFAC"], [[0.50]]) + assert( dkw3[0][0][0] == 0.50 ) + assert( dkw3[0][1][0] == 1.0 ) + + dkw4 = DeckKeyword(parser["CBMOPTS"], [["3*", "A", "B", "C", "2*", 0.375]]) + assert( dkw4[0][0][0] == "TIMEDEP" ) + assert( dkw4[0][2][0] == "NOKRMIX" ) + assert( dkw4[0][3][0] == "A" ) + assert( dkw4[0][6][0] == "PMPVK" ) + assert( dkw4[0][8][0] == 0.375 ) + + with self.assertRaises(TypeError): + DeckKeyword(parser["CBMOPTS"], [["3*", "A", "B", "C", "R2*", 0.77]]) + + + if __name__ == "__main__": From 7555c00ac3de82aaa69a836cd491769da58362eb Mon Sep 17 00:00:00 2001 From: Steinar Foss Date: Sun, 6 Oct 2019 15:11:49 +0200 Subject: [PATCH 2/3] python DeckKeyword constr. resolved nested try blocks. ... --- python/cxx/deck_keyword.cpp | 54 +++++++++++++++---------------------- 1 file changed, 22 insertions(+), 32 deletions(-) diff --git a/python/cxx/deck_keyword.cpp b/python/cxx/deck_keyword.cpp index c1dfff51d..681f91015 100644 --- a/python/cxx/deck_keyword.cpp +++ b/python/cxx/deck_keyword.cpp @@ -60,29 +60,15 @@ struct DeckRecordIterator }; -bool is_number(const std::string& s) -{ - return !s.empty() && std::find_if(s.begin(), - s.end(), [](char c) { return !std::isdigit(c); }) == s.end(); -} - - void push_string_as_deck_value(std::vector& record, const std::string str) { - int max_indx = str.length() - 1; - if (str[max_indx] == '*') { + if (str.back() == '*') { int it; - if (max_indx == 0) + if (str.length() == 1) it = 1; - else { - std::string substr = str.substr(0, max_indx); - if (is_number(substr)) { - it = std::stoi(substr); - } - else - throw py::type_error("DeckKeyword: string values ending in '*' can only be preceeded by a number."); - } + else + it = stod( str.substr(0, str.length() - 1) ); for (int i = 0; i < it; i++) record.push_back( DeckValue() ); @@ -111,22 +97,26 @@ void python::common::export_DeckKeyword(py::module& module) { try { int val_int = value_obj.cast(); value_record.push_back( DeckValue(val_int) ); + continue; } - catch (std::exception e_int) { - try { - double val_double = value_obj.cast(); - value_record.push_back( DeckValue(val_double) ); - } - catch(std::exception e_double) { - try { - std::string val_string = value_obj.cast(); - push_string_as_deck_value(value_record, val_string); - } - catch(std::exception e_string) { - throw py::type_error("DeckKeyword: tried to add unkown type to record."); - } - } + catch (std::exception e_int) {} + + try { + double val_double = value_obj.cast(); + value_record.push_back( DeckValue(val_double) ); + continue; } + catch (std::exception e_double) {} + + try { + std::string val_string = value_obj.cast(); + push_string_as_deck_value(value_record, val_string); + continue; + } + catch (std::exception e_string) {} + + throw py::type_error("DeckKeyword: tried to add unkown type to record."); + } value_record_list.push_back( value_record ); } From 3bce48586ab9a473100ad19de143ec91088096da Mon Sep 17 00:00:00 2001 From: Steinar Foss Date: Mon, 7 Oct 2019 09:51:08 +0200 Subject: [PATCH 3/3] Python: DeckKeyword: can accept DeckValues( parserkw, [["5*$VALUE"]]) python : deckkeyword accepts 5*. ... --- python/cxx/deck_keyword.cpp | 41 +++++++++++++++++++++++++++++-------- python/tests/test_parser.py | 8 ++++++++ 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/python/cxx/deck_keyword.cpp b/python/cxx/deck_keyword.cpp index 681f91015..1498bdc61 100644 --- a/python/cxx/deck_keyword.cpp +++ b/python/cxx/deck_keyword.cpp @@ -60,23 +60,46 @@ struct DeckRecordIterator }; +bool is_int(const std::string& s) +{ + return !s.empty() && std::find_if(s.begin(), + s.end(), [](char c) { return !std::isdigit(c); }) == s.end(); +} + + void push_string_as_deck_value(std::vector& record, const std::string str) { - if (str.back() == '*') { - int it; + std::size_t star_pos = str.find('*'); + if (star_pos != std::string::npos) { + int multiplier = 1; + + std::string mult_str = str.substr(0, star_pos); - if (str.length() == 1) - it = 1; - else - it = stod( str.substr(0, str.length() - 1) ); + if (mult_str.length() > 0) { + if (is_int(mult_str)) + multiplier = std::stoi( mult_str ); + else + throw py::type_error(); + } - for (int i = 0; i < it; i++) - record.push_back( DeckValue() ); + std::string value_str = str.substr(star_pos + 1, str.length()); + DeckValue value; + + if (value_str.length() > 0) { + if (is_int(value_str)) + value = DeckValue( stoi(value_str) ); + else + value = DeckValue( stod(value_str) ); + } + + for (int i = 0; i < multiplier; i++) + record.push_back( value ); + } else record.push_back( DeckValue(str) ); -} +} } diff --git a/python/tests/test_parser.py b/python/tests/test_parser.py index ab8cbc692..94eb1e4b9 100644 --- a/python/tests/test_parser.py +++ b/python/tests/test_parser.py @@ -98,7 +98,15 @@ FIPNUM with self.assertRaises(TypeError): DeckKeyword(parser["CBMOPTS"], [["3*", "A", "B", "C", "R2*", 0.77]]) + with self.assertRaises(TypeError): + DeckKeyword(parser["CBMOPTS"], [["3*", "A", "B", "C", "2.2*", 0.77]]) + dkw5 = DeckKeyword(parser["AQUCWFAC"], [["2*5.5"]]) + assert( dkw5[0][0][0] == 5.5 ) + assert( dkw5[0][1][0] == 5.5 ) + + with self.assertRaises(ValueError): + raise DeckKeyword(parser["AQANTRC"], [["1*2.2", "ABC", 8]])