pythontinkerpopbulbs

Python Bulbs framework example of fget argument in a bulbs object init method


What is the scope of the fget= argument upon initialization of a Bulbs class property?

For instance when I am writing:

from bulbs.model import Node, Relationship
from bulbs.property import String

class foobar(Node)
   element_type = "foobar"
   fget_property = String(fget=some_method)

What some_method should be to get for the fget_property to be properly defined? Should it perform some operation on the other class properties or can it also be a function of the relations that are liked to an instance of the class, for instance something calling self.outV(some_relation)?


Solution

  • Here the value for fget should be a method name that returns a calculated value. The method name should reference a method defined in your Bulbs Model class, and the method should have no parameters.

    The fget method gets called every time you create/update/save the element to the database.

    See https://github.com/espeed/bulbs/blob/master/bulbs/model.py#L347

    Bulbs uses a Python Metaclass to set the fget function as a Python property on the Model class you are defining (not to be confused with the Bulbs database Property, such as String in your example).

    See Python class property (little "p") vs Bulbs database Property (big "P")...

    Here's how fget is set on the Bulbs Model you define:

    class ModelMeta(type):
        """Metaclass used to set database Property definitions on Models."""
    
        def __init__(cls, name, base, namespace):
            """Store Property instance definitions on the class as a dictionary.""" 
    
            # Get inherited Properties
            cls._properties = cls._get_initial_properties()
    
            # Add new Properties
            cls._register_properties(namespace)
    
        ### ...other class methods snipped for brevity... ###
    
        def _initialize_property(cls, key, property_instance):
            """
            Set the Model class attribute based on the Property definition.
    
            :param key: Class attribute key
            :type key: str
    
            :param property_instance: Property instance
            :type property_instance bulbs.property.Property
    
            """
            if property_instance.fget:
                fget = getattr(cls, property_instance.fget)
                # TODO: implement fset and fdel (maybe)
                fset = None
                fdel = None
                property_value = property(fget, fset, fdel)
            else:
                property_value = None
            setattr(cls, key, property_value)
    

    See https://github.com/espeed/bulbs/blob/master/bulbs/model.py#L97

    For an overview of how Metaclasses work in Python, see:

    UPDATE: Here is a complete working example of a model declaration using an fget method...

    # people.py    
    
    from bulbs.model import Node, Relationship                                                                                                                                                                                                    
    from bulbs.property import String, Integer, DateTime                                                                                                                                                                                          
    from bulbs.utils import current_datetime
    
    class Person(Node):  
    
        element_type = "person" 
    
       name = String(nullable=False)                                                                                                                                                                                                             
        age = Integer("calc_age")                                                                                                                                                                                                                 
    
        def calc_age(self):                                                                                                                                                                                                                       
            """A pointless method that calculates a hard-coded age."""                                                                                                                                                                            
            age = 2014 - 1977                                                                                                                                                                                                                     
            return age                                                                                                                                                                                                                            
    
    class Knows(Relationship):                                                                                                                                                                                                                    
    
        label = "knows" 
    
        timestamp = DateTime(default=current_datetime, nullable=False) 
    

    And here's a full working example for how to use it...

    >>> from bulbs.rexster import Graph
    >>> from people import Person, Knows                                                                                                                                                                                                              
    
    >>> g = Graph()                                                                                                                                                                                                                                   
    >>> g.add_proxy("people", Person)                                                                                                                                                                                                                 
    >>> g.add_proxy("knows", Knows)                                                                                                                                                                                                                   
    
    >>> james = g.people.create(name="James")                                                                                                                                                                                                         
    >>> julie = g.people.create(name="Julie")                                                                                                                                                                                                         
    >>> knows = g.knows.create(james, julie)                                                                                                                                                                                                          
    
    >>> print james.age
    37                                                                                                                                                                                                                               
    >>> print knows.timestamp
    2014-08-04 21:28:31