def __setup_columns(self): ''' Find all the columns attached to this model and assign storage. ''' column_id_util = ColumnIdentifierUtil(self) for prop_name in dir(self): try: prop = getattr(self, prop_name) except AttributeError: # property has not been initialized yet, ignore and continue continue if Column.is_column(prop): column = Column.get_column(prop) col_name = prop_name col_storage_id = column_id_util.get_column_identifier(column) storage = self.service_locator.get_storage(col_storage_id) self.columns[col_name] = BoundColumnCall(column, storage, self) elif SubModel.is_submodel(prop): submodel_name = prop_name submodel = prop self.submodels[submodel_name] = SubModelBinding(submodel, self)
def __setup_data_context(self): dc = self.data_context dc_navigator = DataContextNavigator(dc) for col_name, col in self.columns.iteritems(): metadata = Column.get_metadata(col) if metadata.uses_data_context: dc_prop = col_name if metadata.data_context == True else\ metadata.data_context try: column_context = dc_navigator.navigate(dc_prop) except (AttributeError, KeyError): raise Exception(type(self).__name__ + ', missing data_context value for column ' '%(col_name)s: %(dc_prop)s' '\n\t data_context = %(dc)s' % locals()) # allow binding primitives to single argument functions if not isinstance(column_context, dict): args = inspect.getargspec(metadata.inner_func).args if args == ['self']: column_context = {tuple():column_context} else: raise Exception(type(self).__name__ + ', data_context error for column ' '%s(col_name), unexpected data type. ' 'Must be dictionary, since the function' ' takes multiple arguments ' '(not just "self"\ndata_context=' '%(column_context)' % column_context) for args, val in column_context.iteritems(): col.set_value(args, val)
def do_timestep(self, t): if self.__columns == None: raise ModelException('You must call super.__init__') for col in self.columns.values(): metadata = Column.get_metadata(col) if metadata.is_automatically_called: col(t) for submodel in self.submodels.values(): submodel.do_timestep(t)
def testSingleArgBoundColumn(self): storage = {} model = object() def get_col_fn(unit_test, expected_model): get_col_fn.call_count = 0 def column_fn(self, t): # check that argument passed in is the model get_col_fn.call_count += 1 unit_test.assertEqual(expected_model, self) return 100 * t return column_fn # Setup a function to memoize column_fn = get_col_fn(self, model) # Setup the Column column = Column(column_fn, True) # Setup the ColumnBinding, maps a column to it's storage # and provides a callable interface column_binding = BoundColumnCall(column, storage, model) # Call the column self.assertEqual(get_col_fn.call_count, 0) column_binding(2) self.assertEqual(get_col_fn.call_count, 1) self.assertEqual({(2, ): 200}, storage) # Call column again column_binding(3) self.assertEqual(get_col_fn.call_count, 2) self.assertEqual({(2, ): 200, (3, ): 300}, storage) # subsequent calls should have no effect for i in xrange(1, 10): column_binding(2) column_binding(3) self.assertEqual(get_col_fn.call_count, 2) self.assertEqual({(2, ): 200, (3, ): 300}, storage) # Call column again column_binding(4) self.assertEqual(get_col_fn.call_count, 3) self.assertEqual({(2, ): 200, (3, ): 300, (4, ): 400}, storage)
def __setup_data_context(self): dc = self.data_context dc_navigator = DataContextNavigator(dc) for col_name, col in self.columns.iteritems(): metadata = Column.get_metadata(col) if metadata.uses_data_context: dc_prop = col_name if metadata.data_context == True else\ metadata.data_context try: column_context = dc_navigator.navigate(dc_prop) except (AttributeError, KeyError): raise Exception( type(self).__name__ + ', missing data_context value for column ' '%(col_name)s: %(dc_prop)s' '\n\t data_context = %(dc)s' % locals()) # allow binding primitives to single argument functions if not isinstance(column_context, dict): args = inspect.getargspec(metadata.inner_func).args if args == ['self']: column_context = {tuple(): column_context} else: raise Exception( type(self).__name__ + ', data_context error for column ' '%s(col_name), unexpected data type. ' 'Must be dictionary, since the function' ' takes multiple arguments ' '(not just "self"\ndata_context=' '%(column_context)' % column_context) for args, val in column_context.iteritems(): col.set_value(args, val)
def testGetMetadata(self): col = Column(lambda x: x, True) metadata = Column.get_metadata(col) self.assertIsInstance(metadata, ColumnMetadata, \ 'Expected column metadata')
def testIsAutoCallColumn(self): col = Column(lambda x: x, True) self.assertTrue(Column.is_column(col)) self.assertTrue(Column.is_auto_call(col))
def testIsColumn(self): col = Column(lambda x: x, False) self.assertTrue(Column.is_column(col)) self.assertFalse(Column.is_auto_call(col))
def get_column_identifier(self, column): col_id = self.__model_identifier + Column.get_column_name(column) metadata = {'args': getargspec(Column.get_metadata(column).inner_func)} return ColumnIdentifier(col_id, column, metadata)