Re: [openstack-dev] [oslo][nova]Accessing nullable, not set versioned object field

2016-12-20 Thread Balázs Gibizer
From: Dan Smith 
Sent: 16 December 2016 16:33
>> NotImplementedError: Cannot load 'nullable_string' in the base class
>>
>> Is this the correct behavior?
> 
> Yes, that's the expected behaviour.

Yes.

>> Then what is the expected behavior if the field is also defaulted to
>> None?
>>
>> fields = {
>> 'nullable_string': fields.StringField(nullable=True,
>> default=None),
>> }
>>
>> The actual behavior is still the same exception above. Is it the
>> correct behavior?
> 
> Yes. So, what the default=None does is describe the behaviour of the
> field when obj_set_defaults() is called. It does *not* describe what is
> returned if the field *value* is accessed before being populated.
>
> What you're looking for is the obj_attr_is_set() method:
>
> 
> if MyObject.obj_attr_is_set('nullable_string'):
> print my_obj.nullable_string

I think you meant s/MyObject/my_obj/ above. However, in modern times,
it's better to use:

 if 'nullable_string' in myobj

On a per-object basis, it may also be reasonable to define
obj_load_attr() to provide the default for a field if it's not set and
attempted to be loaded.

> In addition to the obj_attr_is_set() method, use the obj_set_defaults()
> method to manually set all fields that have a default=XXX value to XXX
> if those fields have not yet been manually set:

There's another wrinkle here. The default=XXX stuff was actually
introduced before we had obj_set_defaults(), and for a very different
reason. That reason was confusing and obscure, and mostly supportive of
the act of converting nova from dicts to objects. If you look in fields,
there is an obscure handling of default, where if you _set_ a field to
None that has a default and is not nullable, it will gain the default value.

It's confusing and I wish we had never done it, but.. it's part of the
contract now and I'd have to do a lot of digging to see if we can remove
it (probably can from Nova, but...).

Your use above is similar to this, so I just wanted to point it out in
case you came across it and it led you to thinking your original example
would work.

--Dan

Thank you for the answers. Following up on this. Is it considered a good
practice to instantiate an ovo but keeping some non-lazy loaded
fields unset?

I think the user of the ovo instance should be able to assume that the
fields declared in the ovo are accessible after the ovo is instantiated
without manually checking obj_attr_is_set().

I know that lazy-loaded fields are a special case because the user of 
the ovo instance will see that the lazy-loaded field is not set if calls 
obj_attr_is_set() but as soon as user code tries to access it the 
backend will fetch and return the value of the field.

However there are cases in nova where an instantiated ovo has some
not set, not lazy-loaded field. For example Service.availability_zone  is
not lazy-loaded [2] but it is allowed to be not set by [1].
Is it considered a bug? Should the code [1] set Serivce.availability_zone to 
None instead of keeping it not set?

Cheers,
gibi

[1] https://github.com/openstack/nova/blob/master/nova/objects/service.py#L197
[2] https://github.com/openstack/nova/blob/master/nova/objects/service.py#L221

__
OpenStack Development Mailing List (not for usage questions)
Unsubscribe: openstack-dev-requ...@lists.openstack.org?subject:unsubscribe
http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev


openstack-dev mailing list
lists.openstack.org
This list for the developers of OpenStack to discuss development issues and 
roadmap. It is focused on the next release of OpenStack: you should post on 
this list if ...


__
OpenStack Development Mailing List (not for usage questions)
Unsubscribe: openstack-dev-requ...@lists.openstack.org?subject:unsubscribe
http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev


Re: [openstack-dev] [oslo][nova]Accessing nullable, not set versioned object field

2016-12-16 Thread Dan Smith
>> NotImplementedError: Cannot load 'nullable_string' in the base class
>>
>> Is this the correct behavior?
> 
> Yes, that's the expected behaviour.

Yes.

>> Then what is the expected behavior if the field is also defaulted to
>> None?
>>
>> fields = {
>> 'nullable_string': fields.StringField(nullable=True,
>> default=None),
>> }
>>
>> The actual behavior is still the same exception above. Is it the
>> correct behavior?
> 
> Yes. So, what the default=None does is describe the behaviour of the
> field when obj_set_defaults() is called. It does *not* describe what is
> returned if the field *value* is accessed before being populated.
>
> What you're looking for is the obj_attr_is_set() method:
>
> 
> if MyObject.obj_attr_is_set('nullable_string'):
> print my_obj.nullable_string

I think you meant s/MyObject/my_obj/ above. However, in modern times,
it's better to use:

 if 'nullable_string' in myobj

On a per-object basis, it may also be reasonable to define
obj_load_attr() to provide the default for a field if it's not set and
attempted to be loaded.

> In addition to the obj_attr_is_set() method, use the obj_set_defaults()
> method to manually set all fields that have a default=XXX value to XXX
> if those fields have not yet been manually set:

There's another wrinkle here. The default=XXX stuff was actually
introduced before we had obj_set_defaults(), and for a very different
reason. That reason was confusing and obscure, and mostly supportive of
the act of converting nova from dicts to objects. If you look in fields,
there is an obscure handling of default, where if you _set_ a field to
None that has a default and is not nullable, it will gain the default value.

It's confusing and I wish we had never done it, but.. it's part of the
contract now and I'd have to do a lot of digging to see if we can remove
it (probably can from Nova, but...).

