py2neo icon indicating copy to clipboard operation
py2neo copied to clipboard

Proposal: py2neo.ogm descriptors are difficult to get

Open motey opened this issue 5 years ago • 1 comments
trafficstars

I am trying to inspect a py2neo.ogm.GraphObject subclass. I want to check if a certain class attribute is a py2neo.ogm.Property:

from py2neo.ogm import Property, GraphObject
class Entity(GraphObject):
    name = Property()
print(type(getattr(Entity, "name")))

This will fail as with getattr(Entity, "name") py2neo.ogm.Property.__get__() will be called and raises an

AttributeError: 'NoneType' object has no attribute '__node__'

One workaround is to check my classes __dict__

print(type(Entity.__dict__["name"]))

This will return '<class 'py2neo.ogm.Property'>' Now i know that Entity.name is py2neo.ogm.Property. Nice...But:

This will fail as soon the Property is inherited.

from py2neo.ogm import Property, GraphObject
class Entity(GraphObject):
    name = Property()
class Person(Entity):
    pass
print(type(Person.__dict__["name"]))

This will fail with a "KeyError: 'name'" as 'name' is in the superclass Entity.

I could now start to traverse all subclasses and search for the attr.

Another solution is to add an instance check to all py2neo.ogm descriptors

py2neo/internal/ogm.py[z41]:

[...]
class Property(object):
[...]
ef __get__(self, instance, owner):
        if instance is None:
            return self
[...]

now we easily could create a neat helper func like:

def get_graphobjectclass_property_keys(cls, graphobjectclass) -> [str]:
	return [
	    propname
	    for propname in dir(graphobjectclass)
	    if isinstance(getattr(graphobjectclass,propname), Property)
	]
  • Whats you opinion on that?
  • Do you know a better way to achive my goal

Related discussion on stackoverflow: https://stackoverflow.com/questions/21629397/neat-way-to-get-descriptor-object

I will create a merge request for the changes.

motey avatar Jan 29 '20 09:01 motey

Hi @motey. Thanks for raising this, I can see that it's a valid gap in the functionality. Your proposal feels like it's along the right lines, but I'm going to give some thought to slightly broader functionality around reflection of GraphObjects. Watch this space.

technige avatar Jan 30 '20 15:01 technige