def __init__(self, *args, **kwargs): # encapsulate fg manager self._m = ForegroundManager(*args, **kwargs) # some common / useful shortcuts self._catalog = self._m._catalog self._flowdb = self._m._flowdb self._menu_position = [choices] self._current_archive = None self._result_set = [] self.selected = set() self._selected_flowable = None self._selected_compartment = None self._selected_fragment = None
class ForegroundInterface(object): """ This class stores all the user functions for handling the foreground, all wrapped up in a tidy menu. The ForegroundManager takes care of serializing changes as soon as they are made. This interface is where we spell out "all the things Kyle would want to do" So here it is: = background catalog reference: - list flows / processes / quantities - group by properties, browse + search - select a set of entities - find terminations / originations = flows: list cfs - synonyms + manage synonyms? = processes: list exchanges - perform LCIA on selected quantity = new foreground (dir) = default quantities (ILCD) + add selected entities to foreground - quantities list - background list, of catalog refs + create flows-- browse compartments to select - name - CAS + characterizations - browse quantities (need ref) = create fragments - select a flow = terminate as foreground or background - fg: match terminating process and recurse on exchanges (elementary flows omitted) - foreground lcia: all flows net, vs each flow * serialize + deserialize fragments The UX: + Search for entities [type of entities] + browse entities by type - process-Classification - select single entity - fg query = ecoinvent- to data = ilcd / uslci- straight from catalog - fg lcia of quantity - tabular output so for TOMORROW... list group search + select and THEN it's the reporting and the charting- barfigs for that?? gonna have to be that or more python- (- feh, day's work to do the TeX) Antelope products: -processes -processflows -lciaresults -fragments -fragmentflows -lciaresults -flowproperties [lack Method tag] -flows -stages -scenarios -params """ def __init__(self, *args, **kwargs): # encapsulate fg manager self._m = ForegroundManager(*args, **kwargs) # some common / useful shortcuts self._catalog = self._m._catalog self._flowdb = self._m._flowdb self._menu_position = [choices] self._current_archive = None self._result_set = [] self.selected = set() self._selected_flowable = None self._selected_compartment = None self._selected_fragment = None def _show(self): self._m.show(loaded=False) return True def _choose_archive(self, loaded=True, allow_all=True): try: self._m.show(loaded=loaded) except NoLoadedArchives: return -1 while True: item = input('Enter choice, 0-%d%s ("x" to cancel):' % (len(self._catalog)-1, ' or "a" to select all' * allow_all)) if item.lower() == 'a' and allow_all: return None elif item.lower() == 'x': return -1 else: try: index = int(item) except ValueError: try: index = self._catalog.get_index(item) except KeyError: break if loaded: if not self._catalog.is_loaded(index): index = None if index is not None: return index print('Invalid choice.') @property def _archive(self): if self._current_archive is None: ar = self._choose_archive(allow_all=False) if ar == -1: raise NoLoadedArchives return self._catalog[ar] return self._catalog[self._current_archive] def menu(self): """ present the menu pointed to by the current _menu_position- follow subdicts until a handler is encountered handlers are callable :return: """ pointer = self._menu_position.pop(-1) while True: print('\n\n%s' % ('#' * 120)) self._catalog.show_loaded() if self._current_archive is None: print('\nSearching all loaded archives') else: print('\nCurrent archive: %s' % self._current_archive) if self._selected_flowable is not None: print('\n Current Flowable: %.100s' % self._flowdb.flowables[self._selected_flowable]) if self._selected_compartment is not None: print('\n Current Compartment: %s' % self._selected_compartment.to_list()) if len(self.selected) == 0: print(' [[ No entities currently selected ]]') else: print('\n Current entity selection: ') for i in self.selected: print('[[ %s ]]' % i) while isinstance(pointer, dict): self._menu_position.append(pointer) go_up = len(self._menu_position) > 1 uchoice = menu_list(*[k for k, v in pointer.items() if v != []], go_up=go_up) if uchoice == -1 or uchoice is None: if len(self._menu_position) == 1: pointer = 1 break self._menu_position.pop(-1) pointer = self._menu_position.pop(-1) else: pointer = pointer[uchoice] # pointer = 1 is the signal to quit if pointer == 1: break # if pointer is not a dict, it must be callable # and it must return a valid pointer string message = pointer(self)() if message is not True and message is not None: print('** %s ** ' % message) sleep(0.8) pointer = self._menu_position.pop(-1) self._m.save() # now the fun part- writing the callables # callables should specify new menu position to return to def add_archive(self): print('Add a new archive by reference.') source = input('Source: ') nick = input('Nickname for this source: ') ds_type = pick_list(dataSourceTypes) print('Input parameters or blank') params = get_kv_pairs('Parameter') self._catalog.add_archive(source, [nick], ds_type, **params) return True def load_archive(self): index = self._choose_archive(loaded=False, allow_all=False) if index == -1: return 'No option selected' if self._catalog.is_loaded(index): print('Loading all entities') self._catalog.load_all(index) else: self._catalog.load(index) return True def set_current_archive(self): self._current_archive = self._choose_archive(loaded=False, allow_all=True) if not self._catalog.is_loaded(self._current_archive): self._m.load(self._current_archive) return True def _prompt_add(self, entity): if entity is None: return True p = ifinput('Add to selection? y/n', 'y') if p == 'y': self.selected.add(entity) return entity return True def add_selection(self): self._menu_position.pop() if not self._catalog.is_loaded(0): return 'Foreground is not loaded.' for i in self.selected: self._m.add_to_foreground(i) self.selected.clear() return True @staticmethod def _narrow_search(result_set): key = ifinput('Enter search key', 'Name') val = input('Enter search expression (regexp): ') n = [r for r in result_set if key in r.keys() and bool(re.search(val, r[key], flags=re.IGNORECASE))] if len(n) == 0: print('No results') return result_set else: return n def _continue_search(self, result_set): """ :param result_set: set of catalog refs :return: """ while 1: if len(result_set) == 0: return 'No results.' if len(result_set) > 20: group(result_set) i = cyoa('\n(B) Browse results, (A) select all, (N)arrow search, or (X) abandon search / finished?', 'BANX', 'N') else: show_res(result_set) i = cyoa('\n(S) Select one, (A) select all, (N)arrow search, or (X) abandon search / finished?', 'SANX', 'S') if i.lower() == 'x': return True elif i.lower() == 'a': self.selected = self.selected.union(result_set) return True elif i.lower() == 'n': result_set = self._narrow_search(result_set) elif i.lower() == 'b': pick = pick_one(result_set) e = self._prompt_add(pick) if e in result_set: result_set.remove(e) elif i.lower() == 'b' or i.lower() == 's': # 'b' ad 's' are the same- browse and pick pick = pick_one(result_set) if pick is not None: self.selected.add(pick) result_set.remove(pick) else: try: if int(i) < len(result_set): pick = result_set[int(i)] self.selected.add(pick) result_set.remove(pick) except ValueError: pass def isearch(self, etype): self._menu_position = [choices, choices['Catalog']] string = input('Search term (regex):') return lambda: self._continue_search(self._m.search(self._current_archive, etype, Name=string, show=False)) ''' def isearch_p(self): self.isearch('process') def isearch_f(self): self.isearch('flow') def isearch_q(self): self.isearch('quantity') ''' def ibrowse(self): self._menu_position = [choices, choices['Catalog']] ar = self._current_archive or self._choose_archive(allow_all=False) if ar == -1: print('No archives loaded!') return [] entities = [e for e in self._catalog[ar].entities()] if len(entities) == 0: return lambda: 'No entities found' g = pick_one(entities) return self._prompt_add(self._catalog.ref(ar, g)) ''' def _processes(self): ar = self._current_archive or self._choose_archive(allow_all=False) if ar == -1: print('No archives loaded!') return [] return self._catalog.processes_for(ar) def _flows(self): return self._catalog.flows_for(ar) def _quantities(self): ar = self._current_archive or self._choose_archive(allow_all=False) if ar == -1: print('No archives loaded!') return [] return self._catalog.quantities_for(ar) ''' def inspect(self): sel = pick_list(self.selected) sel.show() while True: print('** Select Inspection **') uchoice = menu_list(*[k for k, v in inspections[sel.entity_type].items() if v != []], go_up=True) if uchoice == -1 or uchoice is None: return True inspections[sel.entity_type][uchoice](self)(sel) def compare(self): sel = pick_by_etype(self.selected) or self.selected def lcia(self, p_ref): self._m.lcia(p_ref) def q_lcia(self, p_ref): q = pick_one(self._catalog[0].lcia_methods()) self._m.show_detailed_lcia(p_ref, quantity=q) def select_exchange(self, p_ref): exch = self._m._filter_exch(p_ref, elem=False) g = pick_one(exch) self.terminate(ExchangeRef(self._catalog, p_ref.index, g)) def originate(self, exch_ref): z = self._catalog.originate(exch_ref, show=False) g = pick_one(z) return self._prompt_add(g) def terminate(self, exch_ref): z = self._catalog.terminate(exch_ref, show=False) g = pick_one(z) return self._prompt_add(g) def source(self, flow_ref): z = self._catalog.source(flow_ref) g = pick_one(z) return self._prompt_add(g) def sink(self, flow_ref): z = self._catalog.sink(flow_ref) g = pick_one(z) return self._prompt_add(g) def factors(self, q_ref): self._flowdb.factors_for_quantity(q_ref.id) def specify_foreground(self): folder = ifinput('Choose foreground: ', self._catalog.fg) self._m.workon(folder) return True def search_flowables(self): regex = input('Enter search term (regex): ') hits = sorted(self._flowdb.flowables.search(regex)) for f in hits[:min([len(hits), 50])]: self._flowdb.friendly_flowable(f) if len(hits) > 50: print('.. %d more results .. ' % (len(hits) - 50)) i = None while i is None: i = input('Pick one (or n to narrow search, x to abandon search):') if i == 'n': r = input('regex: ') narrow = self._flowdb.flowables.search(r) inter = narrow.intersection(hits) if len(inter) == 0: print('No results in intersection.') else: hits = inter i = None elif int(i) in hits: print('Selecting flowable %d: %s' % int(i), self._flowdb.flowables[i]) self._selected_flowable = int(i) elif i != 'x': print('Invalid choice.') i = None return True def browse_compartments(self): comp = pick_compartment(self._flowdb.compartments) if comp is None: return 'Nothing selected' self._selected_compartment = comp return '%s' % comp.to_list() def view_foreground(self): print('Foreground Entities \n\nProcesses:') for i, p in enumerate(self._catalog[0].processes()): print('%4d (%s) %s' % (i, self._catalog.name(0), p)) print('\nFlows:') for i, f in enumerate(self._catalog[0].flows()): print('%4d (%s) %s' % (i, self._catalog.name(0), f)) print('\nQuantities:') for i, q in enumerate(self._catalog[0].quantities()): print('%4d (%s) %s' % (i, self._catalog.name(0), q)) def view_background(self): self._catalog[0].fragments(background=True, all=False) def create_flow(self): name = input('Enter flow name: ') cas = ifinput('Enter CAS number (or none): ', '') print('Choose reference quantity: ') q = pick_one(self._catalog[0].quantities()) print('Choose compartment:') comment = input('Enter comment: ') c = pick_compartment(self._flowdb.compartments) flow = LcFlow.new(name, q, CasNumber=cas, Compartment=c.to_list(), Comment=comment) # flow.add_characterization(q, reference=True) self._catalog[0].add(flow) return flow def edit_flow(self): flow = pick_one(self._catalog[0].flows()) print('Select field to edit:') field = menu_list(*flow.keys()) if field == -1 or field is None: return True new = ifinput('Enter new value for %s: ' % field, flow[field]) flow[field] = new def list_fragments(self): print('Fragments:') for i, f in enumerate(self._catalog[0].fragments()): print('%4d (%s) %s' % (i, self._catalog.name(0), f)) def create_fragment(self): print('Create fragment.') name = input('Name: ') k = cyoa('Reference flow: Use (F)oreground flow or (S)earch for flow?', 'FS', 'F') if k.lower() == 'f': print('Select Reference flow:') flow = pick_one(self._catalog[0].flows()) else: self.isearch('flow')() flow = pick_one([f for f in self.selected if f.entity_type == 'flow']) self._m.add_to_foreground(flow) flow = flow.entity() print('Direction w.r.t. upstream:') direction = menu_list('Input', 'Output') print('interface\nname: %s\nflow: %s\ndirn: %s' % (name, flow, direction)) self._catalog[0].create_fragment(flow, direction, name=name) def add_child_fragment(self): parent = self._selected_fragment k = cyoa('use (N)ew or (E)xisting flow?', 'NE', 'N') if k.lower() == 'e': print('Select Reference flow:') flow = pick_one(self._catalog[0].flows()) if flow is None: print('Canceling child fragment flow') return None else: flow = self.create_flow() direction = menu_list('Input', 'Output') self._catalog[0].add_child_fragment_flow(parent, flow, direction)