#14648 Python: Support strings containing commas in list arguments

Lists sent from Python over gRPC are serialized as text, and the list parser split on every comma, also commas inside a string. A category name like "Coal,Calcite" was therefore split in two, and set_discrete_property_category_names() failed with "CategoryValues and CategoryNames must have matching sizes".

The list parser is now quote-aware, and ignores commas inside quoted strings and inside nested brackets and parentheses. A quoted item is parsed as a quoted string also when the surrounding text is unquoted, as is the case for text coming from Python. The Python client quotes and escapes strings in lists and tuples when they contain separator characters.

Add unit tests for the field serialization and a Python test for the category names.
This commit is contained in:
Kristian Bendiksen committed 2026-09-09 11:19:44 +02:00
1 parent b02d95bf95
commit 5ed45b8f19
7 files changed
+219 -17

No files matched your search

@@ -14,6 +14,7 @@ set(SOURCE_UNITTEST_FILES
${CMAKE_CURRENT_LIST_DIR}/RigBoundingBoxIjk-Test.cpp
${CMAKE_CURRENT_LIST_DIR}/RigContourMapGrid-Test.cpp
${CMAKE_CURRENT_LIST_DIR}/RifcCommandCore-Test.cpp
${CMAKE_CURRENT_LIST_DIR}/RiaGrpcFieldSerialization-Test.cpp
${CMAKE_CURRENT_LIST_DIR}/RifEclipseInputFileTools-Test.cpp
${CMAKE_CURRENT_LIST_DIR}/RifEclipseOutputFileTools-Test.cpp
${CMAKE_CURRENT_LIST_DIR}/RifOpmFlowDeckFile-Test.cpp
@@ -0,0 +1,83 @@
#include "gtest/gtest.h"
#include "cafPdmFieldScriptingCapability.h"
#include "cafPdmScriptIOMessages.h"
#include <QString>
#include <QTextStream>
#include <vector>
//--------------------------------------------------------------------------------------------------
/// https://github.com/OPM/ResInsight/issues/14648
///
/// A string list sent from Python (via gRPC) is serialized as "[a, b, c]" and parsed with
/// stringsAreQuoted = false. Strings containing a comma are quoted by the Python client, and must
/// not be split into multiple items. If they are, set_discrete_property_category_names() fails with
/// "CategoryValues and CategoryNames must have matching sizes"
//--------------------------------------------------------------------------------------------------
TEST( RiaGrpcFieldSerialization, StringListUnquotedWithCommaInString )
{
// This is the text produced by rips when sending ["Coal,Calcite", "Channel"]. Only strings
// containing separator characters are quoted.
QString source = R"(["Coal,Calcite", Channel])";
QTextStream stream( &source );
std::vector<QString> destination;
caf::PdmScriptIOMessages messages;
const bool stringsAreQuoted = false;
caf::PdmFieldScriptingCapabilityIOHandler<std::vector<QString>>::writeToField( destination, stream, &messages, stringsAreQuoted );
ASSERT_EQ( size_t( 2 ), destination.size() );
EXPECT_STREQ( "Coal,Calcite", destination[0].toStdString().c_str() );
EXPECT_STREQ( "Channel", destination[1].toStdString().c_str() );
}
//--------------------------------------------------------------------------------------------------
/// https://github.com/OPM/ResInsight/issues/14648
///
/// Quoted strings containing a comma must be kept as one item
//--------------------------------------------------------------------------------------------------
TEST( RiaGrpcFieldSerialization, StringListQuotedWithCommaInString )
{
QString source = R"(["Coal,Calcite", "Channel"])";
QTextStream stream( &source );
std::vector<QString> destination;
caf::PdmScriptIOMessages messages;
const bool stringsAreQuoted = true;
caf::PdmFieldScriptingCapabilityIOHandler<std::vector<QString>>::writeToField( destination, stream, &messages, stringsAreQuoted );
ASSERT_EQ( size_t( 2 ), destination.size() );
EXPECT_STREQ( "Coal,Calcite", destination[0].toStdString().c_str() );
EXPECT_STREQ( "Channel", destination[1].toStdString().c_str() );
}
//--------------------------------------------------------------------------------------------------
/// https://github.com/OPM/ResInsight/issues/14648
///
/// Serialize and parse a string list containing commas
//--------------------------------------------------------------------------------------------------
TEST( RiaGrpcFieldSerialization, StringListWithCommaRoundTrip )
{
const std::vector<QString> source = { "Coal,Calcite", "Channel" };
QString serialized;
QTextStream outputStream( &serialized );
caf::PdmFieldScriptingCapabilityIOHandler<std::vector<QString>>::readFromField( source, outputStream, true, false );
QTextStream inputStream( &serialized );
std::vector<QString> destination;
caf::PdmScriptIOMessages messages;
const bool stringsAreQuoted = true;
caf::PdmFieldScriptingCapabilityIOHandler<std::vector<QString>>::writeToField( destination, inputStream, &messages, stringsAreQuoted );
ASSERT_EQ( source.size(), destination.size() );
EXPECT_STREQ( "Coal,Calcite", destination[0].toStdString().c_str() );
EXPECT_STREQ( "Channel", destination[1].toStdString().c_str() );
}