Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@dnachbaur
Copy link
Contributor

  • emit JSON schema from FBS in zerobufCxx.py
  • create enum class for enums instead of 'old' enums; breaks existing enum names
  • fix wrong JSON value for empty arrays (was 'null', is '[]' now)

Copy link

@rdumusc rdumusc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there unit tests for the new ZeroBuf::getSchema() functionality?

"::" + impl_function +
"\n{" +
NEXTLINE + self.body)
file.write('\n{0} {1}{2}\n{{{3}{4}'.format(self.ret_val,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there not an extra '{' between \n and {3} ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, because .format() replaces all {} placeholders

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahhhh I finally got it after testing for myself... so the single { is ESCAPED as {{, otherwise .format() complains about a missing matching }...

return 'set{0}( {1}( ::zerobuf::fromJSON< {2} >( ::zerobuf::getJSONField( json, "{3}" ))));'.\
# convert enums to their name as a string
if self.value_type.is_enum_type:
return 'set{0}( {1}( from_string( ::zerobuf::fromJSON< std::string >( ::zerobuf::getJSONField( json, "{3}" )))));'.\
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

{2} not used, remove?

return '::zerobuf::toJSON( {0}( get{1}( )), ::zerobuf::getJSONField( json, "{2}" ));'.\
# convert enums back from their name
if self.value_type.is_enum_type:
return '::zerobuf::toJSON( std::string( to_string( get{1}( ))), ::zerobuf::getJSONField( json, "{2}" ));'.\
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here, {0} not used

strs.append('case {0}::{1}: return std::string( "{1}" );'.format(self.name, enumValue))
return Function('std::string',
'to_string( const {0}& val )'.format(self.name),
'switch( val )\n {{\n'
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

replace '\n ' occurences with NEXTLINE

if len(attrib) == 2 and is_zerobuf_type:
member = DynamicZeroBufMember(name, value_type, dynamic_type_index)
table = next(x for x in fbsFile.tables if x.name == cxxtype)
properties[name] = table.json_schema
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit confused as to what these variables represent. Is 'property' the equivalent of a c++ pointer or a reference on properties[name]? can't you do "property = table.json_schema" instead of "properties[name] = table.json_schema"?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's python, so it's most probably a reference. I tried the same assignment as you described, and as it didn't work, I fell back to the code I put.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

property = table.json_schema can't work. In python all variables are pointers (and argument passing could be called pointer by value)

if is_byte_type:
property['type'] = 'string'
property['media'] = {}
property['media']['binaryEncoding'] = 'base64'
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these three lines are a copy-paste of the other "if is_byte_type" above, maybe can be combined somehow?


if fbs in ['float', 'double']:
return 'number'
return 'integer'

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Funny naming... that means that for json an integer is not a number.

NEXTLINE + self.body)
file.write('\n{0} {1}{2}\n{{{3}{4}'.format(self.ret_val,
(classname + '::') if classname else '', impl_function,
NEXTLINE, self.body))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would write self.body in a separate file.write call, not so much for performance, but for readability.
I would even replace NEXTLINE with a function call startNextLine(file) to reduce the number of string concatenations (In some places the look ugly).

NEXTLINE + self.body + "\n")
file.write('\n{0}{1}{2}{3}\n'
.format((classname + '::') if classname else '', impl_function,
NEXTLINE, self.body))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

# convert enums to their name as a string
if self.value_type.is_enum_type:
return 'set{0}( {1}( from_string( ::zerobuf::fromJSON< std::string >( ::zerobuf::getJSONField( json, "{3}" )))));'.\
format(self.cxxName, self.value_type.type, self.value_type.get_data_type(), self.cxxname)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The format string doesn't have any {2}, but you are passing four parameters, review.

# convert enums back from their name
if self.value_type.is_enum_type:
return '::zerobuf::toJSON( std::string( to_string( get{1}( ))), ::zerobuf::getJSONField( json, "{2}" ));'.\
format(self.value_type.get_data_type(), self.cxxName, self.cxxname)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Format string has no {0}

def parse_members(self, fbsFile):
dynamic_type_index = 0
self.json_schema['properties'] = {}
properties = self.json_schema['properties']

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

properties = {}
self.json_schema['properties'] = properties
?

value_type = ValueType(cxxtype, cxxtype_size, is_zerobuf_type, is_enum_type, is_byte_type)

properties[name] = {}
property = properties[name]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above

if self.is_dynamic(attrib, fbsFile):
if len(attrib) == 2 and is_zerobuf_type:
member = DynamicZeroBufMember(name, value_type, dynamic_type_index)
table = next(x for x in fbsFile.tables if x.name == cxxtype)
Copy link

@hernando hernando Oct 20, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find this code a bit hard to understand (not the code itself, but why you do this). Can you add some comments to explain it.

dynamic_type_index += 1
self.dynamic_members.append(member)
else:
if len(attrib) == 2 or len(attrib) == 3:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ifs in this function are quite cryptic, but this is the one I understand less. Can you add comments to know what are the cases that you are dealing with in each branch?

dynamic_type_index = 0
self.json_schema['properties'] = {}
properties = self.json_schema['properties']
for attrib in self.attributes:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to suggest a big change in this for loop, feel free to do it, but I think it will improve readability. Actually it's two different proposals, if you don't want to do it any of them at least you should add more comments because the code it's quite convoluted.
Here I understand that you are doing two independent things in the same loop and it gets big. For readability I think it's better to separate the two processings. The easiest way to do it is to have two separate loops (despite the if sentences are going to be the same), one for the original code and another for the new stuff about properties. For maintainability the loop code should be refactored, and the only way I can imagine is using something similar to a visitor factor. In python you do it without to much hassle. Create a function for doing the loop and the if parts, this function takes as an argument a list of objects with callbacks to deal with each specific case. Declare two classes, one with the callbacks for the original code and another for the properties. With proper function names you won't need to write any single comment.

'\n default: throw std::runtime_error( "{1}" );\n }}'
.format(NEXTLINE.join(strs), 'Unknown value for enum {0}'.format(self.name)), split=True)
'switch( val ){0}{{\n'
' {1}'
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is still one NEXTLINE hiding here

property['media'] = {}
property['media']['binaryEncoding'] = 'base64'
if is_byte_type: # byte arrays are base64 strings
property = _add_base64_string(property)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So if I understand correctly the assignment and function return statement are redundant, since the function already modifies the property object passed to it

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function arguments are passed by copy, hence I found this 'pattern' to mimic a in-place modification :)

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just discovered that it is more subtle than that, you can't really reason in C++ terms of copy or reference with the python 'variables', they are more like 'labels' pointing to objects which are either mutable, or immutable. In this case 'property' is mutable (it's like a list) and it is modified by the function - the assignment and return value have no effect (it just reassigns 'property' to 'property'). Some references:
http://python.net/~goodger/projects/pycon/2007/idiomatic/handout.html#other-languages-have-variables
http://stackoverflow.com/questions/986006/how-do-i-pass-a-variable-by-reference/8140747#8140747

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rdumusc is right, property = _add_base64_string(property) doesn't make sense in Python. Functions arguments are not passed by copy, what is copied is the pointer to the object. That means you can't change the variable at the caller scope (but remind the variable is just a pointer), but you can change the object it points to.

@rdumusc
Copy link

rdumusc commented Oct 21, 2016

The code is good now, but what about the unit tests?

@dnachbaur
Copy link
Contributor Author

Good point.

@dnachbaur
Copy link
Contributor Author

dnachbaur commented Oct 21, 2016

On the other hand, the code coverage has not been affected. But I guess you want me to test the generated JSON schema.

@rdumusc
Copy link

rdumusc commented Oct 21, 2016

Yes indeed, I meant testing the new JSON schema part. This is really the sort of code which is well suited to unit testing.

@rdumusc
Copy link

rdumusc commented Oct 21, 2016

...almost there, the last thing missing are tests for the new enum-to-string conversion functions:

    std::string to_string( const TestEnum& val );
    TestEnum from_string( const std::string& val );
    std::ostream& operator << ( std::ostream& os, const TestEnum& val );

* emit JSON schema from FBS in zerobufCxx.py
* create enum class for enums instead of 'old' enums; breaks existing enum names
* fix wrong JSON value for empty arrays (was 'null', is '[]' now)
@dnachbaur
Copy link
Contributor Author

retest this please

@dnachbaur dnachbaur merged commit e095397 into HBPVIS:master Oct 21, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants