commit a0a42c69c163e3f8143bb4b311b8526ae9e88891 Author: Damian Johnson atagar@torproject.org Date: Wed Jan 2 20:45:44 2013 -0800
Using stem's str_tools util
Stem's str_tools is the subset of our uiTools that will commonly be useful to other users. Making use of its version of the utils. --- src/cli/configPanel.py | 6 +- src/cli/connections/connEntry.py | 4 +- src/cli/graphing/bandwidthStats.py | 28 +++--- src/cli/graphing/graphPanel.py | 4 +- src/cli/graphing/resourceStats.py | 8 +- src/cli/headerPanel.py | 10 +- src/cli/menu/actions.py | 10 +- src/util/sysTools.py | 8 +- src/util/torConfig.py | 7 +- src/util/torTools.py | 6 +- src/util/uiTools.py | 201 ------------------------------------ 11 files changed, 46 insertions(+), 246 deletions(-)
diff --git a/src/cli/configPanel.py b/src/cli/configPanel.py index 38df235..32233f2 100644 --- a/src/cli/configPanel.py +++ b/src/cli/configPanel.py @@ -11,7 +11,7 @@ import popups
from util import panel, sysTools, torConfig, torTools, uiTools
-from stem.util import conf, enum +from stem.util import conf, enum, str_tools
# TODO: The arm use cases are incomplete since they currently can't be # modified, have their descriptions fetched, or even get a complete listing @@ -174,9 +174,9 @@ class ConfigEntry(): elif self.get(Field.TYPE) == "Boolean" and confValue in ("0", "1"): confValue = "False" if confValue == "0" else "True" elif self.get(Field.TYPE) == "DataSize" and confValue.isdigit(): - confValue = uiTools.getSizeLabel(int(confValue)) + confValue = str_tools.get_size_label(int(confValue)) elif self.get(Field.TYPE) == "TimeInterval" and confValue.isdigit(): - confValue = uiTools.getTimeLabel(int(confValue), isLong = True) + confValue = str_tools.get_time_label(int(confValue), is_long = True)
return confValue
diff --git a/src/cli/connections/connEntry.py b/src/cli/connections/connEntry.py index 73c3ece..bec5aa9 100644 --- a/src/cli/connections/connEntry.py +++ b/src/cli/connections/connEntry.py @@ -9,7 +9,7 @@ import curses from util import connections, torTools, uiTools from cli.connections import entries
-from stem.util import conf, enum +from stem.util import conf, enum, str_tools
# Connection Categories: # Inbound Relay connection, coming to us. @@ -295,7 +295,7 @@ class ConnectionLine(entries.ConnectionPanelLine): timePrefix = "+" if self.isInitialConnection else " " else: timePrefix = ""
- timeLabel = timePrefix + "%5s" % uiTools.getTimeLabel(currentTime - self.startTime, 1) + timeLabel = timePrefix + "%5s" % str_tools.get_time_label(currentTime - self.startTime, 1) myListing[2] = (timeLabel, myListing[2][1])
return myListing diff --git a/src/cli/graphing/bandwidthStats.py b/src/cli/graphing/bandwidthStats.py index 2268f63..8a75fff 100644 --- a/src/cli/graphing/bandwidthStats.py +++ b/src/cli/graphing/bandwidthStats.py @@ -11,7 +11,7 @@ import cli.controller from cli.graphing import graphPanel from util import sysTools, torTools, uiTools
-from stem.util import conf, log +from stem.util import conf, log, str_tools
def conf_handler(key, value): if key == "features.graph.bw.accounting.rate": @@ -228,7 +228,7 @@ class BandwidthStats(graphPanel.GraphStats):
msg = PREPOPULATE_SUCCESS_MSG missingSec = time.time() - min(lastReadTime, lastWriteTime) - if missingSec: msg += " (%s is missing)" % uiTools.getTimeLabel(missingSec, 0, True) + if missingSec: msg += " (%s is missing)" % str_tools.get_time_label(missingSec, 0, True) log.notice(msg)
return True @@ -310,7 +310,7 @@ class BandwidthStats(graphPanel.GraphStats): stats[1] = "- %s" % self._getAvgLabel(isPrimary) stats[2] = ", %s" % self._getTotalLabel(isPrimary)
- stats[0] = "%-14s" % ("%s/sec" % uiTools.getSizeLabel((self.lastPrimary if isPrimary else self.lastSecondary) * 1024, 1, False, CONFIG["features.graph.bw.transferInBytes"])) + stats[0] = "%-14s" % ("%s/sec" % str_tools.get_size_label((self.lastPrimary if isPrimary else self.lastSecondary) * 1024, 1, False, CONFIG["features.graph.bw.transferInBytes"]))
# drops label's components if there's not enough space labeling = graphType + " (" + "".join(stats).strip() + "):" @@ -346,8 +346,8 @@ class BandwidthStats(graphPanel.GraphStats): labelInBytes = CONFIG["features.graph.bw.transferInBytes"]
if bwRate and bwBurst: - bwRateLabel = uiTools.getSizeLabel(bwRate, 1, False, labelInBytes) - bwBurstLabel = uiTools.getSizeLabel(bwBurst, 1, False, labelInBytes) + bwRateLabel = str_tools.get_size_label(bwRate, 1, False, labelInBytes) + bwBurstLabel = str_tools.get_size_label(bwBurst, 1, False, labelInBytes)
# if both are using rounded values then strip off the ".0" decimal if ".0" in bwRateLabel and ".0" in bwBurstLabel: @@ -361,21 +361,21 @@ class BandwidthStats(graphPanel.GraphStats): # available or if the measured bandwidth is the observed (this happens # if there isn't yet enough bandwidth measurements). if bwObserved and (not bwMeasured or bwMeasured == bwObserved): - stats.append("observed: %s/s" % uiTools.getSizeLabel(bwObserved, 1, False, labelInBytes)) + stats.append("observed: %s/s" % str_tools.get_size_label(bwObserved, 1, False, labelInBytes)) elif bwMeasured: - stats.append("measured: %s/s" % uiTools.getSizeLabel(bwMeasured, 1, False, labelInBytes)) + stats.append("measured: %s/s" % str_tools.get_size_label(bwMeasured, 1, False, labelInBytes))
self._titleStats = stats
def _getAvgLabel(self, isPrimary): total = self.primaryTotal if isPrimary else self.secondaryTotal total += self.prepopulatePrimaryTotal if isPrimary else self.prepopulateSecondaryTotal - return "avg: %s/sec" % uiTools.getSizeLabel((total / max(1, self.tick + self.prepopulateTicks)) * 1024, 1, False, CONFIG["features.graph.bw.transferInBytes"]) + return "avg: %s/sec" % str_tools.get_size_label((total / max(1, self.tick + self.prepopulateTicks)) * 1024, 1, False, CONFIG["features.graph.bw.transferInBytes"])
def _getTotalLabel(self, isPrimary): total = self.primaryTotal if isPrimary else self.secondaryTotal total += self.initialPrimaryTotal if isPrimary else self.initialSecondaryTotal - return "total: %s" % uiTools.getSizeLabel(total * 1024, 1) + return "total: %s" % str_tools.get_size_label(total * 1024, 1)
def _updateAccountingInfo(self): """ @@ -398,7 +398,7 @@ class BandwidthStats(graphPanel.GraphStats):
sec = time.mktime(time.strptime(endInterval, "%Y-%m-%d %H:%M:%S")) - time.time() - tz_offset if CONFIG["features.graph.bw.accounting.isTimeLong"]: - queried["resetTime"] = ", ".join(uiTools.getTimeLabels(sec, True)) + queried["resetTime"] = ", ".join(str_tools.get_time_labels(sec, True)) else: days = sec / 86400 sec %= 86400 @@ -417,10 +417,10 @@ class BandwidthStats(graphPanel.GraphStats): read, written = int(usedComp[0]), int(usedComp[1]) readLeft, writtenLeft = int(leftComp[0]), int(leftComp[1])
- queried["read"] = uiTools.getSizeLabel(read) - queried["written"] = uiTools.getSizeLabel(written) - queried["readLimit"] = uiTools.getSizeLabel(read + readLeft) - queried["writtenLimit"] = uiTools.getSizeLabel(written + writtenLeft) + queried["read"] = str_tools.get_size_label(read) + queried["written"] = str_tools.get_size_label(written) + queried["readLimit"] = str_tools.get_size_label(read + readLeft) + queried["writtenLimit"] = str_tools.get_size_label(written + writtenLeft)
self.accountingInfo = queried self.accountingLastUpdated = time.time() diff --git a/src/cli/graphing/graphPanel.py b/src/cli/graphing/graphPanel.py index b989ef5..a0a348a 100644 --- a/src/cli/graphing/graphPanel.py +++ b/src/cli/graphing/graphPanel.py @@ -26,7 +26,7 @@ import stem.control
from util import panel, torTools, uiTools
-from stem.util import conf, enum +from stem.util import conf, enum, str_tools
# time intervals at which graphs can be updated UPDATE_INTERVALS = [("each second", 1), ("5 seconds", 5), ("30 seconds", 30), @@ -464,7 +464,7 @@ class GraphPanel(panel.Panel): unitsLabel, decimalPrecision = None, 0 for i in range((graphCol - 4) / intervalSpacing): loc = (i + 1) * intervalSpacing - timeLabel = uiTools.getTimeLabel(loc * intervalSec, decimalPrecision) + timeLabel = str_tools.get_time_label(loc * intervalSec, decimalPrecision)
if not unitsLabel: unitsLabel = timeLabel[-1] elif unitsLabel != timeLabel[-1]: diff --git a/src/cli/graphing/resourceStats.py b/src/cli/graphing/resourceStats.py index e028874..d9c15b5 100644 --- a/src/cli/graphing/resourceStats.py +++ b/src/cli/graphing/resourceStats.py @@ -3,7 +3,9 @@ Tracks the system resource usage (cpu and memory) of the tor process. """
from cli.graphing import graphPanel -from util import sysTools, torTools, uiTools +from util import sysTools, torTools + +from stem.util import str_tools
class ResourceStats(graphPanel.GraphStats): """ @@ -29,8 +31,8 @@ class ResourceStats(graphPanel.GraphStats): return "CPU (%0.1f%%, avg: %0.1f%%):" % (lastAmount, avg) else: # memory sizes are converted from MB to B before generating labels - usageLabel = uiTools.getSizeLabel(lastAmount * 1048576, 1) - avgLabel = uiTools.getSizeLabel(avg * 1048576, 1) + usageLabel = str_tools.get_size_label(lastAmount * 1048576, 1) + avgLabel = str_tools.get_size_label(avg * 1048576, 1) return "Memory (%s, avg: %s):" % (usageLabel, avgLabel)
def eventTick(self): diff --git a/src/cli/headerPanel.py b/src/cli/headerPanel.py index 09d2ada..29d5f74 100644 --- a/src/cli/headerPanel.py +++ b/src/cli/headerPanel.py @@ -23,7 +23,7 @@ import stem import stem.connection
from stem.control import Controller -from stem.util import conf +from stem.util import conf, str_tools
import starter import cli.popups @@ -31,7 +31,7 @@ import cli.controller
from util import panel, sysTools, torTools, uiTools
-from stem.util import log +from stem.util import log, str_tools
# minimum width for which panel attempts to double up contents (two columns to # better use screen real estate) @@ -262,16 +262,16 @@ class HeaderPanel(panel.Panel, threading.Thread):
# Line 3 / Line 1 Right (system usage info) y, x = (0, leftWidth) if isWide else (2, 0) - if self.vals["stat/rss"] != "0": memoryLabel = uiTools.getSizeLabel(int(self.vals["stat/rss"])) + if self.vals["stat/rss"] != "0": memoryLabel = str_tools.get_size_label(int(self.vals["stat/rss"])) else: memoryLabel = "0"
uptimeLabel = "" if self.vals["tor/startTime"]: if self.isPaused() or not self._isTorConnected: # freeze the uptime when paused or the tor process is stopped - uptimeLabel = uiTools.getShortTimeLabel(self.getPauseTime() - self.vals["tor/startTime"]) + uptimeLabel = str_tools.get_short_time_label(self.getPauseTime() - self.vals["tor/startTime"]) else: - uptimeLabel = uiTools.getShortTimeLabel(time.time() - self.vals["tor/startTime"]) + uptimeLabel = str_tools.get_short_time_label(time.time() - self.vals["tor/startTime"])
sysFields = ((0, "cpu: %s%% tor, %s%% arm" % (self.vals["stat/%torCpu"], self.vals["stat/%armCpu"])), (27, "mem: %s (%s%%)" % (memoryLabel, self.vals["stat/%mem"])), diff --git a/src/cli/menu/actions.py b/src/cli/menu/actions.py index b1371c4..3cf7eb6 100644 --- a/src/cli/menu/actions.py +++ b/src/cli/menu/actions.py @@ -11,6 +11,8 @@ import cli.graphing.graphPanel
from util import connections, torTools, uiTools
+from stem.util import str_tools + def makeMenu(): """ Constructs the base menu and all of its contents. @@ -84,7 +86,7 @@ def makeViewMenu():
for i in range(control.getPageCount()): pagePanels = control.getDisplayPanels(pageNumber = i, includeSticky = False) - label = " / ".join([uiTools.camelCase(panel.getName()) for panel in pagePanels]) + label = " / ".join([str_tools.camel_case(panel.getName()) for panel in pagePanels])
viewMenu.add(cli.menu.item.SelectionMenuItem(label, pageGroup, i))
@@ -95,7 +97,7 @@ def makeViewMenu(): colorMenu.add(cli.menu.item.SelectionMenuItem("All", colorGroup, None))
for color in uiTools.COLOR_LIST: - colorMenu.add(cli.menu.item.SelectionMenuItem(uiTools.camelCase(color), colorGroup, color)) + colorMenu.add(cli.menu.item.SelectionMenuItem(str_tools.camel_case(color), colorGroup, color))
viewMenu.add(colorMenu)
@@ -135,7 +137,7 @@ def makeGraphMenu(graphPanel): availableStats.sort()
for statKey in ["None"] + availableStats: - label = uiTools.camelCase(statKey, divider = " ") + label = str_tools.camel_case(statKey, divider = " ") statKey = None if statKey == "None" else statKey graphMenu.add(cli.menu.item.SelectionMenuItem(label, statGroup, statKey))
@@ -148,7 +150,7 @@ def makeGraphMenu(graphPanel):
for i in range(len(cli.graphing.graphPanel.UPDATE_INTERVALS)): label = cli.graphing.graphPanel.UPDATE_INTERVALS[i][0] - label = uiTools.camelCase(label, divider = " ") + label = str_tools.camel_case(label, divider = " ") intervalMenu.add(cli.menu.item.SelectionMenuItem(label, intervalGroup, i))
graphMenu.add(intervalMenu) diff --git a/src/util/sysTools.py b/src/util/sysTools.py index 2be73fd..8078c1c 100644 --- a/src/util/sysTools.py +++ b/src/util/sysTools.py @@ -6,9 +6,7 @@ import os import time import threading
-from util import uiTools - -from stem.util import conf, log, proc +from stem.util import conf, log, proc, str_tools
# Mapping of commands to if they're available or not. This isn't always # reliable, failing for some special commands. For these the cache is @@ -499,8 +497,8 @@ class ResourceTracker(threading.Thread):
if len(stats) == 4: try: - totalCpuTime = uiTools.parseShortTimeLabel(stats[0]) - uptime = uiTools.parseShortTimeLabel(stats[1]) + totalCpuTime = str_tools.parse_short_time_label(stats[0]) + uptime = str_tools.parse_short_time_label(stats[1]) cpuDelta = totalCpuTime - self._lastCpuTotal newValues["cpuSampling"] = cpuDelta / timeSinceReset newValues["cpuAvg"] = totalCpuTime / uptime diff --git a/src/util/torConfig.py b/src/util/torConfig.py index c9f32f6..57a9d05 100644 --- a/src/util/torConfig.py +++ b/src/util/torConfig.py @@ -11,8 +11,7 @@ import stem.version
from util import sysTools, torTools, uiTools
-from stem.util import conf, enum, log - +from stem.util import conf, enum, log, str_tools
def conf_handler(key, value): if key == "config.important": @@ -594,9 +593,9 @@ def validate(contents = None): # converts corrections to reader friedly size values displayValues = torValues if valueType == ValueType.SIZE: - displayValues = [uiTools.getSizeLabel(int(val)) for val in torValues] + displayValues = [str_tools.get_size_label(int(val)) for val in torValues] elif valueType == ValueType.TIME: - displayValues = [uiTools.getTimeLabel(int(val)) for val in torValues] + displayValues = [str_tools.get_time_label(int(val)) for val in torValues]
issuesFound.append((lineNumber, ValidationError.MISMATCH, ", ".join(displayValues)))
diff --git a/src/util/torTools.py b/src/util/torTools.py index bce3481..73121c5 100644 --- a/src/util/torTools.py +++ b/src/util/torTools.py @@ -16,9 +16,9 @@ import stem import stem.control import stem.descriptor
-from util import connections, sysTools, uiTools +from util import connections, sysTools
-from stem.util import conf, enum, log, proc +from stem.util import conf, enum, log, proc, str_tools
# enums for tor's controller state: # INIT - attached to a new controller @@ -1721,7 +1721,7 @@ class Controller:
if psCall and len(psCall) >= 2: etimeEntry = psCall[1].strip() - result = time.time() - uiTools.parseShortTimeLabel(etimeEntry) + result = time.time() - str_tools.parse_short_time_label(etimeEntry) except: pass elif key == "authorities": # There's two configuration options that can overwrite the default diff --git a/src/util/uiTools.py b/src/util/uiTools.py index 2091197..d93af73 100644 --- a/src/util/uiTools.py +++ b/src/util/uiTools.py @@ -27,16 +27,6 @@ COLOR_IS_SUPPORTED = None COLOR_ATTR_INITIALIZED = False COLOR_ATTR = dict([(color, 0) for color in COLOR_LIST])
-# value tuples for label conversions (bits / bytes / seconds, short label, long label) -SIZE_UNITS_BITS = [(140737488355328.0, " Pb", " Petabit"), (137438953472.0, " Tb", " Terabit"), - (134217728.0, " Gb", " Gigabit"), (131072.0, " Mb", " Megabit"), - (128.0, " Kb", " Kilobit"), (0.125, " b", " Bit")] -SIZE_UNITS_BYTES = [(1125899906842624.0, " PB", " Petabyte"), (1099511627776.0, " TB", " Terabyte"), - (1073741824.0, " GB", " Gigabyte"), (1048576.0, " MB", " Megabyte"), - (1024.0, " KB", " Kilobyte"), (1.0, " B", " Byte")] -TIME_UNITS = [(86400.0, "d", " day"), (3600.0, "h", " hour"), - (60.0, "m", " minute"), (1.0, "s", " second")] - Ending = enum.Enum("ELLIPSE", "HYPHEN") SCROLL_KEYS = (curses.KEY_UP, curses.KEY_DOWN, curses.KEY_PPAGE, curses.KEY_NPAGE, curses.KEY_HOME, curses.KEY_END)
@@ -294,26 +284,6 @@ def padStr(msg, size, cropExtra = False): if cropExtra: msg = msg[:size] return ("%%-%is" % size) % msg
-def camelCase(label, divider = "_", joiner = " "): - """ - Converts the given string to camel case, ie: - >>> camelCase("I_LIKE_PEPPERJACK!") - 'I Like Pepperjack!' - - Arguments: - label - input string to be converted - divider - character to be used for word breaks - joiner - character used to fill between word breaks - """ - - words = [] - for entry in label.split(divider): - if len(entry) == 0: words.append("") - elif len(entry) == 1: words.append(entry.upper()) - else: words.append(entry[0].upper() + entry[1:].lower()) - - return joiner.join(words) - def drawBox(panel, top, left, width, height, attr=curses.A_NORMAL): """ Draws a box in the panel with the given bounds. @@ -395,137 +365,6 @@ def getScrollPosition(key, position, pageHeight, contentHeight, isCursor = False return max(0, min(position + shift, maxLoc)) else: return position
-def getSizeLabel(bytes, decimal = 0, isLong = False, isBytes=True): - """ - Converts byte count into label in its most significant units, for instance - 7500 bytes would return "7 KB". If the isLong option is used this expands - unit labels to be the properly pluralized full word (for instance 'Kilobytes' - rather than 'KB'). Units go up through PB. - - Example Usage: - getSizeLabel(2000000) = '1 MB' - getSizeLabel(1050, 2) = '1.02 KB' - getSizeLabel(1050, 3, True) = '1.025 Kilobytes' - - Arguments: - bytes - source number of bytes for conversion - decimal - number of decimal digits to be included - isLong - expands units label - isBytes - provides units in bytes if true, bits otherwise - """ - - if isBytes: return _getLabel(SIZE_UNITS_BYTES, bytes, decimal, isLong) - else: return _getLabel(SIZE_UNITS_BITS, bytes, decimal, isLong) - -def getTimeLabel(seconds, decimal = 0, isLong = False): - """ - Converts seconds into a time label truncated to its most significant units, - for instance 7500 seconds would return "2h". Units go up through days. - - This defaults to presenting single character labels, but if the isLong option - is used this expands labels to be the full word (space included and properly - pluralized). For instance, "4h" would be "4 hours" and "1m" would become - "1 minute". - - Example Usage: - getTimeLabel(10000) = '2h' - getTimeLabel(61, 1, True) = '1.0 minute' - getTimeLabel(61, 2, True) = '1.01 minutes' - - Arguments: - seconds - source number of seconds for conversion - decimal - number of decimal digits to be included - isLong - expands units label - """ - - return _getLabel(TIME_UNITS, seconds, decimal, isLong) - -def getTimeLabels(seconds, isLong = False): - """ - Provides a list containing label conversions for each time unit, starting - with its most significant units on down. Any counts that evaluate to zero are - omitted. - - Example Usage: - getTimeLabels(400) = ['6m', '40s'] - getTimeLabels(3640, True) = ['1 hour', '40 seconds'] - - Arguments: - seconds - source number of seconds for conversion - isLong - expands units label - """ - - timeLabels = [] - - for countPerUnit, _, _ in TIME_UNITS: - if seconds >= countPerUnit: - timeLabels.append(_getLabel(TIME_UNITS, seconds, 0, isLong)) - seconds %= countPerUnit - - return timeLabels - -def getShortTimeLabel(seconds): - """ - Provides a time in the following format: - [[dd-]hh:]mm:ss - - Arguments: - seconds - source number of seconds for conversion - """ - - timeComp = {} - - for amount, _, label in TIME_UNITS: - count = int(seconds / amount) - seconds %= amount - timeComp[label.strip()] = count - - labelPrefix = "" - if timeComp["day"]: - labelPrefix = "%i-%02i:" % (timeComp["day"], timeComp["hour"]) - elif timeComp["hour"]: - labelPrefix = "%02i:" % timeComp["hour"] - - return "%s%02i:%02i" % (labelPrefix, timeComp["minute"], timeComp["second"]) - -def parseShortTimeLabel(timeEntry): - """ - Provides the number of seconds corresponding to the formatting used for the - cputime and etime fields of ps: - [[dd-]hh:]mm:ss or mm:ss.ss - - If the input entry is malformed then this raises a ValueError. - - Arguments: - timeEntry - formatting ps time entry - """ - - days, hours, minutes, seconds = 0, 0, 0, 0 - errorMsg = "invalidly formatted ps time entry: %s" % timeEntry - - dateDivider = timeEntry.find("-") - if dateDivider != -1: - days = int(timeEntry[:dateDivider]) - timeEntry = timeEntry[dateDivider+1:] - - timeComp = timeEntry.split(":") - if len(timeComp) == 3: - hours, minutes, seconds = timeComp - elif len(timeComp) == 2: - minutes, seconds = timeComp - seconds = round(float(seconds)) - else: - raise ValueError(errorMsg) - - try: - timeSum = int(seconds) - timeSum += int(minutes) * 60 - timeSum += int(hours) * 3600 - timeSum += int(days) * 86400 - return timeSum - except ValueError: - raise ValueError(errorMsg) - class Scroller: """ Tracks the scrolling position when there might be a visible cursor. This @@ -616,46 +455,6 @@ class Scroller: return True else: return False
-def _getLabel(units, count, decimal, isLong): - """ - Provides label corresponding to units of the highest significance in the - provided set. This rounds down (ie, integer truncation after visible units). - - Arguments: - units - type of units to be used for conversion, a tuple containing - (countPerUnit, shortLabel, longLabel) - count - number of base units being converted - decimal - decimal precision of label - isLong - uses the long label if true, short label otherwise - """ - - format = "%%.%if" % decimal - if count < 1: - unitsLabel = units[-1][2] + "s" if isLong else units[-1][1] - return "%s%s" % (format % count, unitsLabel) - - for countPerUnit, shortLabel, longLabel in units: - if count >= countPerUnit: - if count * 10 ** decimal % countPerUnit * 10 ** decimal == 0: - # even division, keep it simple - countLabel = format % (count / countPerUnit) - else: - # unfortunately the %f formatting has no method of rounding down, so - # reducing value to only concern the digits that are visible - note - # that this doesn't work with minuscule values (starts breaking down at - # around eight decimal places) or edge cases when working with powers - # of two - croppedCount = count - (count % (countPerUnit / (10 ** decimal))) - countLabel = format % (croppedCount / countPerUnit) - - if isLong: - # plural if any of the visible units make it greater than one (for - # instance 1.0003 is plural but 1.000 isn't) - if decimal > 0: isPlural = count >= (countPerUnit + countPerUnit / (10 ** decimal)) - else: isPlural = count >= countPerUnit * 2 - return countLabel + longLabel + ("s" if isPlural else "") - else: return countLabel + shortLabel - def _isWideCharactersAvailable(): """ True if curses has wide character support (which is required to print
tor-commits@lists.torproject.org