dropbox/stone

Properties are not always optional

gvanrossum opened this issue · 2 comments

Hey Stone team! We found an issue with the typing stub code generated for properties. I believe this block of code should be deleted:

if not is_nullable_type(field.data_type) and not is_void_type(field.data_type):
self.import_tracker._register_typing_import('Optional')
getter_field_type = 'Optional[{}]'.format(setter_field_type)

The effect of this block is to always add Optional[] around the return type of a property getter. (The logic looks backwards, but for nullable and void types there already is an Optional[].)

But if you look at the runtime code generated, you'll see that for a non-nullable default-less property, None is never returned, it raises an exception if the value isn't set:

if dt_nullable:
self.emit('if val is None:')
with self.indent():
self.emit('del self.{}'.format(field_name_reserved_check))
self.emit('return')
if is_user_defined_type(field_dt):
self.emit('self._%s_validator.validate_type_only(val)' %
field_name)
else:
self.emit('val = self._{}_validator.validate(val)'.format(field_name))

I will propose a PR to fix this. I have tested the PR in the Dropbox server repo, and it caused only two errors, and those look genuine.

CC: @ilevkivskyi

nit: should the second code example from line 609 to line 618?

Oh, you're right. Here's the code fragment I meant to link to:

self.emit('if self._{}_present:'.format(field_name))
with self.indent():
self.emit('return self._{}_value'.format(field_name))
self.emit('else:')
with self.indent():
if dt_nullable:
self.emit('return None')
elif field.has_default:
self.emit('return {}'.format(
self._generate_python_value(ns, field.default)))
else:
self.emit(
"raise AttributeError(\"missing required field '%s'\")"
% field_name
)