Your use above is similar to this, so I just wanted to point it out in
case you came across it and it led you to thinking your original example
would work.

--Dan

__
OpenStack Development Mailing List (not for usage questions)
Unsubscribe: openstack-dev-requ...@lists.openstack.org?subject:unsubscribe
http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev


Re: [openstack-dev] [oslo][nova]Accessing nullable, not set versioned object field

2016-12-16 Thread Jay Pipes

On 12/16/2016 07:42 AM, Balázs Gibizer wrote:

Hi,

What is the expected behavior of accessing a nullable and
not set versioned object field?
See the following example code:

from oslo_versionedobjects import base
from oslo_versionedobjects import fields


@base.VersionedObjectRegistry.register
class MyObject(base.VersionedObject):

VERSION = '1.0'
fields = {
'nullable_string': fields.StringField(nullable=True),
}


my_obj = MyObject()
my_obj.nullable_string

#EOF

My naïve expectation would be that the value of my_obj.nullable_string
is None but the actual behavior is an exception:

Traceback (most recent call last):
  File "ovo_nullable_test.py", line 15, in 
my_obj.nullable_string
  File 
".tox/functional/local/lib/python2.7/site-packages/oslo_versionedobjects/base.py",
 line 67, in getter
self.obj_load_attr(name)
  File 
".tox/functional/local/lib/python2.7/site-packages/oslo_versionedobjects/base.py",
 line 603, in obj_load_attr
_("Cannot load '%s' in the base class") % attrname)
NotImplementedError: Cannot load 'nullable_string' in the base class

Is this the correct behavior?


Yes, that's the expected behaviour.


Then what is the expected behavior if the field is also defaulted to None?

fields = {
'nullable_string': fields.StringField(nullable=True, default=None),
}

The actual behavior is still the same exception above. Is it the correct 
behavior?


Yes. So, what the default=None does is describe the behaviour of the 
field when obj_set_defaults() is called. It does *not* describe what is 
returned if the field *value* is accessed before being populated.


What you're looking for is the obj_attr_is_set() method:

if MyObject.obj_attr_is_set('nullable_string'):
print my_obj.nullable_string

In addition to the obj_attr_is_set() method, use the obj_set_defaults() 
method to manually set all fields that have a default=XXX value to XXX 
if those fields have not yet been manually set:


class MyObject(ovo.VersionedObjectBase):
def create(self):
self.obj_set_defaults()
# Now you can access your nullable_string field.

The reason this was done was to allow us to differentiate between fields 
that had not had their value set and fields that HAD had their attribute 
set, but to None.


Best,
-jay

__
OpenStack Development Mailing List (not for usage questions)
Unsubscribe: openstack-dev-requ...@lists.openstack.org?subject:unsubscribe
http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev


[openstack-dev] [oslo][nova]Accessing nullable, not set versioned object field

2016-12-16 Thread Balázs Gibizer
Hi, 

What is the expected behavior of accessing a nullable and 
not set versioned object field?
See the following example code:

from oslo_versionedobjects import base
from oslo_versionedobjects import fields


@base.VersionedObjectRegistry.register
class MyObject(base.VersionedObject):

VERSION = '1.0'
fields = {
'nullable_string': fields.StringField(nullable=True),
}


my_obj = MyObject()
my_obj.nullable_string

#EOF

My naïve expectation would be that the value of my_obj.nullable_string
is None but the actual behavior is an exception:

Traceback (most recent call last):
  File "ovo_nullable_test.py", line 15, in 
my_obj.nullable_string
  File 
".tox/functional/local/lib/python2.7/site-packages/oslo_versionedobjects/base.py",
 line 67, in getter
self.obj_load_attr(name)
  File 
".tox/functional/local/lib/python2.7/site-packages/oslo_versionedobjects/base.py",
 line 603, in obj_load_attr
_("Cannot load '%s' in the base class") % attrname)
NotImplementedError: Cannot load 'nullable_string' in the base class

Is this the correct behavior?

Then what is the expected behavior if the field is also defaulted to None?

fields = {
'nullable_string': fields.StringField(nullable=True, default=None),
}

The actual behavior is still the same exception above. Is it the correct 
behavior?

More real life example:
Nova has a Service object that has an availability_zone nullable field [1].
When a Service object is loaded from the db the code allows not to fill
the availability_zone field [2]. This result in a Service object instance that
will produce the above exception if the code tries to access the 
availability_zone
field later. 

The whole problem arises when we try to send a service status notification and 
we
want to copy the fields from the Service object blindly to the notification 
payload.
To avoid the above exception we added a check to the notification payload 
generation
[3] to see if the given field is set or not. But this causes that if a field is 
lazy-loaded
but not loaded yet then we simply handle that the same way as non lazy-loaded
not set field. In the lazy-load case we might want to trigger a lazy-load 
during the copy but
in the non lazy-load case accessing the field would cause an exception.
Currently I don't see a way to distinguish between the two cases without 
triggering the
lazy-load / exception itself.

Cheers,
gibi

[1] https://github.com/openstack/nova/blob/master/nova/objects/service.py#L133 
[2] https://github.com/openstack/nova/blob/master/nova/objects/service.py#L197 
[3] 
https://github.com/openstack/nova/blob/master/nova/notifications/objects/base.py#L97
 

__
OpenStack Development Mailing List (not for usage questions)
Unsubscribe: openstack-dev-requ...@lists.openstack.org?subject:unsubscribe
http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev