def _generate_compute_method(self): compute_method = 4 * ' ' + 'def compute(self, dataset_pool): \n' # Generate local bindings for variables. We need to avoid overwriting an existing binding, # so keep track of which have already been generated. For example, when we first encounter # urbansim.gridcell.population, we need to generate all of the bindings (as described in the # long comment before this method). After that, if we encounter urbansim.household.has_children # we need to add a household attribute to urbansim -- but not reinitialize the variable # urbansim itself. Then if we find urbansim.gridcell.population_density we should just add # the population_density attribute to urbansim.gridcell (and not reinitialize either urbansim # or urbansim.gridcell). already_generated = set() for pkg, ds, short in self._dependents: # if the dataset name ends in self._constant_suffix, get the dataset out of the dataset pool; otherwise it is self.get_dataset() if ds is not None and ds.endswith(self._constant_suffix): getter = 'dataset_pool.get_dataset("%s").get_attribute("%s.%s")' % ( ds, ds, short) else: getter = 'self.get_dataset().get_attribute("%s.%s")' % (ds, short) if ds is None: # the dependent is an unqualified attribute name compute_method = compute_method + 8 * ' ' + '%s = %s \n' % ( short, getter) elif pkg is None: if (None, ds) not in already_generated: compute_method = compute_method + 8 * ' ' + '%s = DummyDataset(self, "%s", dataset_pool) \n' % ( ds, ds) already_generated.add((None, ds)) compute_method = compute_method + 8 * ' ' + '%s.%s = %s \n' % ( ds, short, getter) else: if pkg not in already_generated: compute_method = compute_method + 8 * ' ' + '%s = DummyName() \n' % pkg already_generated.add(pkg) if (pkg, ds) not in already_generated: compute_method = compute_method + 8 * ' ' + '%s.%s = DummyDataset(self, "%s", dataset_pool) \n' % ( pkg, ds, ds) already_generated.add((pkg, ds)) compute_method = compute_method + 8 * ' ' + '%s.%s.%s = %s \n' % ( pkg, ds, short, getter) # generate bindings for receivers of aggregate and disaggregate methods for receiver, method, pkg, aggregated_dataset, aggregated_attr, intermediates, op in self._aggregation_calls: if (None, receiver) not in already_generated: compute_method = compute_method + 8 * ' ' + '%s = DummyDataset(self, "%s", dataset_pool) \n' % ( receiver, receiver) already_generated.add((None, receiver)) for receiver in self._special_dataset_receivers: if (None, receiver) not in already_generated: compute_method = compute_method + 8 * ' ' + '%s = DummyDataset(self, "%s", dataset_pool) \n' % ( receiver, receiver) already_generated.add((None, receiver)) # If we need to replace parts of the parse tree, do the replacements, and turn the parse tree # back into a string to generate the method. Otherwise just use the original expression. # (We could always turn the tree back into a string I guess ...) if len(self._parsetree_replacements) == 0: newexpr = self._expr else: newtree = parsetree_substitute(self._expr_parsetree, self._parsetree_replacements) newexpr = parsetree_to_string(newtree) # the parse tree doesn't include the assignment statement that sets up the alias if self._alias is not None: newexpr = self._alias + ' = ' + newexpr # If alias is None, we can just return the expression. If alias is not none, then expr will bind # the alias to the desired value, so execute expr, and return the value in the alias. if self._alias is None: compute_method = compute_method + 8 * ' ' + 'return ' + newexpr + '\n' else: compute_method = compute_method + 8 * ' ' + newexpr + '\n' compute_method = compute_method + 8 * ' ' + 'return ' + self._alias + '\n' return compute_method
def _generate_compute_method(self): compute_method = 4*' ' + 'def compute(self, dataset_pool): \n' # Generate local bindings for variables. We need to avoid overwriting an existing binding, # so keep track of which have already been generated. For example, when we first encounter # urbansim.gridcell.population, we need to generate all of the bindings (as described in the # long comment before this method). After that, if we encounter urbansim.household.has_children # we need to add a household attribute to urbansim -- but not reinitialize the variable # urbansim itself. Then if we find urbansim.gridcell.population_density we should just add # the population_density attribute to urbansim.gridcell (and not reinitialize either urbansim # or urbansim.gridcell). already_generated = set() for pkg, ds, short in self._dependents: # if the dataset name ends in self._constant_suffix, get the dataset out of the dataset pool; otherwise it is self.get_dataset() if ds is not None and ds.endswith(self._constant_suffix): getter = 'dataset_pool.get_dataset("%s").get_attribute("%s.%s")' % (ds,ds,short) else: getter = 'self.get_dataset().get_attribute("%s.%s")' % (ds,short) if ds is None: # the dependent is an unqualified attribute name compute_method = compute_method + 8*' ' + '%s = %s \n' % (short, getter) elif pkg is None: if (None,ds) not in already_generated: compute_method = compute_method + 8*' ' + '%s = DummyDataset(self, "%s", dataset_pool) \n' % (ds, ds) already_generated.add( (None,ds) ) compute_method = compute_method + 8*' ' + '%s.%s = %s \n' % (ds, short, getter) else: if pkg not in already_generated: compute_method = compute_method + 8*' ' + '%s = DummyName() \n' % pkg already_generated.add(pkg) if (pkg,ds) not in already_generated: compute_method = compute_method + 8*' ' + '%s.%s = DummyDataset(self, "%s", dataset_pool) \n' % (pkg, ds, ds) already_generated.add( (pkg,ds) ) compute_method = compute_method + 8*' ' + '%s.%s.%s = %s \n' % (pkg, ds, short, getter) # generate bindings for receivers of aggregate and disaggregate methods for receiver, method, pkg, aggregated_dataset, aggregated_attr, intermediates, op in self._aggregation_calls: if (None,receiver) not in already_generated: compute_method = compute_method + 8*' ' + '%s = DummyDataset(self, "%s", dataset_pool) \n' % (receiver, receiver) already_generated.add( (None,receiver) ) for receiver in self._special_dataset_receivers: if (None,receiver) not in already_generated: compute_method = compute_method + 8*' ' + '%s = DummyDataset(self, "%s", dataset_pool) \n' % (receiver, receiver) already_generated.add( (None,receiver) ) # If we need to replace parts of the parse tree, do the replacements, and turn the parse tree # back into a string to generate the method. Otherwise just use the original expression. # (We could always turn the tree back into a string I guess ...) if len(self._parsetree_replacements)==0: newexpr = self._expr else: newtree = parsetree_substitute(self._expr_parsetree, self._parsetree_replacements) newexpr = parsetree_to_string(newtree) # the parse tree doesn't include the assignment statement that sets up the alias if self._alias is not None: newexpr = self._alias + ' = ' + newexpr # If alias is None, we can just return the expression. If alias is not none, then expr will bind # the alias to the desired value, so execute expr, and return the value in the alias. if self._alias is None: compute_method = compute_method + 8*' ' + 'return ' + newexpr + '\n' else: compute_method = compute_method + 8*' ' + newexpr + '\n' compute_method = compute_method + 8*' ' + 'return ' + self._alias + '\n' return compute_method
def _analyze_aggregation_method_call(self, receiver, method, args): same, vars = match(SUBPATTERN_AGGREGATION, args) if not same: raise ValueError, "syntax error for aggregation method call" arg_dict = self._get_arguments( ('arg1', 'arg2', 'arg3'), ('aggr_var', 'intermediates', 'function'), vars) if 'aggr_var' not in arg_dict: raise ValueError, "syntax error for aggregation method call (problem with argument for variable being aggregated)" same1, vars1 = match(SUBPATTERN_FULLY_QUALIFIED_VARIABLE_ARG, arg_dict['aggr_var']) if same1: # the aggregated variable is a fully-qualified name pkg = vars1['package'] dataset = vars1['dataset'] attr = vars1['shortname'] else: same2, vars2 = match(SUBPATTERN_DATASET_QUALIFIED_VARIABLE_ARG, arg_dict['aggr_var']) if same2: # the aggregated variable is a dataset-qualified name pkg = None dataset = vars2['dataset'] attr = vars2['shortname'] else: # The thing being aggregated is an expression. Generate a new autogen variable for that expression, # and use the autogen variable in the aggregation call. subexpr = arg_dict['aggr_var'] newvar = VariableName(parsetree_to_string(subexpr)) pkg = None dataset = newvar.get_dataset_name() if dataset is None: raise ValueError, "syntax error for aggregation method call - could not determine dataset for variable being aggregated" attr = newvar.get_short_name() # TODO DELETE BELOW: # replacements = {'dataset': dataset, 'attribute': attr} # newvar_tree = parsetree_substitute(DATASET_QUALIFIED_VARIABLE_TEMPLATE, replacements) # self._parsetree_replacements[subexpr] = newvar_tree if 'intermediates' in arg_dict: # make sure that it really is a list s, v = match(SUBPATTERN_LIST_ARG, arg_dict['intermediates']) if not s: raise ValueError, "syntax error for aggregation method call (list of intermediate datasets not a list?)" intermediates = tuple( self._extract_names(arg_dict['intermediates'])) else: intermediates = () if 'function' in arg_dict: # bind fcn to a string that is the name of the function, or to the string "None" s, v = match(SUBPATTERN_NAME_ARG, arg_dict['function']) if not s: raise ValueError, "syntax error for aggregation method call (problem with the function argument in the call)" fcn = v['name'] else: fcn = None self._aggregation_calls.add( (receiver, method, pkg, dataset, attr, intermediates, fcn)) quoted_intermediates = "" if len(intermediates) == 0 else quote( intermediates[0]) for n in intermediates[1:]: quoted_intermediates = quoted_intermediates + ', ' + quote(n) # 'call' is a string representing the new aggregation call. Parse it, extract the args, and then add a replacement to # parsetree_replacements for the old args. We want to replace just the args and not the entire call to aggregate, # since the way Python represents parsetrees the whole tree may include astype and exponentiation calls, and it's simpler # to just replace the args part. call = "%s.%s(%s, %s,%s, [%s], %s)" % ( receiver, method, quote(pkg), quote(dataset), quote(attr), quoted_intermediates, quote(fcn)) (newtree, _) = self._parse_expr(call) s, v = match(FULL_EXPRESSION_METHOD_CALL, newtree) if not s: raise StandardError, 'internal error - problem generating new aggregation expression' self._parsetree_replacements[args] = v['args']
def _analyze_aggregation_method_call(self, receiver, method, args): same, vars = match(SUBPATTERN_AGGREGATION, args) if not same: raise ValueError, "syntax error for aggregation method call" arg_dict = self._get_arguments( ('arg1', 'arg2','arg3'), ('aggr_var', 'intermediates','function'), vars ) if 'aggr_var' not in arg_dict: raise ValueError, "syntax error for aggregation method call (problem with argument for variable being aggregated)" same1, vars1 = match(SUBPATTERN_FULLY_QUALIFIED_VARIABLE_ARG, arg_dict['aggr_var']) if same1: # the aggregated variable is a fully-qualified name pkg = vars1['package'] dataset = vars1['dataset'] attr = vars1['shortname'] else: same2, vars2 = match(SUBPATTERN_DATASET_QUALIFIED_VARIABLE_ARG, arg_dict['aggr_var']) if same2: # the aggregated variable is a dataset-qualified name pkg = None dataset = vars2['dataset'] attr = vars2['shortname'] else: # The thing being aggregated is an expression. Generate a new autogen variable for that expression, # and use the autogen variable in the aggregation call. subexpr = arg_dict['aggr_var'] newvar = VariableName(parsetree_to_string(subexpr)) pkg = None dataset = newvar.get_dataset_name() if dataset is None: raise ValueError, "syntax error for aggregation method call - could not determine dataset for variable being aggregated" attr = newvar.get_short_name() # TODO DELETE BELOW: # replacements = {'dataset': dataset, 'attribute': attr} # newvar_tree = parsetree_substitute(DATASET_QUALIFIED_VARIABLE_TEMPLATE, replacements) # self._parsetree_replacements[subexpr] = newvar_tree if 'intermediates' in arg_dict: # make sure that it really is a list s, v = match(SUBPATTERN_LIST_ARG, arg_dict['intermediates']) if not s: raise ValueError, "syntax error for aggregation method call (list of intermediate datasets not a list?)" intermediates = tuple(self._extract_names(arg_dict['intermediates'])) else: intermediates = () if 'function' in arg_dict: # bind fcn to a string that is the name of the function, or to the string "None" s,v = match(SUBPATTERN_NAME_ARG, arg_dict['function']) if not s: raise ValueError, "syntax error for aggregation method call (problem with the function argument in the call)" fcn = v['name'] else: fcn = None self._aggregation_calls.add( (receiver, method, pkg, dataset, attr, intermediates, fcn) ) quoted_intermediates = "" if len(intermediates)==0 else quote(intermediates[0]) for n in intermediates[1:]: quoted_intermediates = quoted_intermediates + ', ' + quote(n) # 'call' is a string representing the new aggregation call. Parse it, extract the args, and then add a replacement to # parsetree_replacements for the old args. We want to replace just the args and not the entire call to aggregate, # since the way Python represents parsetrees the whole tree may include astype and exponentiation calls, and it's simpler # to just replace the args part. call = "%s.%s(%s, %s,%s, [%s], %s)" % (receiver, method, quote(pkg), quote(dataset), quote(attr), quoted_intermediates, quote(fcn)) (newtree,_) = self._parse_expr(call) s, v = match(FULL_EXPRESSION_METHOD_CALL, newtree) if not s: raise StandardError, 'internal error - problem generating new aggregation expression' self._parsetree_replacements[args] = v['args']