THRIFT-242. python: Used named arguments in __init__ instead of a dict
This is a wire-compatible but non-source-compatible change.
When initializing structures, you must use
Foo(bar=1, baz="qux")
Foo(**{"bar": 1, "baz": "qux"})
instead of
Foo({"bar": 1, "baz": "qux"})
git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@734536 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/compiler/cpp/src/generate/t_py_generator.cc b/compiler/cpp/src/generate/t_py_generator.cc
index 8c9747a..0218394 100644
--- a/compiler/cpp/src/generate/t_py_generator.cc
+++ b/compiler/cpp/src/generate/t_py_generator.cc
@@ -143,7 +143,8 @@
std::string py_imports();
std::string render_includes();
std::string render_fastbinary_includes();
- std::string declare_field(t_field* tfield);
+ std::string declare_argument(t_field* tfield);
+ std::string render_field_default_value(t_field* tfield);
std::string type_name(t_type* ttype);
std::string function_signature(t_function* tfunction, std::string prefix="");
std::string argument_list(t_struct* tstruct);
@@ -387,7 +388,7 @@
} else if (type->is_enum()) {
indent(out) << value->get_integer();
} else if (type->is_struct() || type->is_xception()) {
- out << type->get_name() << "({" << endl;
+ out << type->get_name() << "(**{" << endl;
indent_up();
const vector<t_field*>& fields = ((t_struct*)type)->get_members();
vector<t_field*>::const_iterator f_iter;
@@ -563,7 +564,7 @@
<< type_to_enum((*m_iter)->get_type()) << ", "
<< "'" << (*m_iter)->get_name() << "'" << ", "
<< type_to_spec_args((*m_iter)->get_type()) << ", "
- << "None" << ", "
+ << render_field_default_value(*m_iter) << ", "
<< "),"
<< " # " << sorted_keys_pos
<< endl;
@@ -578,36 +579,38 @@
}
- out <<
- indent() << "def __init__(self, d=None):" << endl;
- indent_up();
+ if (members.size() > 0) {
+ out <<
+ indent() << "def __init__(self,";
- if (members.size() == 0) {
- indent(out) <<
- "pass" <<endl;
- } else {
for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
// This fills in default values, as opposed to nulls
- indent(out) <<
- declare_field(*m_iter) << endl;
+ out << " " << declare_argument(*m_iter) << ",";
}
- indent(out) <<
- "if isinstance(d, dict):" << endl;
+ out << "):" << endl;
+
indent_up();
+
for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
- out <<
- indent() << "if '" << (*m_iter)->get_name() << "' in d:" << endl <<
- indent() << " self." << (*m_iter)->get_name() << " = d['" << (*m_iter)->get_name() << "']" << endl;
+ // Initialize fields
+ t_type* type = (*m_iter)->get_type();
+ if (!type->is_base_type() && !type->is_enum() && (*m_iter)->get_value() != NULL) {
+ indent(out) <<
+ "if " << (*m_iter)->get_name() << " is " << "self.thrift_spec[" <<
+ (*m_iter)->get_key() << "][4]:" << endl;
+ indent(out) << " " << (*m_iter)->get_name() << " = " <<
+ render_field_default_value(*m_iter) << endl;
+ }
+ indent(out) <<
+ "self." << (*m_iter)->get_name() << " = " << (*m_iter)->get_name() << endl;
}
+
indent_down();
+
+ out << endl;
}
- indent_down();
-
- out << endl;
-
-
generate_py_struct_reader(out, tstruct);
generate_py_struct_writer(out, tstruct);
@@ -1756,19 +1759,34 @@
}
/**
- * Declares a field, which may include initialization as necessary.
+ * Declares an argument, which may include initialization as necessary.
*
- * @param ttype The type
+ * @param tfield The field
*/
-string t_py_generator::declare_field(t_field* tfield) {
- string result = "self." + tfield->get_name();
+string t_py_generator::declare_argument(t_field* tfield) {
+ std::ostringstream result;
+ result << tfield->get_name() << "=";
+ if (tfield->get_value() != NULL) {
+ result << "thrift_spec[" <<
+ tfield->get_key() << "][4]";
+ } else {
+ result << "None";
+ }
+ return result.str();
+}
+
+/**
+ * Renders a field default value, returns None otherwise.
+ *
+ * @param tfield The field
+ */
+string t_py_generator::render_field_default_value(t_field* tfield) {
t_type* type = get_true_type(tfield->get_type());
if (tfield->get_value() != NULL) {
- result += " = " + render_const_value(type, tfield->get_value());
+ return render_const_value(type, tfield->get_value());
} else {
- result += " = None";
+ return "None";
}
- return result;
}
/**
diff --git a/test/py/SerializationTest.py b/test/py/SerializationTest.py
index 3b34661..4be8b8c 100755
--- a/test/py/SerializationTest.py
+++ b/test/py/SerializationTest.py
@@ -14,25 +14,25 @@
class AbstractTest(unittest.TestCase):
def setUp(self):
- self.v1obj = VersioningTestV1(d=dict(
+ self.v1obj = VersioningTestV1(
begin_in_both=12345,
end_in_both=54321,
- ))
+ )
- self.v2obj = VersioningTestV2(d=dict(
+ self.v2obj = VersioningTestV2(
begin_in_both=12345,
newint=1,
newbyte=2,
newshort=3,
newlong=4,
newdouble=5.0,
- newstruct=Bonk(d=dict(message="Hello!", type=123)),
+ newstruct=Bonk(message="Hello!", type=123),
newlist=[7,8,9],
newset=[42,1,8],
newmap={1:2,2:3},
newstring="Hola!",
end_in_both=54321,
- ))
+ )
def _serialize(self, obj):
trans = TTransport.TMemoryBuffer()