def func(self): """Show server time data in a table.""" table1 = EvTable("|wServer time", "", align="l", width=78) table1.add_row("Current uptime", utils.time_format(gametime.uptime(), 3)) table1.add_row("Total runtime", utils.time_format(gametime.runtime(), 2)) table1.add_row( "First start", datetime.datetime.fromtimestamp(gametime.server_epoch())) table1.add_row("Current time", datetime.datetime.now()) table1.reformat_column(0, width=30) table2 = EvTable("|wIn-Game time", "|wReal time x %g" % gametime.TIMEFACTOR, align="l", width=77, border_top=0) epochtxt = "Epoch (%s)" % ("from settings" if settings.TIME_GAME_EPOCH else "server start") table2.add_row(epochtxt, datetime.datetime.fromtimestamp(gametime.game_epoch())) table2.add_row("Total time passed:", utils.time_format(gametime.gametime(), 2)) table2.add_row( "Current time ", datetime.datetime.fromtimestamp(gametime.gametime(absolute=True))) table2.reformat_column(0, width=30) self.caller.msg(unicode(table1) + "\n" + unicode(table2))
def func(self): """Show server time data in a table.""" lat, lon, ele = 33.43, -112.07, 24 here = self.character.location if here: x = float(here.tags.get(category="coordx", default=0)) y = float(here.tags.get(category="coordy", default=0)) # z = here.tags.get(category="coordz") if x and y: lat, lon = float(y/10000), float(x/10000) print('Using location coordinates: {}, {}'.format(lat, lon)) place = astral.LocationInfo(timezone='UTC', latitude=lat, longitude=lon) obsr = astral.Observer(latitude=lat, longitude=lon, elevation=ele) def time_dif(at, when): diff = abs(at - when) return 'now' if diff.total_seconds() < 60 else (utils.time_format(diff.total_seconds(), 2) + (' ago' if at > when else '')) def moon_phase(days): """ Summarize the visible portion, given days into cycle Args: days (int or float): days into current cycle Returns: phase (str): summary of view of visible portion """ phases = ('new', 'waxing crescent', 'First quarter', 'waxing gibbous', 'full', 'waning gibbous', 'last quarter', 'waning crescent') percent = float((float(days) + 0.5) / 29.53) phase = int((percent - int(percent)) * len(phases)) return phases[phase] try: sun = astral.sun.sun(date=datetime.date.today(), observer=obsr) except Exception as e: return else: past = here.tags.get('past', category='realm') moon = astral.moon.phase(date=datetime.date.today()) now = timezone.now() moment = ['dawn', 'sunrise', 'noon', 'sunset', 'dusk'] events = zip([each.capitalize() + ':' for each in moment], [time_dif(now, sun[each]) for each in moment]) table1 = EvTable("|wServer", '|wtime', align='l', width=75) table1.add_row('Current uptime', utils.time_format(gametime.uptime(), 3)) table1.add_row('First start', time_dif(datetime.datetime.now(), datetime.datetime.fromtimestamp(gametime.server_epoch()))) if here.tags.get('past', category='realm'): table1.add_row('Moon phase', moon_phase(moon)) table1.reformat_column(0, width=20) up = self.cmdstring == 'uptime' # User asking for uptime mode self.msg(('Current uptime: ' + utils.time_format(gametime.uptime(), 3)) if up else str(table1)) if past: # Astral events are to be displayed while in past realm table2 = EvTable("|wEvent", "|wTime until", align="l", width=75) for entry in events: table2.add_row(entry[0], entry[1]) table2.reformat_column(0, width=20) self.msg(str(table2) if self.cmdstring == 'events' else ('\n' + str(table2)))
def view_plots_table(self, old=False, only_open_tickets=False, only_recruiting=False): """Returns an EvTable chock full of spicy Plots.""" from evennia.utils.evtable import EvTable qs = (self.filter(resolved=old).exclude( Q(usage=self.model.CRISIS) | Q(parent_plot__isnull=False)).distinct()) if only_open_tickets: from web.helpdesk.models import Ticket qs = qs.filter(tickets__status=Ticket.OPEN_STATUS) if only_recruiting: from .models import PCPlotInvolvement qs = qs.filter( Q(dompc_involvement__activity_status=PCPlotInvolvement.ACTIVE) & Q(dompc_involvement__admin_status__gte=PCPlotInvolvement. RECRUITER) & ~Q(dompc_involvement__recruiter_story="")).distinct() alt_header = "Resolved " if old else "" table = EvTable( "|w#|n", "|w%sPlot (owner)|n" % alt_header, "|wSummary|n", width=78, border="cells", ) for plot in qs: def get_plot_name_and_owner(plotmato): owner = (" (%s)" % plotmato.first_owner) if plotmato.first_owner else "" return "%s%s" % (str(plotmato), owner) def add_subplots_rows(subplot, color_num): sub_name = get_plot_name_and_owner(subplot) table.add_row("|%s35%s|n" % (color_num, subplot.id), sub_name, subplot.headline) color_num += 1 if color_num > 5: color_num = 0 for subplotmato in subplot.subplots.filter(resolved=old): add_subplots_rows(subplotmato, color_num) plot_name = get_plot_name_and_owner(plot) table.add_row(plot.id, plot_name, plot.headline) for subploterino in plot.subplots.filter(resolved=old): add_subplots_rows(subploterino, color_num=0) table.reformat_column(0, width=7) table.reformat_column(1, width=25) table.reformat_column(2, width=46) return table
def list_actions(self): """Lists the actions for the matching queryset""" qs = self.get_queryset_from_switches() table = EvTable("{wID", "{wplayer", "{wtldr", "{wdate", "{wcrisis", width=78, border="cells") for action in qs: if action.unanswered_questions: action_id = "{c*%s{n" % action.id else: action_id = action.id date = action.date_submitted.strftime( "%m/%d") if action.date_submitted else "----" table.add_row(action_id, action.dompc, action.topic, date, action.plot) table.reformat_column(0, width=9) table.reformat_column(1, width=10) table.reformat_column(2, width=37) table.reformat_column(3, width=8) table.reformat_column(4, width=14) arx_more.msg(self.caller, str(table), justify_kwargs=False, pages_by_char=True)
def func(self): """Show server time data in a table.""" table1 = EvTable("|wServer time", "", align="l", width=78) table1.add_row("Current uptime", utils.time_format(gametime.uptime(), 3)) table1.add_row("Total runtime", utils.time_format(gametime.runtime(), 2)) table1.add_row("First start", datetime.datetime.fromtimestamp(gametime.server_epoch())) table1.add_row("Current time", datetime.datetime.now()) table1.reformat_column(0, width=30) table2 = EvTable("|wIn-Game time", "|wReal time x %g" % gametime.TIMEFACTOR, align="l", width=77, border_top=0) epochtxt = "Epoch (%s)" % ("from settings" if settings.TIME_GAME_EPOCH else "server start") table2.add_row(epochtxt, datetime.datetime.fromtimestamp(gametime.game_epoch())) table2.add_row("Total time passed:", utils.time_format(gametime.gametime(), 2)) table2.add_row("Current time ", datetime.datetime.fromtimestamp(gametime.gametime(absolute=True))) table2.reformat_column(0, width=30) self.caller.msg(unicode(table1) + "\n" + unicode(table2))
def list_tasks(self): """List the active tasks.""" obj = self.obj callback_name = self.callback_name handler = self.handler tasks = [(k, v[0], v[1], v[2]) for k, v in handler.db.tasks.items()] if obj: tasks = [task for task in tasks if task[2] is obj] if callback_name: tasks = [task for task in tasks if task[3] == callback_name] tasks.sort() table = EvTable("ID", "Object", "Callback", "In", width=78) table.reformat_column(0, align="r") now = datetime.now() for task_id, future, obj, callback_name in tasks: key = obj.get_display_name(self.caller) delta = time_format((future - now).total_seconds(), 1) table.add_row(task_id, key, callback_name, delta) self.msg(unicode(table))
def list_tasks(self): """List the active tasks.""" obj = self.obj callback_name = self.callback_name handler = self.handler tasks = [(k, v[0], v[1], v[2]) for k, v in handler.db.tasks.items()] if obj: tasks = [task for task in tasks if task[2] is obj] if callback_name: tasks = [task for task in tasks if task[3] == callback_name] tasks.sort() table = EvTable("ID", "Object", "Callback", "In", width=78) table.reformat_column(0, align="r") now = datetime.now() for task_id, future, obj, callback_name in tasks: key = obj.get_display_name(self.caller) delta = time_format((future - now).total_seconds(), 1) table.add_row(task_id, key, callback_name, delta) self.msg(unicode(table))
def list_crises(self): qs = self.viewable_crises resolved = "old" in self.switches qs = qs.filter(usage=Plot.CRISIS, resolved=resolved) table = EvTable("{w#{n", "{wName{n", "{wDesc{n", "{wUpdates On{n", width=78, border="cells") for ob in qs: date = "--" if not ob.end_date else ob.end_date.strftime("%m/%d") table.add_row(ob.id, ob.name, ob.headline, date) table.reformat_column(0, width=7) table.reformat_column(1, width=20) table.reformat_column(2, width=40) table.reformat_column(3, width=11) self.msg(table)
def list_prototypes(caller, key=None, tags=None, show_non_use=False, show_non_edit=True): """ Collate a list of found prototypes based on search criteria and access. Args: caller (Account or Object): The object requesting the list. key (str, optional): Exact or partial prototype key to query for. tags (str or list, optional): Tag key or keys to query for. show_non_use (bool, optional): Show also prototypes the caller may not use. show_non_edit (bool, optional): Show also prototypes the caller may not edit. Returns: table (EvTable or None): An EvTable representation of the prototypes. None if no prototypes were found. """ # this allows us to pass lists of empty strings tags = [tag for tag in make_iter(tags) if tag] # get prototypes for readonly and db-based prototypes prototypes = search_prototype(key, tags) # get use-permissions of readonly attributes (edit is always False) display_tuples = [] for prototype in sorted(prototypes, key=lambda d: d.get('prototype_key', '')): lock_use = caller.locks.check_lockstring( caller, prototype.get('prototype_locks', ''), access_type='spawn', default=True) if not show_non_use and not lock_use: continue if prototype.get('prototype_key', '') in _MODULE_PROTOTYPES: lock_edit = False else: lock_edit = caller.locks.check_lockstring( caller, prototype.get('prototype_locks', ''), access_type='edit', default=True) if not show_non_edit and not lock_edit: continue ptags = [] for ptag in prototype.get('prototype_tags', []): if is_iter(ptag): if len(ptag) > 1: ptags.append("{} (category: {}".format(ptag[0], ptag[1])) else: ptags.append(ptag[0]) else: ptags.append(str(ptag)) display_tuples.append( (prototype.get('prototype_key', '<unset>'), prototype.get('prototype_desc', '<unset>'), "{}/{}".format('Y' if lock_use else 'N', 'Y' if lock_edit else 'N'), ",".join(ptags))) if not display_tuples: return "" table = [] width = 78 for i in range(len(display_tuples[0])): table.append([str(display_tuple[i]) for display_tuple in display_tuples]) table = EvTable("Key", "Desc", "Spawn/Edit", "Tags", table=table, crop=True, width=width) table.reformat_column(0, width=22) table.reformat_column(1, width=29) table.reformat_column(2, width=11, align='c') table.reformat_column(3, width=16) return table
def post_top_prestige(self): """Makes a board post of the top prestige earners this past week""" import random from world.dominion.models import PraiseOrCondemn changes = PraiseOrCondemn.objects.filter(week=self.db.week).exclude( target__organization_owner__secret=True) praises = defaultdict(list) condemns = defaultdict(list) total_values = {} for praise in changes.filter(value__gte=0): praises[praise.target].append(praise) for condemn in changes.filter(value__lt=0): condemns[condemn.target].append(condemn) for change in changes: current = total_values.get(change.target, 0) current += change.value total_values[change.target] = current board = BBoard.objects.get(db_key__iexact=PRESTIGE_BOARD_NAME) def get_total_from_list(entry_list): """Helper function to get total prestige amount from a list""" return sum(praise_ob.value for praise_ob in entry_list) sorted_praises = sorted(praises.items(), key=lambda x: get_total_from_list(x[1]), reverse=True) sorted_praises = sorted_praises[:20] table = EvTable("{wName{n", "{wValue{n", "{wMsg{n", border="cells", width=78) for tup in sorted_praises: praise_messages = [ob.message for ob in tup[1] if ob.message] selected_message = "" if praise_messages: selected_message = random.choice(praise_messages) table.add_row( str(tup[0]).capitalize()[:18], get_total_from_list(tup[1]), selected_message) table.reformat_column(0, width=18) table.reformat_column(1, width=10) table.reformat_column(2, width=50) prestige_msg = "{wMost Praised this week{n".center(72) prestige_msg = "%s\n%s" % (prestige_msg, str(table).lstrip()) prestige_msg += "\n\n" try: # sort by our prestige change amount sorted_changes = sorted(total_values.items(), key=lambda x: abs(x[1]), reverse=True) sorted_changes = sorted_changes[:20] table = EvTable("{wName{n", "{wPrestige Change Amount{n", "{wPrestige Rank{n", border="cells", width=78) rank_order = list( AssetOwner.objects.filter( player__player__roster__roster__name="Active").distinct()) rank_order = sorted(rank_order, key=lambda x: x.prestige, reverse=True) for tup in sorted_changes: # get our prestige ranking compared to others owner = tup[0] try: rank = rank_order.index(owner) + 1 except ValueError: # they rostered mid-week or whatever, skip them continue # get the amount that our prestige has changed. add + for positive amt = tup[1] if amt > 0: amt = "+%s" % amt table.add_row(owner, amt, rank) prestige_msg += "\n\n" prestige_msg += "{wTop Prestige Changes{n".center(72) prestige_msg = "%s\n%s" % (prestige_msg, str(table).lstrip()) except (AttributeError, ValueError, TypeError): import traceback traceback.print_exc() board.bb_post(poster_obj=self, msg=prestige_msg, subject="Weekly Praises/Condemns", poster_name="Prestige") inform_staff("Praises/condemns tally complete. Posted on %s." % board)
def func(self): """Show server time data in a table.""" lat, lon, ele = 33.43, -112.07, 24 here = self.character.location if here: x = float(here.tags.get(category="coordx", default=0)) y = float(here.tags.get(category="coordy", default=0)) # z = here.tags.get(category="coordz") if x and y: lat, lon = float(y/10000), float(x/10000) print('Using location coordinates: {}, {}'.format(lat, lon)) place = Astral.Location(info=('', '', lat, lon, 'UTC', ele)) place.solar_depression = 'civil' def time_dif(at, when): diff = abs(at - when) return 'now' if diff.total_seconds < 60 else (utils.time_format(diff.total_seconds(), 2) + (' ago' if at > when else '')) def moon_phase(days): """ Summarize the visible portion, given days into cycle Args: days (int or float): days into current cycle Returns: phase (str): summary of view of visible portion """ phases = ('new', 'waxing crescent', 'First quarter', 'waxing gibbous', 'full', 'waning gibbous', 'last quarter', 'waning crescent') percent = float((float(days) + 0.5) / 29.53) phase = int((percent - int(percent)) * len(phases)) return phases[phase] try: sun = place.sun(date=datetime.date.today(), local=True) except Exception: return else: past = here.tags.get('past', category='realm') moon = place.moon_phase(date=datetime.date.today()) now = timezone.now() moment = ['dawn', 'sunrise', 'noon', 'sunset', 'dusk'] events = zip([each.capitalize() + ':' for each in moment], [time_dif(now, sun[each]) for each in moment]) table1 = EvTable("|wServer", '|wtime', align='l', width=75) table1.add_row('Current uptime', utils.time_format(gametime.uptime(), 3)) table1.add_row('First start', time_dif(datetime.datetime.now(), datetime.datetime.fromtimestamp(gametime.server_epoch()))) if here.tags.get('past', category='realm'): table1.add_row('Moon phase', moon_phase(moon)) table1.reformat_column(0, width=20) if past: table2 = EvTable("|wEvent", "|wTime until", align="l", width=75) for entry in events: table2.add_row(entry[0], entry[1]) table2.reformat_column(0, width=20) if self.cmdstring == 'uptime': self.msg('Current uptime: ' + utils.time_format(gametime.uptime(), 3)) else: self.msg(unicode(table1)) if past: if self.cmdstring == 'events': self.msg(unicode(table2)) else: self.msg("\n" + unicode(table2))
def accept_callback(self): """Accept a callback.""" obj = self.obj callback_name = self.callback_name parameters = self.parameters # If no object, display the list of callbacks to be checked if obj is None: table = EvTable("ID", "Type", "Object", "Name", "Updated by", "On", width=78) table.reformat_column(0, align="r") now = datetime.now() for obj, name, number in self.handler.db.to_valid: callbacks = self.handler.get_callbacks(obj).get(name) if callbacks is None: continue try: callback = callbacks[number] except IndexError: continue type_name = obj.typeclass_path.split(".")[-1] by = callback.get("updated_by") by = by.key if by else "|gUnknown|n" updated_on = callback.get("updated_on") if updated_on is None: updated_on = callback.get("created_on") if updated_on: updated_on = "{} ago".format( time_format((now - updated_on).total_seconds(), 4).capitalize()) else: updated_on = "|gUnknown|n" table.add_row(obj.id, type_name, obj, name, by, updated_on) self.msg(unicode(table)) return # An object was specified callbacks = self.handler.get_callbacks(obj) types = self.handler.get_events(obj) # If no callback name is specified, display the list of callbacks if not callback_name: self.list_callbacks() return # Check that the callback exists if not callback_name in callbacks: self.msg("The callback name {} can't be found in {}.".format( callback_name, obj)) return if not parameters: self.msg( "Which callback do you wish to accept? Specify a number.") self.list_callbacks() return # Check that the parameter points to an existing callback try: number = int(parameters) - 1 assert number >= 0 callback = callbacks[callback_name][number] except (ValueError, AssertionError, IndexError): self.msg("The callback {} {} cannot be found in {}.".format( callback_name, parameters, obj)) return # Accept the callback if callback["valid"]: self.msg("This callback has already been accepted.") else: self.handler.accept_callback(obj, callback_name, number) self.msg("The callback {} {} of {} has been accepted.".format( callback_name, parameters, obj))
def list_callbacks(self): """Display the list of callbacks connected to the object.""" obj = self.obj callback_name = self.callback_name parameters = self.parameters callbacks = self.handler.get_callbacks(obj) types = self.handler.get_events(obj) if callback_name: # Check that the callback name can be found in this object created = callbacks.get(callback_name) if created is None: self.msg("No callback {} has been set on {}.".format( callback_name, obj)) return if parameters: # Check that the parameter points to an existing callback try: number = int(parameters) - 1 assert number >= 0 callback = callbacks[callback_name][number] except (ValueError, AssertionError, IndexError): self.msg( "The callback {} {} cannot be found in {}.".format( callback_name, parameters, obj)) return # Display the callback's details author = callback.get("author") author = author.key if author else "|gUnknown|n" updated_by = callback.get("updated_by") updated_by = updated_by.key if updated_by else "|gUnknown|n" created_on = callback.get("created_on") created_on = created_on.strftime( "%Y-%m-%d %H:%M:%S") if created_on else "|gUnknown|n" updated_on = callback.get("updated_on") updated_on = updated_on.strftime( "%Y-%m-%d %H:%M:%S") if updated_on else "|gUnknown|n" msg = "Callback {} {} of {}:".format(callback_name, parameters, obj) msg += "\nCreated by {} on {}.".format(author, created_on) msg += "\nUpdated by {} on {}".format(updated_by, updated_on) if self.is_validator: if callback.get("valid"): msg += "\nThis callback is |rconnected|n and active." else: msg += "\nThis callback |rhasn't been|n accepted yet." msg += "\nCallback code:\n" msg += raw(callback["code"]) self.msg(msg) return # No parameter has been specified, display the table of callbacks cols = ["Number", "Author", "Updated", "Param"] if self.is_validator: cols.append("Valid") table = EvTable(*cols, width=78) table.reformat_column(0, align="r") now = datetime.now() for i, callback in enumerate(created): author = callback.get("author") author = author.key if author else "|gUnknown|n" updated_on = callback.get("updated_on") if updated_on is None: updated_on = callback.get("created_on") if updated_on: updated_on = "{} ago".format( time_format((now - updated_on).total_seconds(), 4).capitalize()) else: updated_on = "|gUnknown|n" parameters = callback.get("parameters", "") row = [str(i + 1), author, updated_on, parameters] if self.is_validator: row.append("Yes" if callback.get("valid") else "No") table.add_row(*row) self.msg(unicode(table)) else: names = list(set(list(types.keys()) + list(callbacks.keys()))) table = EvTable("Callback name", "Number", "Description", valign="t", width=78) table.reformat_column(0, width=20) table.reformat_column(1, width=10, align="r") table.reformat_column(2, width=48) for name in sorted(names): number = len(callbacks.get(name, [])) lines = sum( len(e["code"].splitlines()) for e in callbacks.get(name, [])) no = "{} ({})".format(number, lines) description = types.get(name, (None, "Chained event."))[1] description = description.strip("\n").splitlines()[0] table.add_row(name, no, description) self.msg(unicode(table))
def accept_callback(self): """Accept a callback.""" obj = self.obj callback_name = self.callback_name parameters = self.parameters # If no object, display the list of callbacks to be checked if obj is None: table = EvTable("ID", "Type", "Object", "Name", "Updated by", "On", width=78) table.reformat_column(0, align="r") now = datetime.now() for obj, name, number in self.handler.db.to_valid: callbacks = self.handler.get_callbacks(obj).get(name) if callbacks is None: continue try: callback = callbacks[number] except IndexError: continue type_name = obj.typeclass_path.split(".")[-1] by = callback.get("updated_by") by = by.key if by else "|gUnknown|n" updated_on = callback.get("updated_on") if updated_on is None: updated_on = callback.get("created_on") if updated_on: updated_on = "{} ago".format(time_format( (now - updated_on).total_seconds(), 4).capitalize()) else: updated_on = "|gUnknown|n" table.add_row(obj.id, type_name, obj, name, by, updated_on) self.msg(unicode(table)) return # An object was specified callbacks = self.handler.get_callbacks(obj) types = self.handler.get_events(obj) # If no callback name is specified, display the list of callbacks if not callback_name: self.list_callbacks() return # Check that the callback exists if callback_name not in callbacks: self.msg("The callback name {} can't be found in {}.".format( callback_name, obj)) return if not parameters: self.msg("Which callback do you wish to accept? Specify a number.") self.list_callbacks() return # Check that the parameter points to an existing callback try: number = int(parameters) - 1 assert number >= 0 callback = callbacks[callback_name][number] except (ValueError, AssertionError, IndexError): self.msg("The callback {} {} cannot be found in {}.".format( callback_name, parameters, obj)) return # Accept the callback if callback["valid"]: self.msg("This callback has already been accepted.") else: self.handler.accept_callback(obj, callback_name, number) self.msg("The callback {} {} of {} has been accepted.".format( callback_name, parameters, obj))
def list_callbacks(self): """Display the list of callbacks connected to the object.""" obj = self.obj callback_name = self.callback_name parameters = self.parameters callbacks = self.handler.get_callbacks(obj) types = self.handler.get_events(obj) if callback_name: # Check that the callback name can be found in this object created = callbacks.get(callback_name) if created is None: self.msg("No callback {} has been set on {}.".format(callback_name, obj)) return if parameters: # Check that the parameter points to an existing callback try: number = int(parameters) - 1 assert number >= 0 callback = callbacks[callback_name][number] except (ValueError, AssertionError, IndexError): self.msg("The callback {} {} cannot be found in {}.".format( callback_name, parameters, obj)) return # Display the callback's details author = callback.get("author") author = author.key if author else "|gUnknown|n" updated_by = callback.get("updated_by") updated_by = updated_by.key if updated_by else "|gUnknown|n" created_on = callback.get("created_on") created_on = created_on.strftime("%Y-%m-%d %H:%M:%S") if created_on else "|gUnknown|n" updated_on = callback.get("updated_on") updated_on = updated_on.strftime("%Y-%m-%d %H:%M:%S") if updated_on else "|gUnknown|n" msg = "Callback {} {} of {}:".format(callback_name, parameters, obj) msg += "\nCreated by {} on {}.".format(author, created_on) msg += "\nUpdated by {} on {}".format(updated_by, updated_on) if self.is_validator: if callback.get("valid"): msg += "\nThis callback is |rconnected|n and active." else: msg += "\nThis callback |rhasn't been|n accepted yet." msg += "\nCallback code:\n" msg += raw(callback["code"]) self.msg(msg) return # No parameter has been specified, display the table of callbacks cols = ["Number", "Author", "Updated", "Param"] if self.is_validator: cols.append("Valid") table = EvTable(*cols, width=78) table.reformat_column(0, align="r") now = datetime.now() for i, callback in enumerate(created): author = callback.get("author") author = author.key if author else "|gUnknown|n" updated_on = callback.get("updated_on") if updated_on is None: updated_on = callback.get("created_on") if updated_on: updated_on = "{} ago".format(time_format( (now - updated_on).total_seconds(), 4).capitalize()) else: updated_on = "|gUnknown|n" parameters = callback.get("parameters", "") row = [str(i + 1), author, updated_on, parameters] if self.is_validator: row.append("Yes" if callback.get("valid") else "No") table.add_row(*row) self.msg(unicode(table)) else: names = list(set(list(types.keys()) + list(callbacks.keys()))) table = EvTable("Callback name", "Number", "Description", valign="t", width=78) table.reformat_column(0, width=20) table.reformat_column(1, width=10, align="r") table.reformat_column(2, width=48) for name in sorted(names): number = len(callbacks.get(name, [])) lines = sum(len(e["code"].splitlines()) for e in callbacks.get(name, [])) no = "{} ({})".format(number, lines) description = types.get(name, (None, "Chained event."))[1] description = description.strip("\n").splitlines()[0] table.add_row(name, no, description) self.msg(unicode(table))