tor-commits
Threads by month
- ----- 2025 -----
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
September 2014
- 22 participants
- 980 discussions
commit c0d0d322b6e960cd7da6ee43d24f747488c2ad00
Author: David Fifield <david(a)bamsoftware.com>
Date: Sun Aug 31 19:16:39 2014 -0700
Simplify with gofmt -s.
gofmt -l -w -s .
---
args.go | 2 +-
args_test.go | 22 +++++++++++-----------
2 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/args.go b/args.go
index c38adf7..f1b5a8d 100644
--- a/args.go
+++ b/args.go
@@ -200,7 +200,7 @@ func encodeSmethodArgs(args Args) string {
}
keys := make([]string, 0, len(args))
- for key, _ := range args {
+ for key := range args {
keys = append(keys, key)
}
sort.Strings(keys)
diff --git a/args_test.go b/args_test.go
index 8a77251..134ac31 100644
--- a/args_test.go
+++ b/args_test.go
@@ -255,29 +255,29 @@ func TestParseServerTransportOptions(t *testing.T) {
{
"t:k=v",
map[string]Args{
- "t": Args{"k": []string{"v"}},
+ "t": {"k": []string{"v"}},
},
},
{
"t1:k=v1;t2:k=v2;t1:k=v3",
map[string]Args{
- "t1": Args{"k": []string{"v1", "v3"}},
- "t2": Args{"k": []string{"v2"}},
+ "t1": {"k": []string{"v1", "v3"}},
+ "t2": {"k": []string{"v2"}},
},
},
{
"t\\:1:k=v;t\\=2:k=v;t\\;3:k=v;t\\\\4:k=v",
map[string]Args{
- "t:1": Args{"k": []string{"v"}},
- "t=2": Args{"k": []string{"v"}},
- "t;3": Args{"k": []string{"v"}},
- "t\\4": Args{"k": []string{"v"}},
+ "t:1": {"k": []string{"v"}},
+ "t=2": {"k": []string{"v"}},
+ "t;3": {"k": []string{"v"}},
+ "t\\4": {"k": []string{"v"}},
},
},
{
"t:k\\:1=v;t:k\\=2=v;t:k\\;3=v;t:k\\\\4=v",
map[string]Args{
- "t": Args{
+ "t": {
"k:1": []string{"v"},
"k=2": []string{"v"},
"k;3": []string{"v"},
@@ -288,14 +288,14 @@ func TestParseServerTransportOptions(t *testing.T) {
{
"t:k=v\\:1;t:k=v\\=2;t:k=v\\;3;t:k=v\\\\4",
map[string]Args{
- "t": Args{"k": []string{"v:1", "v=2", "v;3", "v\\4"}},
+ "t": {"k": []string{"v:1", "v=2", "v;3", "v\\4"}},
},
},
{
"trebuchet:secret=nou;trebuchet:cache=/tmp/cache;ballista:secret=yes",
map[string]Args{
- "trebuchet": Args{"secret": []string{"nou"}, "cache": []string{"/tmp/cache"}},
- "ballista": Args{"secret": []string{"yes"}},
+ "trebuchet": {"secret": []string{"nou"}, "cache": []string{"/tmp/cache"}},
+ "ballista": {"secret": []string{"yes"}},
},
},
}
1
0

01 Sep '14
commit f8ed0cfe8eba91741eca5c33cdb852cc0aa8a123
Author: Mike Perry <mikeperry-git(a)torproject.org>
Date: Sun Aug 31 17:42:21 2014 -0700
Update NoScript to 2.6.8.39.
---
Bundle-Data/Docs/ChangeLog.txt | 2 ++
gitian/versions.alpha | 6 +++---
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/Bundle-Data/Docs/ChangeLog.txt b/Bundle-Data/Docs/ChangeLog.txt
index d511d84..29082ac 100644
--- a/Bundle-Data/Docs/ChangeLog.txt
+++ b/Bundle-Data/Docs/ChangeLog.txt
@@ -1,6 +1,7 @@
Tor Browser Bundle 4.0-alpha-2 -- Sep 2 2014
* All Platforms
* Update Firefox to 24.8.0esr
+ * Update NoScript to 2.6.8.39
* Update Tor Launcher to 0.2.7.0
* Bug 11405: Remove firewall prompt from wizard.
* Bug 12895: Mention @riseup.net as a valid bridge request email address
@@ -26,6 +27,7 @@ Tor Browser Bundle 4.0-alpha-2 -- Sep 2 2014
Tor Browser Bundle 3.6.5 -- Sep 2 2014
* All Platforms
* Update Firefox to 24.8.0esr
+ * Update NoScript to 2.6.8.39
* Update HTTPS Everywhere to 4.0.0
* Update Torbutton to 1.6.12.1
* Bug 12684: New strings for canvas image extraction message
diff --git a/gitian/versions.alpha b/gitian/versions.alpha
index d6d93b6..8fcde6e 100755
--- a/gitian/versions.alpha
+++ b/gitian/versions.alpha
@@ -52,7 +52,7 @@ GO_VER=1.3
## File names for the source packages
OPENSSL_PACKAGE=openssl-${OPENSSL_VER}.tar.gz
GMP_PACKAGE=gmp-${GMP_VER}.tar.bz2
-NOSCRIPT_PACKAGE=noscript_security_suite-2.6.8.36-sm+fx+fn.xpi
+NOSCRIPT_PACKAGE=noscript_security_suite-2.6.8.39-fx+sm+fn.xpi
HTTPSE_PACKAGE=https-everywhere-${HTTPSE_VER}.xpi
TOOLCHAIN4_PACKAGE=x86_64-apple-darwin10.tar.xz
TOOLCHAIN4_OLD_PACKAGE=multiarch-darwin11-cctools127.2-gcc42-5666.3-llvmgcc42-2336.1-Linux-120724.tar.xz
@@ -80,7 +80,7 @@ GMP_HASH=752079520b4690531171d0f4532e40f08600215feefede70b24fabdc6f1ab160
OSXSDK_HASH=6602d8d5ddb371fbc02e2a5967d9bd0cd7358d46f9417753c8234b923f2ea6fc
TOOLCHAIN4_HASH=7b71bfe02820409b994c5c33a7eab81a81c72550f5da85ff7af70da3da244645
TOOLCHAIN4_OLD_HASH=65c1b2d302358a6b95a26c6828a66908a199276193bb0b268f2dcc1a997731e9
-NOSCRIPT_HASH=3c8ed31dbd67634debf333f957ba5c08bf3596408c9d09b5bf4da98499733af4
+NOSCRIPT_HASH=6b97c02b3ceab452f0ceec0f8918e0653837b24f376ba1a9dd78bb551bae3715
HTTPSE_HASH=6feb4982d13f89656b61435b6b49e1996c61bc79e52d046d02312879376028e3
MSVCR100_HASH=1221a09484964a6f38af5e34ee292b9afefccb3dc6e55435fd3aaf7c235d9067
PYCRYPTO_HASH=f2ce1e989b272cfcb677616763e0a2e7ec659effa67a88aa92b3a65528f60a3c
@@ -102,7 +102,7 @@ TOOLCHAIN4_OLD_URL=https://people.torproject.org/~mikeperry/mirrors/sources…
OSXSDK_URL=https://launchpad.net/~flosoft/+archive/cross-apple/+files/${OSX…
BINUTILS_URL=https://ftp.gnu.org/gnu/binutils/${BINUTILS_PACKAGE}
GCC_URL=https://ftp.gnu.org/gnu/gcc/gcc-${GCC_VER}/${GCC_PACKAGE}
-NOSCRIPT_URL=https://addons.cdn.mozilla.net/storage/public-staging/722/${NOSCRIPT_PACKAGE}
+NOSCRIPT_URL=https://addons.cdn.mozilla.net/user-media/addons/722/${NOSCRIPT_PACKAGE}
HTTPSE_URL=https://www.eff.org/files/${HTTPSE_PACKAGE}
PYTHON_URL=https://www.python.org/ftp/python/${PYTHON_VER}/${PYTHON_PACKAGE}
PYTHON_MSI_URL=https://www.python.org/ftp/python/${PYTHON_VER}/${PYTHON_MSI…
1
0

[tor-browser-bundle/master] Don't distribute mar tools. They are not reproducible (yet).
by mikeperry@torproject.org 01 Sep '14
by mikeperry@torproject.org 01 Sep '14
01 Sep '14
commit 6de616f8de99af3343a85346028a1538e89f7f49
Author: Mike Perry <mikeperry-git(a)torproject.org>
Date: Sun Aug 31 17:32:47 2014 -0700
Don't distribute mar tools. They are not reproducible (yet).
---
gitian/mkbundle-linux.sh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/gitian/mkbundle-linux.sh b/gitian/mkbundle-linux.sh
index dd8e00a..e3b145d 100755
--- a/gitian/mkbundle-linux.sh
+++ b/gitian/mkbundle-linux.sh
@@ -248,7 +248,7 @@ then
mkdir -p $WRAPPER_DIR/$TORBROWSER_VERSION/
cp -a build/out/tor-browser-linux*xz* $WRAPPER_DIR/$TORBROWSER_VERSION/ || exit 1
cp -a build/out/*.mar $WRAPPER_DIR/$TORBROWSER_VERSION/ || exit 1
- cp -a inputs/mar-tools-linux*.zip $WRAPPER_DIR/$TORBROWSER_VERSION/ || exit 1
+ #cp -a inputs/mar-tools-linux*.zip $WRAPPER_DIR/$TORBROWSER_VERSION/ || exit 1
cp -a inputs/*debug.zip $WRAPPER_DIR/$TORBROWSER_VERSION/ || exit 1
touch inputs/bundle-linux.gbuilt
else
1
0

01 Sep '14
commit 21000b7eb3bcfced485cdf279fc16d1d1976d0c8
Author: Mike Perry <mikeperry-git(a)torproject.org>
Date: Sun Aug 31 17:20:43 2014 -0700
Bump NoScript version.
---
Bundle-Data/Docs/ChangeLog.txt | 1 +
gitian/versions | 6 +++---
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/Bundle-Data/Docs/ChangeLog.txt b/Bundle-Data/Docs/ChangeLog.txt
index 8bb3eae..6688bf1 100644
--- a/Bundle-Data/Docs/ChangeLog.txt
+++ b/Bundle-Data/Docs/ChangeLog.txt
@@ -1,6 +1,7 @@
Tor Browser Bundle 3.6.5 -- Sep 2 2014
* All Platforms
* Update Firefox to 24.8.0esr
+ * Update NoScript to 2.6.8.39
* Update HTTPS Everywhere to 4.0.0
* Update Torbutton to 1.6.12.1
* Bug 12684: New strings for canvas image extraction message
diff --git a/gitian/versions b/gitian/versions
index 14803a8..4096ec0 100755
--- a/gitian/versions
+++ b/gitian/versions
@@ -47,7 +47,7 @@ HTTPSE_VER=4.0.0
## File names for the source packages
OPENSSL_PACKAGE=openssl-${OPENSSL_VER}.tar.gz
GMP_PACKAGE=gmp-${GMP_VER}.tar.bz2
-NOSCRIPT_PACKAGE=noscript_security_suite-2.6.8.36-sm+fx+fn.xpi
+NOSCRIPT_PACKAGE=noscript_security_suite-2.6.8.39-fx+sm+fn.xpi
HTTPSE_PACKAGE=https-everywhere-${HTTPSE_VER}.xpi
TOOLCHAIN4_PACKAGE=x86_64-apple-darwin10.tar.xz
TOOLCHAIN4_OLD_PACKAGE=multiarch-darwin11-cctools127.2-gcc42-5666.3-llvmgcc42-2336.1-Linux-120724.tar.xz
@@ -75,7 +75,7 @@ GMP_HASH=752079520b4690531171d0f4532e40f08600215feefede70b24fabdc6f1ab160
OSXSDK_HASH=6602d8d5ddb371fbc02e2a5967d9bd0cd7358d46f9417753c8234b923f2ea6fc
TOOLCHAIN4_HASH=7b71bfe02820409b994c5c33a7eab81a81c72550f5da85ff7af70da3da244645
TOOLCHAIN4_OLD_HASH=65c1b2d302358a6b95a26c6828a66908a199276193bb0b268f2dcc1a997731e9
-NOSCRIPT_HASH=3c8ed31dbd67634debf333f957ba5c08bf3596408c9d09b5bf4da98499733af4
+NOSCRIPT_HASH=6b97c02b3ceab452f0ceec0f8918e0653837b24f376ba1a9dd78bb551bae3715
HTTPSE_HASH=1241631091f9ceb417f639a6df76425cda36ee4b38b78ce8d318088eb17a7219
MINGW_HASH=a5b03d0448a309341be4cf34c6ad3016d04c89952dca5243254b4d6c738b164f
MSVCR100_HASH=1221a09484964a6f38af5e34ee292b9afefccb3dc6e55435fd3aaf7c235d9067
@@ -97,7 +97,7 @@ TOOLCHAIN4_OLD_URL=https://people.torproject.org/~mikeperry/mirrors/sources…
OSXSDK_URL=https://launchpad.net/~flosoft/+archive/cross-apple/+files/${OSX…
BINUTILS_URL=https://ftp.gnu.org/gnu/binutils/${BINUTILS_PACKAGE}
GCC_URL=https://ftp.gnu.org/gnu/gcc/gcc-${GCC_VER}/${GCC_PACKAGE}
-NOSCRIPT_URL=https://addons.cdn.mozilla.net/storage/public-staging/722/${NOSCRIPT_PACKAGE}
+NOSCRIPT_URL=https://addons.cdn.mozilla.net/user-media/addons/722/${NOSCRIPT_PACKAGE}
HTTPSE_URL=https://www.eff.org/files/${HTTPSE_PACKAGE}
PYTHON_URL=http://www.python.org/ftp/python/${PYTHON_VER}/${PYTHON_PACKAGE}
PYTHON_MSI_URL=http://www.python.org/ftp/python/${PYTHON_VER}/${PYTHON_MSI_…
1
0

01 Sep '14
commit 97bf90abc2386a668f3ae2270b09ef501e6426f8
Author: Damian Johnson <atagar(a)torproject.org>
Date: Sun Aug 31 12:57:48 2014 -0700
Wrap cropping into the Sampling's format() method
---
arm/header_panel.py | 28 ++++++++++++++++------------
1 file changed, 16 insertions(+), 12 deletions(-)
diff --git a/arm/header_panel.py b/arm/header_panel.py
index 82f8ae1..ff862a8 100644
--- a/arm/header_panel.py
+++ b/arm/header_panel.py
@@ -9,20 +9,19 @@ import time
import curses
import threading
-import arm.util.tracker
-
import stem
import stem.util.proc
import stem.util.str_tools
import stem.util.system
+import arm.controller
+import arm.popups
+import arm.starter
+import arm.util.tracker
+
from stem.control import Listener, State
from stem.util import conf, log
-import arm.starter
-import arm.popups
-import arm.controller
-
from util import panel, ui_tools, tor_controller
MIN_DUAL_COL_WIDTH = 141 # minimum width where we'll show two columns
@@ -186,16 +185,16 @@ class HeaderPanel(panel.Panel, threading.Thread):
initial_x, space_left = x, min(width, 40)
- x = self.addstr(y, x, ui_tools.crop_str(vals.format('arm - {hostname}'), space_left))
+ x = self.addstr(y, x, vals.format('arm - {hostname}', space_left))
space_left -= x - initial_x
if space_left >= 10:
- self.addstr(y, x, ' (%s)' % ui_tools.crop_str(vals.platform, space_left - 3, 4))
+ self.addstr(y, x, ' (%s)' % vals.format('{platform}', space_left - 3))
x, space_left = initial_x + 43, width - 43
if vals.version != 'Unknown' and space_left >= 10:
- x = self.addstr(y, x, ui_tools.crop_str(vals.format('Tor {version}'), space_left))
+ x = self.addstr(y, x, vals.format('Tor {version}', space_left))
space_left -= x - 43 - initial_x
if space_left >= 7 + len(vals.version_status):
@@ -284,7 +283,7 @@ class HeaderPanel(panel.Panel, threading.Thread):
initial_x, space_left = x, width
- x = self.addstr(y, x, ui_tools.crop_str(vals.format('fingerprint: {fingerprint}'), width))
+ x = self.addstr(y, x, vals.format('fingerprint: {fingerprint}', width))
space_left -= x - initial_x
if space_left >= 30 and vals.fd_used and vals.fd_limit:
@@ -502,12 +501,17 @@ class Sampling(object):
self.hostname = uname_vals[1]
self.platform = '%s %s' % (uname_vals[0], uname_vals[2]) # [platform name] [version]
- def format(self, msg):
+ def format(self, msg, crop_width = None):
"""
Applies our attributes to the given string.
"""
- return msg.format(**self.__dict__)
+ formatted_msg = msg.format(**self.__dict__)
+
+ if crop_width:
+ formatted_msg = ui_tools.crop_str(formatted_msg, crop_width)
+
+ return formatted_msg
def _get_fd_used(self, pid):
"""
1
0

[arm/master] Replacing ui_tools.crop_str() with str_tools.crop()
by atagar@torproject.org 01 Sep '14
by atagar@torproject.org 01 Sep '14
01 Sep '14
commit 7e583acbe7ae25652d6aae48403b839b4239b0e1
Author: Damian Johnson <atagar(a)torproject.org>
Date: Sun Aug 31 17:12:30 2014 -0700
Replacing ui_tools.crop_str() with str_tools.crop()
Replacing our crop method with the one moved to stem.
---
arm/config_panel.py | 14 ++--
arm/connections/circ_entry.py | 6 +-
arm/connections/conn_entry.py | 20 +++---
arm/connections/count_popup.py | 2 -
arm/connections/descriptor_popup.py | 6 +-
arm/graphing/bandwidth_stats.py | 2 +-
arm/header_panel.py | 5 +-
arm/log_panel.py | 10 +--
arm/torrc_panel.py | 6 +-
arm/util/ui_tools.py | 122 +----------------------------------
10 files changed, 37 insertions(+), 156 deletions(-)
diff --git a/arm/config_panel.py b/arm/config_panel.py
index 061da61..e71948b 100644
--- a/arm/config_panel.py
+++ b/arm/config_panel.py
@@ -171,9 +171,9 @@ class ConfigEntry():
arg_set = (option_width, value_width, summary_width)
if not self.label_cache or self.label_cache_args != arg_set:
- option_label = ui_tools.crop_str(self.get(Field.OPTION), option_width)
- value_label = ui_tools.crop_str(self.get(Field.VALUE), value_width)
- summary_label = ui_tools.crop_str(self.get(Field.SUMMARY), summary_width, None)
+ option_label = str_tools.crop(self.get(Field.OPTION), option_width)
+ value_label = str_tools.crop(self.get(Field.VALUE), value_width)
+ summary_label = str_tools.crop(self.get(Field.SUMMARY), summary_width, None)
line_text_layout = "%%-%is %%-%is %%-%is" % (option_width, value_width, summary_width)
self.label_cache = line_text_layout % (option_label, value_label, summary_label)
self.label_cache_args = arg_set
@@ -500,7 +500,7 @@ class ConfigPanel(panel.Panel):
visible_config_lines = height - 3 if is_option_line_separate else height - 2
for i in range(visible_config_lines):
- line = ui_tools.crop_str(config_lines[i], width - 2)
+ line = str_tools.crop(config_lines[i], width - 2)
if " " in line:
option, arg = line.split(" ", 1)
@@ -686,7 +686,7 @@ class ConfigPanel(panel.Panel):
value_attr_label = ", ".join(value_attr)
value_label_width = width - 12 - len(value_attr_label)
- value_label = ui_tools.crop_str(selection.get(Field.VALUE), value_label_width)
+ value_label = str_tools.crop(selection.get(Field.VALUE), value_label_width)
self.addstr(2, 2, "Value: %s (%s)" % (value_label, value_attr_label), *selection_format)
@@ -716,11 +716,11 @@ class ConfigPanel(panel.Panel):
if i != description_height - 1:
# there's more lines to display
- msg, remainder = ui_tools.crop_str(line_content, width - 3, 4, 4, ui_tools.Ending.HYPHEN, True)
+ msg, remainder = str_tools.crop(line_content, width - 3, 4, 4, str_tools.Ending.HYPHEN, True)
description_content = remainder.strip() + description_content
else:
# this is the last line, end it with an ellipse
- msg = ui_tools.crop_str(line_content, width - 3, 4, 4)
+ msg = str_tools.crop(line_content, width - 3, 4, 4)
self.addstr(3 + i, 2, msg, *selection_format)
diff --git a/arm/connections/circ_entry.py b/arm/connections/circ_entry.py
index 4e7b2d6..c6db152 100644
--- a/arm/connections/circ_entry.py
+++ b/arm/connections/circ_entry.py
@@ -11,7 +11,9 @@ followed by an entry for each hop in the circuit. For instance:
import curses
from arm.connections import entries, conn_entry
-from arm.util import tor_controller, ui_tools
+from arm.util import tor_controller
+
+from stem.util import str_tools
ADDRESS_LOOKUP_CACHE = {}
@@ -191,7 +193,7 @@ class CircLine(conn_entry.ConnectionLine):
# fills the nickname into the empty space here
- dst = "%s%-25s " % (dst[:25], ui_tools.crop_str(self.foreign.get_nickname(), 25, 0))
+ dst = "%s%-25s " % (dst[:25], str_tools.crop(self.foreign.get_nickname(), 25, 0))
etc = self.get_etc_content(width - baseline_space - len(dst), listing_type)
elif listing_type == entries.ListingType.HOSTNAME:
diff --git a/arm/connections/conn_entry.py b/arm/connections/conn_entry.py
index cad2dbb..4b9a017 100644
--- a/arm/connections/conn_entry.py
+++ b/arm/connections/conn_entry.py
@@ -6,7 +6,7 @@ Connection panel entries related to actual connections to or from the system
import time
import curses
-from arm.util import tor_controller, ui_tools
+from arm.util import tor_controller
from arm.connections import entries
import stem.control
@@ -561,7 +561,7 @@ class ConnectionLine(entries.ConnectionPanelLine):
# show nickname (column width: remainder)
nickname_space = width - used_space
- nickname_label = ui_tools.crop_str(self.foreign.get_nickname(), nickname_space, 0)
+ nickname_label = str_tools.crop(self.foreign.get_nickname(), nickname_space, 0)
etc += ("%%-%is " % nickname_space) % nickname_label
used_space += nickname_space + 2
elif listing_type == entries.ListingType.HOSTNAME:
@@ -578,7 +578,7 @@ class ConnectionLine(entries.ConnectionPanelLine):
if width > used_space + 17 and CONFIG["features.connection.showColumn.nickname"]:
# show nickname (column width: min 17 characters, uses half of the remainder)
nickname_space = 15 + (width - (used_space + 17)) / 2
- nickname_label = ui_tools.crop_str(self.foreign.get_nickname(), nickname_space, 0)
+ nickname_label = str_tools.crop(self.foreign.get_nickname(), nickname_space, 0)
etc += ("%%-%is " % nickname_space) % nickname_label
used_space += (nickname_space + 2)
elif listing_type == entries.ListingType.FINGERPRINT:
@@ -597,7 +597,7 @@ class ConnectionLine(entries.ConnectionPanelLine):
nickname_space -= 28
if CONFIG["features.connection.showColumn.nickname"]:
- nickname_label = ui_tools.crop_str(self.foreign.get_nickname(), nickname_space, 0)
+ nickname_label = str_tools.crop(self.foreign.get_nickname(), nickname_space, 0)
etc += ("%%-%is " % nickname_space) % nickname_label
used_space += nickname_space + 2
@@ -723,7 +723,7 @@ class ConnectionLine(entries.ConnectionPanelLine):
# truncates long hostnames and sets dst to <hostname>:<port>
- hostname = ui_tools.crop_str(hostname, hostname_space, 0)
+ hostname = str_tools.crop(hostname, hostname_space, 0)
dst = ("%%-%is" % hostname_space) % (hostname + port_label)
elif listing_type == entries.ListingType.FINGERPRINT:
src = "localhost"
@@ -757,8 +757,8 @@ class ConnectionLine(entries.ConnectionPanelLine):
used_space = width # prevents padding at the end
if len(src) + len(dst) > base_space:
- src = ui_tools.crop_str(src, base_space / 3)
- dst = ui_tools.crop_str(dst, base_space - len(src))
+ src = str_tools.crop(src, base_space / 3)
+ dst = str_tools.crop(dst, base_space - len(src))
# pads dst entry to its max space
@@ -901,7 +901,7 @@ class ConnectionLine(entries.ConnectionPanelLine):
# crops any lines that are too long
for i in range(len(lines)):
- lines[i] = ui_tools.crop_str(lines[i], width - 2)
+ lines[i] = str_tools.crop(lines[i], width - 2)
return lines
@@ -951,7 +951,7 @@ class ConnectionLine(entries.ConnectionPanelLine):
# crops with a hyphen if too long
- purpose = ui_tools.crop_str(purpose, space_available, end_type = ui_tools.Ending.HYPHEN)
+ purpose = str_tools.crop(purpose, space_available, ending = str_tools.Ending.HYPHEN)
destination_address += " (%s)" % purpose
elif not connection.is_private_address(self.foreign.get_address()):
@@ -971,7 +971,7 @@ class ConnectionLine(entries.ConnectionPanelLine):
# dividers if there's multiple pieces of extra data
max_hostname_space = space_available - 2 * len(extra_info)
- destination_hostname = ui_tools.crop_str(destination_hostname, max_hostname_space)
+ destination_hostname = str_tools.crop(destination_hostname, max_hostname_space)
extra_info.append(destination_hostname)
space_available -= len(destination_hostname)
diff --git a/arm/connections/count_popup.py b/arm/connections/count_popup.py
index 50fb7d8..4decf46 100644
--- a/arm/connections/count_popup.py
+++ b/arm/connections/count_popup.py
@@ -8,8 +8,6 @@ import operator
import arm.controller
import arm.popups
-from arm.util import ui_tools
-
from stem.util import connection, enum, log
CountType = enum.Enum("CLIENT_LOCALE", "EXIT_PORT")
diff --git a/arm/connections/descriptor_popup.py b/arm/connections/descriptor_popup.py
index 30adb6c..af6ee69 100644
--- a/arm/connections/descriptor_popup.py
+++ b/arm/connections/descriptor_popup.py
@@ -10,6 +10,8 @@ import arm.connections.conn_entry
from arm.util import panel, tor_controller, ui_tools
+from stem.util import str_tools
+
# field keywords used to identify areas for coloring
LINE_NUM_COLOR = "yellow"
@@ -238,12 +240,12 @@ def draw(popup, fingerprint, display_text, display_color, scroll, show_line_numb
if len(msg) >= max_msg_size:
# needs to split up the line
- msg, remainder = ui_tools.crop_str(msg, max_msg_size, None, end_type = None, get_remainder = True)
+ msg, remainder = str_tools.crop(msg, max_msg_size, None, ending = None, get_remainder = True)
if x_offset == cursor_location and msg == "":
# first word is longer than the line
- msg = ui_tools.crop_str(remainder, max_msg_size)
+ msg = str_tools.crop(remainder, max_msg_size)
if " " in remainder:
remainder = remainder.split(" ", 1)[1]
diff --git a/arm/graphing/bandwidth_stats.py b/arm/graphing/bandwidth_stats.py
index 634a0f5..16cc349 100644
--- a/arm/graphing/bandwidth_stats.py
+++ b/arm/graphing/bandwidth_stats.py
@@ -9,7 +9,7 @@ import curses
import arm.controller
from arm.graphing import graph_panel
-from arm.util import tor_controller, ui_tools
+from arm.util import tor_controller
from stem.control import State
from stem.util import conf, log, str_tools, system
diff --git a/arm/header_panel.py b/arm/header_panel.py
index d8dc8ad..13194e4 100644
--- a/arm/header_panel.py
+++ b/arm/header_panel.py
@@ -18,10 +18,9 @@ import arm.controller
import arm.popups
import arm.starter
import arm.util.tracker
-import arm.util.ui_tools
from stem.control import Listener, State
-from stem.util import conf, log
+from stem.util import conf, log, str_tools
from util import panel, tor_controller
@@ -510,7 +509,7 @@ class Sampling(object):
formatted_msg = msg.format(**self.__dict__)
if crop_width:
- formatted_msg = arm.util.ui_tools.crop_str(formatted_msg, crop_width)
+ formatted_msg = str_tools.crop(formatted_msg, crop_width)
return formatted_msg
diff --git a/arm/log_panel.py b/arm/log_panel.py
index e39c70f..6f5087b 100644
--- a/arm/log_panel.py
+++ b/arm/log_panel.py
@@ -14,7 +14,7 @@ import threading
import stem
from stem.control import State
from stem.response import events
-from stem.util import conf, log, system
+from stem.util import conf, log, str_tools, system
import arm.arguments
import arm.popups
@@ -1051,9 +1051,9 @@ class LogPanel(panel.Panel, threading.Thread, logging.Handler):
if len(msg) > max_msg_size:
# message is too long - break it up
if line_offset == max_entries_per_line - 1:
- msg = ui_tools.crop_str(msg, max_msg_size)
+ msg = str_tools.crop(msg, max_msg_size)
else:
- msg, remainder = ui_tools.crop_str(msg, max_msg_size, 4, 4, ui_tools.Ending.HYPHEN, True)
+ msg, remainder = str_tools.crop(msg, max_msg_size, 4, 4, str_tools.Ending.HYPHEN, True)
display_queue.insert(0, (remainder.strip(), format, include_break))
include_break = True
@@ -1246,7 +1246,7 @@ class LogPanel(panel.Panel, threading.Thread, logging.Handler):
if not current_pattern:
panel_label = "Events:"
else:
- label_pattern = ui_tools.crop_str(current_pattern, width - 18)
+ label_pattern = str_tools.crop(current_pattern, width - 18)
panel_label = "Events (filter: %s):" % label_pattern
else:
# does the following with all runlevel types (tor, arm, and stem):
@@ -1320,7 +1320,7 @@ class LogPanel(panel.Panel, threading.Thread, logging.Handler):
if current_pattern:
attr_label += " - filter: %s" % current_pattern
- attr_label = ui_tools.crop_str(attr_label, width - 10, 1)
+ attr_label = str_tools.crop(attr_label, width - 10, 1)
if attr_label:
attr_label = " (%s)" % attr_label
diff --git a/arm/torrc_panel.py b/arm/torrc_panel.py
index a299ef9..6dfaf17 100644
--- a/arm/torrc_panel.py
+++ b/arm/torrc_panel.py
@@ -11,7 +11,7 @@ import arm.popups
from arm.util import panel, tor_config, tor_controller, ui_tools
from stem.control import State
-from stem.util import conf, enum
+from stem.util import conf, enum, str_tools
def conf_handler(key, value):
@@ -316,10 +316,10 @@ class TorrcPanel(panel.Panel):
# message is too long - break it up
if line_offset == max_lines_per_entry - 1:
- msg = ui_tools.crop_str(msg, max_msg_size)
+ msg = str_tools.crop(msg, max_msg_size)
else:
include_break = True
- msg, remainder = ui_tools.crop_str(msg, max_msg_size, 4, 4, ui_tools.Ending.HYPHEN, True)
+ msg, remainder = str_tools.crop(msg, max_msg_size, 4, 4, str_tools.Ending.HYPHEN, True)
display_queue.insert(0, (remainder.strip(), format))
draw_line = display_line + line_offset
diff --git a/arm/util/ui_tools.py b/arm/util/ui_tools.py
index 01daffa..cfa6ba3 100644
--- a/arm/util/ui_tools.py
+++ b/arm/util/ui_tools.py
@@ -2,14 +2,13 @@
Toolkit for working with curses.
"""
-import sys
import curses
from curses.ascii import isprint
from arm.util import log, msg
-from stem.util import conf, enum, system
+from stem.util import conf, system
COLOR_LIST = {
'red': curses.COLOR_RED,
@@ -25,7 +24,6 @@ COLOR_LIST = {
DEFAULT_COLOR_ATTR = dict([(color, 0) for color in COLOR_LIST])
COLOR_ATTR = None
-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)
@@ -183,124 +181,6 @@ def get_printable(line, keep_newlines = True):
return line
-def crop_str(msg, size, min_word_length = 4, min_crop = 0, end_type = Ending.ELLIPSE, get_remainder = False):
- """
- Provides the msg constrained to the given length, truncating on word breaks.
- If the last words is long this truncates mid-word with an ellipse. If there
- isn't room for even a truncated single word (or one word plus the ellipse if
- including those) then this provides an empty string. If a cropped string ends
- with a comma or period then it's stripped (unless we're providing the
- remainder back). For example...
-
- >>> crop_str("This is a looooong message", 17)
- "This is a looo..."
-
- >>> crop_str("This is a looooong message", 12)
- "This is a..."
-
- >>> crop_str("This is a looooong message", 3)
- ""
-
- :param str msg: text to be processed
- :param int size: space available for text
- :param int min_word_length: minimum characters before which a word is
- dropped, requires whole word if **None**
- :param int min_crop: minimum characters that must be dropped if a word is
- cropped
- :param Ending end_type: type of ending used when truncating, no special
- truncation is used if **None**
- :param bool get_remainder: returns a tuple with the second part being the
- cropped portion of the message
-
- :returns: **str** of the text truncated to the given length
- """
-
- # checks if there's room for the whole message
-
- if len(msg) <= size:
- if get_remainder:
- return (msg, "")
- else:
- return msg
-
- # avoids negative input
-
- size = max(0, size)
-
- if min_word_length is not None:
- min_word_length = max(0, min_word_length)
-
- min_crop = max(0, min_crop)
-
- # since we're cropping, the effective space available is less with an
- # ellipse, and cropping words requires an extra space for hyphens
-
- if end_type == Ending.ELLIPSE:
- size -= 3
- elif end_type == Ending.HYPHEN and min_word_length is not None:
- min_word_length += 1
-
- # checks if there isn't the minimum space needed to include anything
-
- last_wordbreak = msg.rfind(" ", 0, size + 1)
-
- if last_wordbreak == -1:
- # we're splitting the first word
-
- if min_word_length is None or size < min_word_length:
- if get_remainder:
- return ("", msg)
- else:
- return ""
-
- include_crop = True
- else:
- last_wordbreak = len(msg[:last_wordbreak].rstrip()) # drops extra ending whitespaces
-
- if (min_word_length is not None and size < min_word_length) or (min_word_length is None and last_wordbreak < 1):
- if get_remainder:
- return ("", msg)
- else:
- return ""
-
- if min_word_length is None:
- min_word_length = sys.maxint
-
- include_crop = size - last_wordbreak - 1 >= min_word_length
-
- # if there's a max crop size then make sure we're cropping at least that many characters
-
- if include_crop and min_crop:
- next_wordbreak = msg.find(" ", size)
-
- if next_wordbreak == -1:
- next_wordbreak = len(msg)
-
- include_crop = next_wordbreak - size + 1 >= min_crop
-
- if include_crop:
- return_msg, remainder = msg[:size], msg[size:]
-
- if end_type == Ending.HYPHEN:
- remainder = return_msg[-1] + remainder
- return_msg = return_msg[:-1].rstrip() + "-"
- else:
- return_msg, remainder = msg[:last_wordbreak], msg[last_wordbreak:]
-
- # if this is ending with a comma or period then strip it off
-
- if not get_remainder and return_msg and return_msg[-1] in (",", "."):
- return_msg = return_msg[:-1]
-
- if end_type == Ending.ELLIPSE:
- return_msg = return_msg.rstrip() + "..."
-
- if get_remainder:
- return (return_msg, remainder)
- else:
- return return_msg
-
-
def pad_str(msg, size, crop_extra = False):
"""
Provides the string padded with whitespace to the given length.
1
0

01 Sep '14
commit 7634f6fbe1e3c76d84fdd6929c30f21cb7a09fe1
Author: Damian Johnson <atagar(a)torproject.org>
Date: Sun Aug 31 14:45:15 2014 -0700
Supporting color names in Panel's addstr()
Python's curses module is a very thin wrapper around the C curses library and
as such it's clunky. One bit it's especially sucky is how it does colors.
We smoothed over this quite a bit by adding a get_color() helper that would
convert a color name (red, blue, etc) into the registered color attribute code
for that. On reflection though why not simply have our addstr() method do that
conversion for us?
This pretty much drops the need for us to call get_color() all throughout our
codebase.
---
arm/config_panel.py | 24 +++++++++++------------
arm/connections/circ_entry.py | 4 ++--
arm/connections/conn_entry.py | 6 +++---
arm/connections/conn_panel.py | 4 ++--
arm/connections/count_popup.py | 6 +++---
arm/connections/descriptor_popup.py | 19 +++++++++---------
arm/graphing/bandwidth_stats.py | 10 +++++-----
arm/graphing/graph_panel.py | 12 ++++++------
arm/header_panel.py | 29 ++++++++++++++--------------
arm/log_panel.py | 32 +++++++++++++++----------------
arm/menu/menu.py | 6 +++---
arm/torrc_panel.py | 36 +++++++++++++++++------------------
arm/util/panel.py | 12 ++++++++++--
13 files changed, 104 insertions(+), 96 deletions(-)
diff --git a/arm/config_panel.py b/arm/config_panel.py
index dabe078..061da61 100644
--- a/arm/config_panel.py
+++ b/arm/config_panel.py
@@ -504,10 +504,10 @@ class ConfigPanel(panel.Panel):
if " " in line:
option, arg = line.split(" ", 1)
- popup.addstr(i + 1, 1, option, curses.A_BOLD | ui_tools.get_color("green"))
- popup.addstr(i + 1, len(option) + 2, arg, curses.A_BOLD | ui_tools.get_color("cyan"))
+ popup.addstr(i + 1, 1, option, curses.A_BOLD, 'green')
+ popup.addstr(i + 1, len(option) + 2, arg, curses.A_BOLD, 'cyan')
else:
- popup.addstr(i + 1, 1, line, curses.A_BOLD | ui_tools.get_color("green"))
+ popup.addstr(i + 1, 1, line, curses.A_BOLD, 'green')
# draws selection options (drawn right to left)
@@ -525,7 +525,7 @@ class ConfigPanel(panel.Panel):
selection_format = curses.A_STANDOUT if i == selection else curses.A_NORMAL
popup.addstr(height - 2, draw_x, "[")
- popup.addstr(height - 2, draw_x + 1, option_label, selection_format | curses.A_BOLD)
+ popup.addstr(height - 2, draw_x + 1, option_label, selection_format, curses.A_BOLD)
popup.addstr(height - 2, draw_x + len(option_label) + 1, "]")
draw_x -= 1 # space gap between the options
@@ -635,16 +635,16 @@ class ConfigPanel(panel.Panel):
entry = self._get_config_options()[line_number]
draw_line = line_number + detail_panel_height + 1 - scroll_location
- line_format = curses.A_NORMAL if entry.get(Field.IS_DEFAULT) else curses.A_BOLD
+ line_format = [curses.A_NORMAL if entry.get(Field.IS_DEFAULT) else curses.A_BOLD]
if entry.get(Field.CATEGORY):
- line_format |= ui_tools.get_color(CATEGORY_COLOR[entry.get(Field.CATEGORY)])
+ line_format += [CATEGORY_COLOR[entry.get(Field.CATEGORY)]]
if entry == cursor_selection:
- line_format |= curses.A_STANDOUT
+ line_format += [curses.A_STANDOUT]
line_text = entry.get_label(option_width, value_width, description_width)
- self.addstr(draw_line, scroll_offset, line_text, line_format)
+ self.addstr(draw_line, scroll_offset, line_text, *line_format)
if draw_line >= height:
break
@@ -667,13 +667,13 @@ class ConfigPanel(panel.Panel):
if is_scrollbar_visible:
self.addch(detail_panel_height, 1, curses.ACS_TTEE)
- selection_format = curses.A_BOLD | ui_tools.get_color(CATEGORY_COLOR[selection.get(Field.CATEGORY)])
+ selection_format = (curses.A_BOLD, CATEGORY_COLOR[selection.get(Field.CATEGORY)])
# first entry:
# <option> (<category> Option)
option_label = " (%s Option)" % selection.get(Field.CATEGORY)
- self.addstr(1, 2, selection.get(Field.OPTION) + option_label, selection_format)
+ self.addstr(1, 2, selection.get(Field.OPTION) + option_label, *selection_format)
# second entry:
# Value: <value> ([default|custom], <type>, usage: <argument usage>)
@@ -688,7 +688,7 @@ class ConfigPanel(panel.Panel):
value_label_width = width - 12 - len(value_attr_label)
value_label = ui_tools.crop_str(selection.get(Field.VALUE), value_label_width)
- self.addstr(2, 2, "Value: %s (%s)" % (value_label, value_attr_label), selection_format)
+ self.addstr(2, 2, "Value: %s (%s)" % (value_label, value_attr_label), *selection_format)
# remainder is filled with the man page description
@@ -723,4 +723,4 @@ class ConfigPanel(panel.Panel):
msg = ui_tools.crop_str(line_content, width - 3, 4, 4)
- self.addstr(3 + i, 2, msg, selection_format)
+ self.addstr(3 + i, 2, msg, *selection_format)
diff --git a/arm/connections/circ_entry.py b/arm/connections/circ_entry.py
index 0041a97..4e7b2d6 100644
--- a/arm/connections/circ_entry.py
+++ b/arm/connections/circ_entry.py
@@ -121,7 +121,7 @@ class CircHeaderLine(conn_entry.ConnectionLine):
def get_details(self, width):
if not self.is_built:
- detail_format = curses.A_BOLD | ui_tools.get_color(conn_entry.CATEGORY_COLOR[self.get_type()])
+ detail_format = (curses.A_BOLD, conn_entry.CATEGORY_COLOR[self.get_type()])
return [("Building Circuit...", detail_format)]
else:
return conn_entry.ConnectionLine.get_details(self, width)
@@ -170,7 +170,7 @@ class CircLine(conn_entry.ConnectionLine):
return entries.ConnectionPanelLine.get_listing_entry(self, width, current_time, listing_type)
def _get_listing_entry(self, width, current_time, listing_type):
- line_format = ui_tools.get_color(conn_entry.CATEGORY_COLOR[self.get_type()])
+ line_format = conn_entry.CATEGORY_COLOR[self.get_type()]
# The required widths are the sum of the following:
# initial space (1 character)
diff --git a/arm/connections/conn_entry.py b/arm/connections/conn_entry.py
index f3ec86c..cad2dbb 100644
--- a/arm/connections/conn_entry.py
+++ b/arm/connections/conn_entry.py
@@ -374,14 +374,14 @@ class ConnectionLine(entries.ConnectionPanelLine):
# category - "<type>"
# postType - ") "
- line_format = ui_tools.get_color(CATEGORY_COLOR[entry_type])
+ line_format = CATEGORY_COLOR[entry_type]
time_width = 6 if CONFIG["features.connection.markInitialConnections"] else 5
draw_entry = [(" ", line_format),
(self._get_listing_content(width - (12 + time_width) - 1, listing_type), line_format),
(" " * time_width, line_format),
(" (", line_format),
- (entry_type.upper(), line_format | curses.A_BOLD),
+ (entry_type.upper(), line_format, curses.A_BOLD),
(")" + " " * (9 - len(entry_type)), line_format)]
return draw_entry
@@ -395,7 +395,7 @@ class ConnectionLine(entries.ConnectionPanelLine):
width - available space to display in
"""
- detail_format = curses.A_BOLD | ui_tools.get_color(CATEGORY_COLOR[self.get_type()])
+ detail_format = (curses.A_BOLD, CATEGORY_COLOR[self.get_type()])
return [(line, detail_format) for line in self._get_detail_content(width)]
def reset_display(self):
diff --git a/arm/connections/conn_panel.py b/arm/connections/conn_panel.py
index 491c810..8168572 100644
--- a/arm/connections/conn_panel.py
+++ b/arm/connections/conn_panel.py
@@ -432,7 +432,7 @@ class ConnectionPanel(panel.Panel, threading.Thread):
draw_entries = cursor_selection.get_details(width)
for i in range(min(len(draw_entries), DETAILS_HEIGHT)):
- self.addstr(1 + i, 2, draw_entries[i][0], draw_entries[i][1])
+ self.addstr(1 + i, 2, draw_entries[i][0], *draw_entries[i][1])
# title label with connection counts
@@ -476,7 +476,7 @@ class ConnectionPanel(panel.Panel, threading.Thread):
for msg, attr in draw_entry:
attr |= extra_format
- self.addstr(draw_line, x_offset, msg, attr)
+ self.addstr(draw_line, x_offset, msg, *attr)
x_offset += len(msg)
if draw_line >= height:
diff --git a/arm/connections/count_popup.py b/arm/connections/count_popup.py
index b764c05..50fb7d8 100644
--- a/arm/connections/count_popup.py
+++ b/arm/connections/count_popup.py
@@ -55,7 +55,7 @@ def showCountDialog(count_type, counts):
popup.addstr(0, 0, title, curses.A_STANDOUT)
if is_no_stats:
- popup.addstr(1, 2, no_stats_msg, curses.A_BOLD | ui_tools.get_color("cyan"))
+ popup.addstr(1, 2, no_stats_msg, curses.A_BOLD, 'cyan')
else:
sorted_counts = sorted(counts.iteritems(), key=operator.itemgetter(1))
sorted_counts.reverse()
@@ -89,7 +89,7 @@ def showCountDialog(count_type, counts):
k = key_format % (k, usage[:EXIT_USAGE_WIDTH - 3])
label = label_format % (k, v, v * 100 / value_total)
- popup.addstr(i + 1, 2, label, curses.A_BOLD | ui_tools.get_color("green"))
+ popup.addstr(i + 1, 2, label, curses.A_BOLD, 'green')
# All labels have the same size since they're based on the max widths.
# If this changes then this'll need to be the max label width.
@@ -101,7 +101,7 @@ def showCountDialog(count_type, counts):
fill_width = v * (width - 4 - label_width) / value_total
for j in range(fill_width):
- popup.addstr(i + 1, 3 + label_width + j, " ", curses.A_STANDOUT | ui_tools.get_color("red"))
+ popup.addstr(i + 1, 3 + label_width + j, " ", curses.A_STANDOUT, 'red')
popup.addstr(height - 2, 2, "Press any key...")
diff --git a/arm/connections/descriptor_popup.py b/arm/connections/descriptor_popup.py
index 9404224..30adb6c 100644
--- a/arm/connections/descriptor_popup.py
+++ b/arm/connections/descriptor_popup.py
@@ -194,38 +194,37 @@ def draw(popup, fingerprint, display_text, display_color, scroll, show_line_numb
if show_line_number:
line_number_label = ("%%%ii" % line_number_width) % (i + 1)
- line_number_format = curses.A_BOLD | ui_tools.get_color(LINE_NUM_COLOR)
- popup.addstr(draw_line, x_offset, line_number_label, line_number_format)
+ popup.addstr(draw_line, x_offset, line_number_label, curses.A_BOLD, LINE_NUM_COLOR)
x_offset += line_number_width + 1
# Most consensus and descriptor lines are keyword/value pairs. Both are
# shown with the same color, but the keyword is bolded.
keyword, value = line_text, ""
- draw_format = ui_tools.get_color(display_color)
+ draw_format = display_color
if line_text.startswith(HEADER_PREFIX[0]) or line_text.startswith(HEADER_PREFIX[1]):
keyword, value = line_text, ""
- draw_format = ui_tools.get_color(HEADER_COLOR)
+ draw_format = HEADER_COLOR
elif line_text == UNRESOLVED_MSG or line_text == ERROR_MSG:
keyword, value = line_text, ""
elif line_text in SIG_START_KEYS:
keyword, value = line_text, ""
is_encryption_block = True
- draw_format = ui_tools.get_color(SIG_COLOR)
+ draw_format = SIG_COLOR
elif line_text in SIG_END_KEYS:
keyword, value = line_text, ""
is_encryption_block = False
- draw_format = ui_tools.get_color(SIG_COLOR)
+ draw_format = SIG_COLOR
elif is_encryption_block:
keyword, value = "", line_text
- draw_format = ui_tools.get_color(SIG_COLOR)
+ draw_format = SIG_COLOR
elif " " in line_text:
div_index = line_text.find(" ")
keyword, value = line_text[:div_index], line_text[div_index:]
- display_queue = [(keyword, draw_format | curses.A_BOLD), (value, draw_format)]
+ display_queue = [(keyword, (draw_format, curses.A_BOLD)), (value, (draw_format,))]
cursor_location = x_offset
while display_queue:
@@ -251,14 +250,14 @@ def draw(popup, fingerprint, display_text, display_color, scroll, show_line_numb
else:
remainder = ""
- popup.addstr(draw_line, cursor_location, msg, msg_format)
+ popup.addstr(draw_line, cursor_location, msg, *msg_format)
cursor_location = x_offset
if remainder:
display_queue.insert(0, (remainder.strip(), msg_format))
draw_line += 1
else:
- popup.addstr(draw_line, cursor_location, msg, msg_format)
+ popup.addstr(draw_line, cursor_location, msg, *msg_format)
cursor_location += len(msg)
if draw_line > page_height:
diff --git a/arm/graphing/bandwidth_stats.py b/arm/graphing/bandwidth_stats.py
index 6396873..634a0f5 100644
--- a/arm/graphing/bandwidth_stats.py
+++ b/arm/graphing/bandwidth_stats.py
@@ -307,8 +307,8 @@ class BandwidthStats(graph_panel.GraphStats):
primary_footer = "%s, %s" % (self._get_avg_label(True), self._get_total_label(True))
secondary_footer = "%s, %s" % (self._get_avg_label(False), self._get_total_label(False))
- panel.addstr(labeling_line, 1, primary_footer, ui_tools.get_color(self.get_color(True)))
- panel.addstr(labeling_line, graph_column + 6, secondary_footer, ui_tools.get_color(self.get_color(False)))
+ panel.addstr(labeling_line, 1, primary_footer, self.get_color(True))
+ panel.addstr(labeling_line, graph_column + 6, secondary_footer, self.get_color(False))
# provides accounting stats if enabled
@@ -327,7 +327,7 @@ class BandwidthStats(graph_panel.GraphStats):
status, hibernate_color = "unknown", "red"
panel.addstr(labeling_line + 2, 0, "Accounting (", curses.A_BOLD)
- panel.addstr(labeling_line + 2, 12, status, curses.A_BOLD | ui_tools.get_color(hibernate_color))
+ panel.addstr(labeling_line + 2, 12, status, curses.A_BOLD, hibernate_color)
panel.addstr(labeling_line + 2, 12 + len(status), ")", curses.A_BOLD)
reset_time = self.accounting_info["reset_time"]
@@ -340,12 +340,12 @@ class BandwidthStats(graph_panel.GraphStats):
used, total = self.accounting_info["read"], self.accounting_info["read_limit"]
if used and total:
- panel.addstr(labeling_line + 3, 2, "%s / %s" % (used, total), ui_tools.get_color(self.get_color(True)))
+ panel.addstr(labeling_line + 3, 2, "%s / %s" % (used, total), self.get_color(True))
used, total = self.accounting_info["written"], self.accounting_info["writtenLimit"]
if used and total:
- panel.addstr(labeling_line + 3, 37, "%s / %s" % (used, total), ui_tools.get_color(self.get_color(False)))
+ panel.addstr(labeling_line + 3, 37, "%s / %s" % (used, total), self.get_color(False))
else:
panel.addstr(labeling_line + 2, 0, "Accounting:", curses.A_BOLD)
panel.addstr(labeling_line + 2, 12, "Connection Closed...")
diff --git a/arm/graphing/graph_panel.py b/arm/graphing/graph_panel.py
index 41bd352..b54b8b8 100644
--- a/arm/graphing/graph_panel.py
+++ b/arm/graphing/graph_panel.py
@@ -435,8 +435,8 @@ class GraphPanel(panel.Panel):
param = self.get_attr("stats")[self.current_display]
graph_column = min((width - 10) / 2, param.max_column)
- primary_color = ui_tools.get_color(param.get_color(True))
- secondary_color = ui_tools.get_color(param.get_color(False))
+ primary_color = param.get_color(True)
+ secondary_color = param.get_color(False)
if self.is_title_visible():
self.addstr(0, 0, param.get_title(width), curses.A_STANDOUT)
@@ -446,10 +446,10 @@ class GraphPanel(panel.Panel):
left, right = param.get_header_label(width / 2, True), param.get_header_label(width / 2, False)
if left:
- self.addstr(1, 0, left, curses.A_BOLD | primary_color)
+ self.addstr(1, 0, left, curses.A_BOLD, primary_color)
if right:
- self.addstr(1, graph_column + 5, right, curses.A_BOLD | secondary_color)
+ self.addstr(1, graph_column + 5, right, curses.A_BOLD, secondary_color)
# determines max/min value on the graph
@@ -518,13 +518,13 @@ class GraphPanel(panel.Panel):
column_height = min(self.graph_height, self.graph_height * column_count / (max(1, primary_max_bound) - primary_min_bound))
for row in range(column_height):
- self.addstr(self.graph_height + 1 - row, col + 5, " ", curses.A_STANDOUT | primary_color)
+ self.addstr(self.graph_height + 1 - row, col + 5, " ", curses.A_STANDOUT, primary_color)
column_count = int(param.secondary_counts[self.update_interval][col + 1]) - secondary_min_bound
column_height = min(self.graph_height, self.graph_height * column_count / (max(1, secondary_max_bound) - secondary_min_bound))
for row in range(column_height):
- self.addstr(self.graph_height + 1 - row, col + graph_column + 10, " ", curses.A_STANDOUT | secondary_color)
+ self.addstr(self.graph_height + 1 - row, col + graph_column + 10, " ", curses.A_STANDOUT, secondary_color)
# bottom labeling of x-axis
diff --git a/arm/header_panel.py b/arm/header_panel.py
index ff862a8..d8dc8ad 100644
--- a/arm/header_panel.py
+++ b/arm/header_panel.py
@@ -18,11 +18,12 @@ import arm.controller
import arm.popups
import arm.starter
import arm.util.tracker
+import arm.util.ui_tools
from stem.control import Listener, State
from stem.util import conf, log
-from util import panel, ui_tools, tor_controller
+from util import panel, tor_controller
MIN_DUAL_COL_WIDTH = 141 # minimum width where we'll show two columns
SHOW_FD_THRESHOLD = 60 # show file descriptor usage if usage is over this percentage
@@ -201,7 +202,7 @@ class HeaderPanel(panel.Panel, threading.Thread):
version_color = CONFIG['attr.version_status_colors'].get(vals.version_status, 'white')
x = self.addstr(y, x, ' (')
- x = self.addstr(y, x, vals.version_status, ui_tools.get_color(version_color))
+ x = self.addstr(y, x, vals.version_status, version_color)
self.addstr(y, x, ')')
def _draw_ports_section(self, x, y, width, vals):
@@ -212,7 +213,7 @@ class HeaderPanel(panel.Panel, threading.Thread):
"""
if not vals.is_relay:
- x = self.addstr(y, x, 'Relaying Disabled', ui_tools.get_color('cyan'))
+ x = self.addstr(y, x, 'Relaying Disabled', 'cyan')
else:
x = self.addstr(y, x, vals.format('{nickname} - {or_address}:{or_port}'))
@@ -226,7 +227,7 @@ class HeaderPanel(panel.Panel, threading.Thread):
auth_color = 'red' if vals.auth_type == 'open' else 'green'
x = self.addstr(y, x, ', Control Port (')
- x = self.addstr(y, x, vals.auth_type, ui_tools.get_color(auth_color))
+ x = self.addstr(y, x, vals.auth_type, auth_color)
self.addstr(y, x, vals.format('): {control_port}'))
else:
self.addstr(y, x, ', Control Port: %s' % vals.control_port)
@@ -238,7 +239,7 @@ class HeaderPanel(panel.Panel, threading.Thread):
Tor Disconnected (15:21 07/13/2014, press r to reconnect)
"""
- x = self.addstr(y, x, 'Tor Disconnected', curses.A_BOLD | ui_tools.get_color('red'))
+ x = self.addstr(y, x, 'Tor Disconnected', curses.A_BOLD, 'red')
self.addstr(y, x, ' (%s, press r to reconnect)' % vals.last_heartbeat)
def _draw_resource_usage(self, x, y, width, vals):
@@ -291,17 +292,17 @@ class HeaderPanel(panel.Panel, threading.Thread):
if fd_percent >= SHOW_FD_THRESHOLD:
if fd_percent >= 95:
- percentage_format = curses.A_BOLD | ui_tools.get_color('red')
+ percentage_format = (curses.A_BOLD, 'red')
elif fd_percent >= 90:
- percentage_format = ui_tools.get_color('red')
+ percentage_format = ('red',)
elif fd_percent >= 60:
- percentage_format = ui_tools.get_color('yellow')
+ percentage_format = ('yellow',)
else:
- percentage_format = curses.A_NORMAL
+ percentage_format = ()
x = self.addstr(y, x, ', file descriptors' if space_left >= 37 else ', file desc')
x = self.addstr(y, x, vals.format(': {fd_used} / {fd_limit} ('))
- x = self.addstr(y, x, '%i%%' % fd_percent, percentage_format)
+ x = self.addstr(y, x, '%i%%' % fd_percent, *percentage_format)
self.addstr(y, x, ')')
def _draw_flags(self, x, y, width, vals):
@@ -316,12 +317,12 @@ class HeaderPanel(panel.Panel, threading.Thread):
if len(vals.flags) > 0:
for i, flag in enumerate(vals.flags):
flag_color = CONFIG['attr.flag_colors'].get(flag, 'white')
- x = self.addstr(y, x, flag, curses.A_BOLD | ui_tools.get_color(flag_color))
+ x = self.addstr(y, x, flag, curses.A_BOLD, flag_color)
if i < len(vals.flags) - 1:
x = self.addstr(y, x, ', ')
else:
- self.addstr(y, x, 'none', curses.A_BOLD | ui_tools.get_color('cyan'))
+ self.addstr(y, x, 'none', curses.A_BOLD, 'cyan')
def _draw_exit_policy(self, x, y, width, vals):
"""
@@ -342,7 +343,7 @@ class HeaderPanel(panel.Panel, threading.Thread):
for i, rule in enumerate(rules):
policy_color = 'green' if rule.is_accept else 'red'
- x = self.addstr(y, x, str(rule), curses.A_BOLD | ui_tools.get_color(policy_color))
+ x = self.addstr(y, x, str(rule), curses.A_BOLD, policy_color)
if i < len(rules) - 1:
x = self.addstr(y, x, ', ')
@@ -509,7 +510,7 @@ class Sampling(object):
formatted_msg = msg.format(**self.__dict__)
if crop_width:
- formatted_msg = ui_tools.crop_str(formatted_msg, crop_width)
+ formatted_msg = arm.util.ui_tools.crop_str(formatted_msg, crop_width)
return formatted_msg
diff --git a/arm/log_panel.py b/arm/log_panel.py
index e984938..e39c70f 100644
--- a/arm/log_panel.py
+++ b/arm/log_panel.py
@@ -967,7 +967,7 @@ class LogPanel(panel.Panel, threading.Thread, logging.Handler):
line_count = 1 - self.scroll
seen_first_date_divider = False
- divider_attr, duplicate_attr = curses.A_BOLD | ui_tools.get_color("yellow"), curses.A_BOLD | ui_tools.get_color("green")
+ divider_attr, duplicate_attr = (curses.A_BOLD, 'yellow'), (curses.A_BOLD, 'green')
is_dates_shown = self.regex_filter is None and CONFIG["features.log.showDateDividers"]
event_log = get_daybreaks(current_log, self.is_paused()) if is_dates_shown else list(current_log)
@@ -999,9 +999,9 @@ class LogPanel(panel.Panel, threading.Thread, logging.Handler):
if seen_first_date_divider:
if line_count >= 1 and line_count < height and show_daybreaks:
- self.addch(line_count, divider_indent, curses.ACS_LLCORNER, divider_attr)
- self.hline(line_count, divider_indent + 1, width - divider_indent - 2, divider_attr)
- self.addch(line_count, width - 1, curses.ACS_LRCORNER, divider_attr)
+ self.addch(line_count, divider_indent, curses.ACS_LLCORNER, *divider_attr)
+ self.hline(line_count, divider_indent + 1, width - divider_indent - 2, *divider_attr)
+ self.addch(line_count, width - 1, curses.ACS_LRCORNER, *divider_attr)
line_count += 1
@@ -1009,13 +1009,13 @@ class LogPanel(panel.Panel, threading.Thread, logging.Handler):
if line_count >= 1 and line_count < height and show_daybreaks:
time_label = time.strftime(" %B %d, %Y ", time.localtime(entry.timestamp))
- self.addch(line_count, divider_indent, curses.ACS_ULCORNER, divider_attr)
- self.addch(line_count, divider_indent + 1, curses.ACS_HLINE, divider_attr)
- self.addstr(line_count, divider_indent + 2, time_label, curses.A_BOLD | divider_attr)
+ self.addch(line_count, divider_indent, curses.ACS_ULCORNER, *divider_attr)
+ self.addch(line_count, divider_indent + 1, curses.ACS_HLINE, *divider_attr)
+ self.addstr(line_count, divider_indent + 2, time_label, curses.A_BOLD, *divider_attr)
line_length = width - divider_indent - len(time_label) - 3
- self.hline(line_count, divider_indent + len(time_label) + 2, line_length, divider_attr)
- self.addch(line_count, divider_indent + len(time_label) + 2 + line_length, curses.ACS_URCORNER, divider_attr)
+ self.hline(line_count, divider_indent + len(time_label) + 2, line_length, *divider_attr)
+ self.addch(line_count, divider_indent + len(time_label) + 2 + line_length, curses.ACS_URCORNER, *divider_attr)
seen_first_date_divider = True
line_count += 1
@@ -1029,7 +1029,7 @@ class LogPanel(panel.Panel, threading.Thread, logging.Handler):
for i in range(len(msg_comp)):
font = curses.A_BOLD if "ERR" in entry.type else curses.A_NORMAL # emphasizes ERR messages
- display_queue.append((msg_comp[i].strip(), font | ui_tools.get_color(entry.color), i != len(msg_comp) - 1))
+ display_queue.append((msg_comp[i].strip(), (font, entry.color), i != len(msg_comp) - 1))
if duplicate_count:
plural_label = "s" if duplicate_count > 1 else ""
@@ -1060,10 +1060,10 @@ class LogPanel(panel.Panel, threading.Thread, logging.Handler):
if draw_line < height and draw_line >= 1:
if seen_first_date_divider and width - divider_indent >= 3 and show_daybreaks:
- self.addch(draw_line, divider_indent, curses.ACS_VLINE, divider_attr)
- self.addch(draw_line, width - 1, curses.ACS_VLINE, divider_attr)
+ self.addch(draw_line, divider_indent, curses.ACS_VLINE, *divider_attr)
+ self.addch(draw_line, width - 1, curses.ACS_VLINE, *divider_attr)
- self.addstr(draw_line, cursor_location, msg, format)
+ self.addstr(draw_line, cursor_location, msg, *format)
cursor_location += len(msg)
@@ -1077,9 +1077,9 @@ class LogPanel(panel.Panel, threading.Thread, logging.Handler):
if not deduplicated_log and seen_first_date_divider:
if line_count < height and show_daybreaks:
- self.addch(line_count, divider_indent, curses.ACS_LLCORNER, divider_attr)
- self.hline(line_count, divider_indent + 1, width - divider_indent - 2, divider_attr)
- self.addch(line_count, width - 1, curses.ACS_LRCORNER, divider_attr)
+ self.addch(line_count, divider_indent, curses.ACS_LLCORNER, *divider_attr)
+ self.hline(line_count, divider_indent + 1, width - divider_indent - 2, *divider_attr)
+ self.addch(line_count, width - 1, curses.ACS_LRCORNER, *divider_attr)
line_count += 1
diff --git a/arm/menu/menu.py b/arm/menu/menu.py
index be705e5..435725b 100644
--- a/arm/menu/menu.py
+++ b/arm/menu/menu.py
@@ -178,12 +178,12 @@ def _draw_submenu(cursor, level, top, left):
for menu_item in submenu.get_children():
if menu_item == selection:
- draw_format = curses.A_BOLD | ui_tools.get_color("white")
+ draw_format = (curses.A_BOLD, 'white')
selection_top = draw_top
else:
- draw_format = curses.A_NORMAL
+ draw_format = (curses.A_NORMAL,)
- popup.addstr(draw_top, 0, label_format % menu_item.get_label(), draw_format)
+ popup.addstr(draw_top, 0, label_format % menu_item.get_label(), *draw_format)
draw_top += 1
popup.win.refresh()
diff --git a/arm/torrc_panel.py b/arm/torrc_panel.py
index e561478..a299ef9 100644
--- a/arm/torrc_panel.py
+++ b/arm/torrc_panel.py
@@ -239,10 +239,10 @@ class TorrcPanel(panel.Panel):
# splits the line into its component (msg, format) tuples
line_comp = {
- "option": ["", curses.A_BOLD | ui_tools.get_color("green")],
- "argument": ["", curses.A_BOLD | ui_tools.get_color("cyan")],
- "correction": ["", curses.A_BOLD | ui_tools.get_color("cyan")],
- "comment": ["", ui_tools.get_color("white")],
+ 'option': ['', (curses.A_BOLD, 'green')],
+ 'argument': ['', (curses.A_BOLD, 'cyan')],
+ 'correction': ['', (curses.A_BOLD, 'cyan')],
+ 'comment': ['', ('white',)],
}
# parses the comment
@@ -250,7 +250,7 @@ class TorrcPanel(panel.Panel):
comment_index = line_text.find("#")
if comment_index != -1:
- line_comp["comment"][0] = line_text[comment_index:]
+ line_comp['comment'][0] = line_text[comment_index:]
line_text = line_text[:comment_index]
# splits the option and argument, preserving any whitespace around them
@@ -261,15 +261,15 @@ class TorrcPanel(panel.Panel):
if is_multiline:
# part of a multiline entry started on a previous line so everything
# is part of the argument
- line_comp["argument"][0] = line_text
+ line_comp['argument'][0] = line_text
elif option_index == -1:
# no argument provided
- line_comp["option"][0] = line_text
+ line_comp['option'][0] = line_text
else:
option_text = stripped_line[:option_index]
option_end = line_text.find(option_text) + len(option_text)
- line_comp["option"][0] = line_text[:option_end]
- line_comp["argument"][0] = line_text[option_end:]
+ line_comp['option'][0] = line_text[:option_end]
+ line_comp['argument'][0] = line_text[option_end:]
# flags following lines as belonging to this multiline entry if it ends
# with a slash
@@ -283,29 +283,29 @@ class TorrcPanel(panel.Panel):
line_issue, line_issue_msg = corrections[line_number]
if line_issue in (tor_config.ValidationError.DUPLICATE, tor_config.ValidationError.IS_DEFAULT):
- line_comp["option"][1] = curses.A_BOLD | ui_tools.get_color("blue")
- line_comp["argument"][1] = curses.A_BOLD | ui_tools.get_color("blue")
+ line_comp['option'][1] = (curses.A_BOLD, 'blue')
+ line_comp['argument'][1] = (curses.A_BOLD, 'blue')
elif line_issue == tor_config.ValidationError.MISMATCH:
- line_comp["argument"][1] = curses.A_BOLD | ui_tools.get_color("red")
- line_comp["correction"][0] = " (%s)" % line_issue_msg
+ line_comp['argument'][1] = (curses.A_BOLD, 'red')
+ line_comp['correction'][0] = ' (%s)' % line_issue_msg
else:
# For some types of configs the correction field is simply used to
# provide extra data (for instance, the type for tor state fields).
- line_comp["correction"][0] = " (%s)" % line_issue_msg
- line_comp["correction"][1] = curses.A_BOLD | ui_tools.get_color("magenta")
+ line_comp['correction'][0] = ' (%s)' % line_issue_msg
+ line_comp['correction'][1] = (curses.A_BOLD, 'magenta')
# draws the line number
if self.show_line_num and display_line < height and display_line >= 1:
line_number_str = ("%%%ii" % (line_number_offset - 1)) % (line_number + 1)
- self.addstr(display_line, scroll_offset, line_number_str, curses.A_BOLD | ui_tools.get_color("yellow"))
+ self.addstr(display_line, scroll_offset, line_number_str, curses.A_BOLD, 'yellow')
# draws the rest of the components with line wrap
cursor_location, line_offset = line_number_offset + scroll_offset, 0
max_lines_per_entry = CONFIG["features.config.file.max_lines_per_entry"]
- display_queue = [line_comp[entry] for entry in ("option", "argument", "correction", "comment")]
+ display_queue = [line_comp[entry] for entry in ('option', 'argument', 'correction', 'comment')]
while display_queue:
msg, format = display_queue.pop(0)
@@ -325,7 +325,7 @@ class TorrcPanel(panel.Panel):
draw_line = display_line + line_offset
if msg and draw_line < height and draw_line >= 1:
- self.addstr(draw_line, cursor_location, msg, format)
+ self.addstr(draw_line, cursor_location, msg, *format)
# If we're done, and have added content to this line, then start
# further content on the next line.
diff --git a/arm/util/panel.py b/arm/util/panel.py
index 33cff32..d68268a 100644
--- a/arm/util/panel.py
+++ b/arm/util/panel.py
@@ -489,7 +489,7 @@ class Panel():
# in edge cases drawing could cause a _curses.error
pass
- def addstr(self, y, x, msg, attr=curses.A_NORMAL):
+ def addstr(self, y, x, msg, *attributes):
"""
Writes string to subwindow if able. This takes into account screen bounds
to avoid making curses upset. This should only be called from the context
@@ -502,13 +502,21 @@ class Panel():
attr - text attributes
"""
+ format_attr = curses.A_NORMAL
+
+ for attr in attributes:
+ if isinstance(attr, str):
+ format_attr |= ui_tools.get_color(attr)
+ else:
+ format_attr |= attr
+
# subwindows need a single character buffer (either in the x or y
# direction) from actual content to prevent crash when shrank
if self.win and self.max_x > x and self.max_y > y:
try:
drawn_msg = msg[:self.max_x - x]
- self.win.addstr(y, x, drawn_msg, attr)
+ self.win.addstr(y, x, drawn_msg, format_attr)
return x + len(drawn_msg)
except:
# this might produce a _curses.error during edge cases, for instance
1
0
commit cdd4e47affe863cd82c54eca097ce5bb25dbef3b
Author: Damian Johnson <atagar(a)torproject.org>
Date: Wed Aug 27 09:21:19 2014 -0700
Stylistic issues from pep8 1.5.7
Fixing issues spotted by the new release of pep8.
---
arm/config_panel.py | 4 +--
arm/connections/circ_entry.py | 2 +-
arm/connections/conn_entry.py | 20 +++++------
arm/graphing/bandwidth_stats.py | 2 +-
arm/graphing/graph_panel.py | 4 +--
arm/header_panel.py | 70 +++++++++++++++++++--------------------
arm/log_panel.py | 4 +--
arm/popups.py | 2 +-
arm/util/panel.py | 2 +-
arm/util/tor_config.py | 14 ++++----
10 files changed, 62 insertions(+), 62 deletions(-)
diff --git a/arm/config_panel.py b/arm/config_panel.py
index 84f7f3a..dabe078 100644
--- a/arm/config_panel.py
+++ b/arm/config_panel.py
@@ -279,7 +279,7 @@ class ConfigPanel(panel.Panel):
elif not CONFIG["features.config.state.showVirtualOptions"] and conf_type == "Virtual":
continue
- self.conf_contents.append(ConfigEntry(conf_option, conf_type, not conf_option in custom_options))
+ self.conf_contents.append(ConfigEntry(conf_option, conf_type, conf_option not in custom_options))
elif self.config_type == State.ARM:
# loaded via the conf utility
@@ -416,7 +416,7 @@ class ConfigPanel(panel.Panel):
# resets the is_default flag
custom_options = tor_config.get_custom_options()
- selection.fields[Field.IS_DEFAULT] = not config_option in custom_options
+ selection.fields[Field.IS_DEFAULT] = config_option not in custom_options
self.redraw(True)
except Exception as exc:
diff --git a/arm/connections/circ_entry.py b/arm/connections/circ_entry.py
index 7f9c47b..0041a97 100644
--- a/arm/connections/circ_entry.py
+++ b/arm/connections/circ_entry.py
@@ -231,7 +231,7 @@ def get_relay_address(controller, relay_fingerprint, default = None):
if controller.is_alive():
# query the address if it isn't yet cached
- if not relay_fingerprint in ADDRESS_LOOKUP_CACHE:
+ if relay_fingerprint not in ADDRESS_LOOKUP_CACHE:
if relay_fingerprint == controller.get_info("fingerprint", None):
# this is us, simply check the config
my_address = controller.get_info("address", None)
diff --git a/arm/connections/conn_entry.py b/arm/connections/conn_entry.py
index 62c01f3..f3ec86c 100644
--- a/arm/connections/conn_entry.py
+++ b/arm/connections/conn_entry.py
@@ -114,14 +114,14 @@ class Endpoint:
"""
# TODO: skipping all hostname resolution to be safe for now
- #try:
- # myHostname = hostnames.resolve(self.address)
- #except:
- # # either a ValueError or IOError depending on the source of the lookup failure
- # myHostname = None
+ # try:
+ # myHostname = hostnames.resolve(self.address)
+ # except:
+ # # either a ValueError or IOError depending on the source of the lookup failure
+ # myHostname = None
#
- #if not myHostname: return default
- #else: return myHostname
+ # if not myHostname: return default
+ # else: return myHostname
return default
@@ -652,7 +652,7 @@ class ConnectionLine(entries.ConnectionPanelLine):
# the source and destination addresses are both private, but that might
# not be perfectly reliable either.
- is_expansion_type = not my_type in (Category.SOCKS, Category.HIDDEN, Category.CONTROL)
+ is_expansion_type = my_type not in (Category.SOCKS, Category.HIDDEN, Category.CONTROL)
if is_expansion_type:
src_address = my_external_address + local_port
@@ -1143,7 +1143,7 @@ class FingerprintTracker:
result = []
else:
# query the fingerprint if it isn't yet cached
- if not (relay_address, relay_port) in self._fingerprint_lookup_cache:
+ if (relay_address, relay_port) not in self._fingerprint_lookup_cache:
relay_fingerprint = self._get_relay_fingerprint(controller, relay_address, relay_port)
self._fingerprint_lookup_cache[(relay_address, relay_port)] = relay_fingerprint
@@ -1165,7 +1165,7 @@ class FingerprintTracker:
if controller.is_alive():
# query the nickname if it isn't yet cached
- if not relay_fingerprint in self._nickname_lookup_cache:
+ if relay_fingerprint not in self._nickname_lookup_cache:
if relay_fingerprint == controller.get_info("fingerprint", None):
# this is us, simply check the config
my_nickname = controller.get_conf("Nickname", "Unnamed")
diff --git a/arm/graphing/bandwidth_stats.py b/arm/graphing/bandwidth_stats.py
index 1fffa4a..6396873 100644
--- a/arm/graphing/bandwidth_stats.py
+++ b/arm/graphing/bandwidth_stats.py
@@ -167,7 +167,7 @@ class BandwidthStats(graph_panel.GraphStats):
# the state tracks a day's worth of data and this should only prepopulate
# results associated with this tor instance
- if not uptime or not "-" in uptime:
+ if not uptime or "-" not in uptime:
msg = PREPOPULATE_FAILURE_MSG % "insufficient uptime"
log.notice(msg)
return False
diff --git a/arm/graphing/graph_panel.py b/arm/graphing/graph_panel.py
index f36b090..41bd352 100644
--- a/arm/graphing/graph_panel.py
+++ b/arm/graphing/graph_panel.py
@@ -502,13 +502,13 @@ class GraphPanel(panel.Panel):
if primary_min_bound != primary_max_bound:
primary_val = (primary_max_bound - primary_min_bound) * (self.graph_height - row - 1) / (self.graph_height - 1)
- if not primary_val in (primary_min_bound, primary_max_bound):
+ if primary_val not in (primary_min_bound, primary_max_bound):
self.addstr(row + 2, 0, "%4i" % primary_val, primary_color)
if secondary_min_bound != secondary_max_bound:
secondary_val = (secondary_max_bound - secondary_min_bound) * (self.graph_height - row - 1) / (self.graph_height - 1)
- if not secondary_val in (secondary_min_bound, secondary_max_bound):
+ if secondary_val not in (secondary_min_bound, secondary_max_bound):
self.addstr(row + 2, graph_column + 5, "%4i" % secondary_val, secondary_color)
# creates bar graph (both primary and secondary)
diff --git a/arm/header_panel.py b/arm/header_panel.py
index 841100f..e16f98c 100644
--- a/arm/header_panel.py
+++ b/arm/header_panel.py
@@ -97,46 +97,46 @@ class HeaderPanel(panel.Panel, threading.Thread):
if key in (ord('n'), ord('N')) and tor_controller().is_newnym_available():
self.send_newnym()
elif key in (ord('r'), ord('R')) and not self.vals.is_connected:
- #oldSocket = tor_tools.get_conn().get_controller().get_socket()
+ # oldSocket = tor_tools.get_conn().get_controller().get_socket()
#
- #controller = None
- #allowPortConnection, allowSocketConnection, _ = starter.allowConnectionTypes()
+ # controller = None
+ # allowPortConnection, allowSocketConnection, _ = starter.allowConnectionTypes()
#
- #if os.path.exists(CONFIG["startup.interface.socket"]) and allowSocketConnection:
- # try:
- # # TODO: um... what about passwords?
- # controller = Controller.from_socket_file(CONFIG["startup.interface.socket"])
- # controller.authenticate()
- # except (IOError, stem.SocketError), exc:
- # controller = None
+ # if os.path.exists(CONFIG["startup.interface.socket"]) and allowSocketConnection:
+ # try:
+ # # TODO: um... what about passwords?
+ # controller = Controller.from_socket_file(CONFIG["startup.interface.socket"])
+ # controller.authenticate()
+ # except (IOError, stem.SocketError), exc:
+ # controller = None
#
- # if not allowPortConnection:
- # arm.popups.show_msg("Unable to reconnect (%s)" % exc, 3)
- #elif not allowPortConnection:
- # arm.popups.show_msg("Unable to reconnect (socket '%s' doesn't exist)" % CONFIG["startup.interface.socket"], 3)
+ # if not allowPortConnection:
+ # arm.popups.show_msg("Unable to reconnect (%s)" % exc, 3)
+ # elif not allowPortConnection:
+ # arm.popups.show_msg("Unable to reconnect (socket '%s' doesn't exist)" % CONFIG["startup.interface.socket"], 3)
#
- #if not controller and allowPortConnection:
- # # TODO: This has diverged from starter.py's connection, for instance it
- # # doesn't account for relative cookie paths or multiple authentication
- # # methods. We can't use the starter.py's connection function directly
- # # due to password prompts, but we could certainly make this mess more
- # # manageable.
+ # if not controller and allowPortConnection:
+ # # TODO: This has diverged from starter.py's connection, for instance it
+ # # doesn't account for relative cookie paths or multiple authentication
+ # # methods. We can't use the starter.py's connection function directly
+ # # due to password prompts, but we could certainly make this mess more
+ # # manageable.
#
- # try:
- # ctlAddr, ctl_port = CONFIG["startup.interface.ip_address"], CONFIG["startup.interface.port"]
- # controller = Controller.from_port(ctlAddr, ctl_port)
+ # try:
+ # ctlAddr, ctl_port = CONFIG["startup.interface.ip_address"], CONFIG["startup.interface.port"]
+ # controller = Controller.from_port(ctlAddr, ctl_port)
#
- # try:
- # controller.authenticate()
- # except stem.connection.MissingPassword:
- # controller.authenticate(authValue) # already got the password above
- # except Exception, exc:
- # controller = None
+ # try:
+ # controller.authenticate()
+ # except stem.connection.MissingPassword:
+ # controller.authenticate(authValue) # already got the password above
+ # except Exception, exc:
+ # controller = None
#
- #if controller:
- # tor_tools.get_conn().init(controller)
- # log.notice("Reconnected to Tor's control port")
- # arm.popups.show_msg("Tor reconnected", 1)
+ # if controller:
+ # tor_tools.get_conn().init(controller)
+ # log.notice("Reconnected to Tor's control port")
+ # arm.popups.show_msg("Tor reconnected", 1)
pass
else:
@@ -388,8 +388,8 @@ class HeaderPanel(panel.Panel, threading.Thread):
is_changed = False
if self.vals.pid:
- #resource_tracker = arm.util.tracker.get_resource_tracker()
- #is_changed = self._last_resource_fetch != resource_tracker.run_counter()
+ # resource_tracker = arm.util.tracker.get_resource_tracker()
+ # is_changed = self._last_resource_fetch != resource_tracker.run_counter()
is_changed = True # TODO: we should decide to redraw or not based on if the sampling values have changed
if is_changed or (self.vals and current_time - self.vals.retrieved >= 20):
diff --git a/arm/log_panel.py b/arm/log_panel.py
index f782e6b..e984938 100644
--- a/arm/log_panel.py
+++ b/arm/log_panel.py
@@ -635,7 +635,7 @@ class LogPanel(panel.Panel, threading.Thread, logging.Handler):
color = "magenta"
elif isinstance(event, events.GuardEvent):
color = "yellow"
- elif not event.type in arm.arguments.TOR_EVENT_TYPES.values():
+ elif event.type not in arm.arguments.TOR_EVENT_TYPES.values():
color = "red" # unknown event type
self.register_event(LogEntry(event.arrived_at, event.type, msg, color))
@@ -648,7 +648,7 @@ class LogPanel(panel.Panel, threading.Thread, logging.Handler):
event - LogEntry for the event that occurred
"""
- if not event.type in self.logged_events:
+ if event.type not in self.logged_events:
return
# strips control characters to avoid screwing up the terminal
diff --git a/arm/popups.py b/arm/popups.py
index be07336..59cf40a 100644
--- a/arm/popups.py
+++ b/arm/popups.py
@@ -179,7 +179,7 @@ def show_help_popup():
if not ui_tools.is_selection_key(exit_key) and \
not ui_tools.is_scroll_key(exit_key) and \
- not exit_key in (curses.KEY_LEFT, curses.KEY_RIGHT):
+ exit_key not in (curses.KEY_LEFT, curses.KEY_RIGHT):
return exit_key
else:
return None
diff --git a/arm/util/panel.py b/arm/util/panel.py
index 99723b0..33cff32 100644
--- a/arm/util/panel.py
+++ b/arm/util/panel.py
@@ -185,7 +185,7 @@ class Panel():
attr - local variable to be returned
"""
- if not attr in self.pause_attr:
+ if attr not in self.pause_attr:
return None
elif self.paused:
return self.pause_buffer[attr]
diff --git a/arm/util/tor_config.py b/arm/util/tor_config.py
index 33b53a3..32d0b07 100644
--- a/arm/util/tor_config.py
+++ b/arm/util/tor_config.py
@@ -183,7 +183,7 @@ def load_option_descriptions(load_path = None, check_version = True):
# gets category enum, failing if it doesn't exist
category = input_file_contents.pop(0).rstrip()
- if not category in Category:
+ if category not in Category:
base_msg = "invalid category in input file: '%s'"
raise IOError(base_msg % category)
@@ -241,7 +241,7 @@ def load_option_descriptions(load_path = None, check_version = True):
stripped_line = line.strip()
# we have content, but an indent less than an option (ignore line)
- #if stripped_line and not line.startswith(" " * MAN_OPT_INDENT): continue
+ # if stripped_line and not line.startswith(" " * MAN_OPT_INDENT): continue
# line starts with an indent equivilant to a new config option
@@ -681,7 +681,7 @@ def validate(contents = None):
# most parameters are overwritten if defined multiple times
- if option in seen_options and not option in get_multiline_parameters():
+ if option in seen_options and option not in get_multiline_parameters():
issues_found.append((line_number, ValidationError.DUPLICATE, option))
continue
else:
@@ -689,7 +689,7 @@ def validate(contents = None):
# checks if the value isn't necessary due to matching the defaults
- if not option in custom_options:
+ if option not in custom_options:
issues_found.append((line_number, ValidationError.IS_DEFAULT, option))
# replace aliases with their recognized representation
@@ -722,7 +722,7 @@ def validate(contents = None):
for fetched_entry in fetched_value.split(","):
fetched_entry = fetched_entry.strip()
- if not fetched_entry in tor_values:
+ if fetched_entry not in tor_values:
tor_values.append(fetched_entry)
for val in value_list:
@@ -730,7 +730,7 @@ def validate(contents = None):
is_blank_match = not val and not tor_values
- if not is_blank_match and not val in tor_values:
+ if not is_blank_match and val not in tor_values:
# converts corrections to reader friedly size values
display_values = tor_values
@@ -754,7 +754,7 @@ def validate(contents = None):
if option == "DirReqStatistics":
continue
- if not option in seen_options:
+ if option not in seen_options:
issues_found.append((None, ValidationError.MISSING, option))
return issues_found
1
0
commit 7b42ae7c492a327437903e59244cbd8647c5b273
Author: Damian Johnson <atagar(a)torproject.org>
Date: Sat Aug 30 19:01:08 2014 -0700
Dropping addtstr() helper
I prefer to avoid helper functions unless they add a fair bit of readability
(otherwise they just obscure things). The header panel's addtstr() helper was
only used in three spots so replacing it.
---
arm/header_panel.py | 29 ++++++++++++++++-------------
1 file changed, 16 insertions(+), 13 deletions(-)
diff --git a/arm/header_panel.py b/arm/header_panel.py
index e16f98c..82f8ae1 100644
--- a/arm/header_panel.py
+++ b/arm/header_panel.py
@@ -71,7 +71,7 @@ class HeaderPanel(panel.Panel, threading.Thread):
is_wide = self.get_parent().getmaxyx()[1] >= MIN_DUAL_COL_WIDTH
- if self.vals.or_port:
+ if self.vals.is_relay:
return 4 if is_wide else 6
else:
return 3 if is_wide else 4
@@ -144,12 +144,8 @@ class HeaderPanel(panel.Panel, threading.Thread):
return is_keystroke_consumed
- def addtstr(self, y, x, msg, space_left, attr=curses.A_NORMAL):
- cursor_position = self.addstr(y, x, ui_tools.crop_str(msg, space_left), attr)
- return cursor_position, space_left - (cursor_position - x)
-
def draw(self, width, height):
- vals = self.vals
+ vals = self.vals # local reference to avoid concurrency concerns
is_wide = width + 1 >= MIN_DUAL_COL_WIDTH
# space available for content
@@ -169,7 +165,7 @@ class HeaderPanel(panel.Panel, threading.Thread):
else:
self._draw_resource_usage(0, 2, left_width, vals)
- if vals.or_port:
+ if vals.is_relay:
if is_wide:
self._draw_fingerprint_and_fd_usage(left_width, 1, right_width, vals)
self._draw_flags(0, 2, left_width, vals)
@@ -188,16 +184,19 @@ class HeaderPanel(panel.Panel, threading.Thread):
|------ platform (40 characters) ------| |----------- tor version -----------|
"""
- space_left = min(width, 40)
- x, space_left = self.addtstr(y, x, vals.format('arm - {hostname}'), space_left)
+ initial_x, space_left = x, min(width, 40)
+
+ x = self.addstr(y, x, ui_tools.crop_str(vals.format('arm - {hostname}'), space_left))
+ space_left -= x - initial_x
if space_left >= 10:
self.addstr(y, x, ' (%s)' % ui_tools.crop_str(vals.platform, space_left - 3, 4))
- x, space_left = 43, width - 43
+ x, space_left = initial_x + 43, width - 43
if vals.version != 'Unknown' and space_left >= 10:
- x, space_left = self.addtstr(y, x, vals.format('Tor {version}'), space_left)
+ x = self.addstr(y, x, ui_tools.crop_str(vals.format('Tor {version}'), space_left))
+ space_left -= x - 43 - initial_x
if space_left >= 7 + len(vals.version_status):
version_color = CONFIG['attr.version_status_colors'].get(vals.version_status, 'white')
@@ -213,7 +212,7 @@ class HeaderPanel(panel.Panel, threading.Thread):
Unnamed - 0.0.0.0:7000, Control Port (cookie): 9051
"""
- if not vals.or_port:
+ if not vals.is_relay:
x = self.addstr(y, x, 'Relaying Disabled', ui_tools.get_color('cyan'))
else:
x = self.addstr(y, x, vals.format('{nickname} - {or_address}:{or_port}'))
@@ -283,7 +282,10 @@ class HeaderPanel(panel.Panel, threading.Thread):
fingerprint: 1A94D1A794FCB2F8B6CBC179EF8FDD4008A98D3B, file desc: 900 / 1000 (90%)
"""
- x, space_left = self.addtstr(y, x, vals.format('fingerprint: {fingerprint}'), width)
+ initial_x, space_left = x, width
+
+ x = self.addstr(y, x, ui_tools.crop_str(vals.format('fingerprint: {fingerprint}'), width))
+ space_left -= x - initial_x
if space_left >= 30 and vals.fd_used and vals.fd_limit:
fd_percent = 100 * vals.fd_used / vals.fd_limit
@@ -474,6 +476,7 @@ class Sampling(object):
self.dir_port = controller.get_conf('DirPort', '0')
self.control_port = controller.get_conf('ControlPort', '0')
self.socket_path = controller.get_conf('ControlSocket', '')
+ self.is_relay = bool(self.or_port)
if controller.get_conf('HashedControlPassword', None):
self.auth_type = 'password'
1
0
commit 28f4f4bc987ad098e3237906df0a55e433fa1d14
Author: Damian Johnson <atagar(a)torproject.org>
Date: Sun Aug 31 17:02:43 2014 -0700
Adding crop() method to our str_tools
Method from arm's ui_tools with a little cleanup. This is a pretty delicate
method and I'm a tad worried about some changes so we might see some regression
from what arm had. That said, regressions can easily be added to our unit tests
(it'll be soooo nice to finally have those for this helper....).
---
docs/change_log.rst | 1 +
stem/util/enum.py | 6 +--
stem/util/str_tools.py | 120 +++++++++++++++++++++++++++++++++++++++++++
test/unit/doctest.py | 1 +
test/unit/util/str_tools.py | 6 +++
5 files changed, 131 insertions(+), 3 deletions(-)
diff --git a/docs/change_log.rst b/docs/change_log.rst
index 4ec16a0..0e605ca 100644
--- a/docs/change_log.rst
+++ b/docs/change_log.rst
@@ -49,6 +49,7 @@ The following are only available within Stem's `git repository
* Added support for directories to :func:`stem.util.conf.Config.load`.
* Changed :func:`stem.util.conf.uses_settings` to only provide a 'config' keyword arument if the decorated function would accept it.
+ * Added :func:`stem.util.str_tools.crop`
* **Interpreter**
diff --git a/stem/util/enum.py b/stem/util/enum.py
index 4a86fc5..473f0de 100644
--- a/stem/util/enum.py
+++ b/stem/util/enum.py
@@ -40,8 +40,6 @@ constructed as simple type listings...
+- __iter__ - iterator over our enum keys
"""
-import stem.util.str_tools
-
def UppercaseEnum(*args):
"""
@@ -70,12 +68,14 @@ class Enum(object):
"""
def __init__(self, *args):
+ from stem.util.str_tools import _to_camel_case
+
# ordered listings of our keys and values
keys, values = [], []
for entry in args:
if isinstance(entry, (bytes, unicode)):
- key, val = entry, stem.util.str_tools._to_camel_case(entry)
+ key, val = entry, _to_camel_case(entry)
elif isinstance(entry, tuple) and len(entry) == 2:
key, val = entry
else:
diff --git a/stem/util/str_tools.py b/stem/util/str_tools.py
index 4b5ccca..e166a4c 100644
--- a/stem/util/str_tools.py
+++ b/stem/util/str_tools.py
@@ -8,6 +8,8 @@ Toolkit for various string activity.
::
+ crop - shortens string to a given length
+
get_size_label - human readable label for a number of bytes
get_time_label - human readable label for a number of seconds
get_time_labels - human readable labels for each time unit
@@ -17,8 +19,11 @@ Toolkit for various string activity.
import codecs
import datetime
+import sys
import stem.prereq
+import stem.util.enum
+
# label conversion tuples of the form...
# (bits / bytes / seconds, short label, long label)
@@ -131,6 +136,121 @@ def _to_camel_case(label, divider = '_', joiner = ' '):
return joiner.join(words)
+# This needs to be defined after _to_camel_case() to avoid a circular
+# dependency with the enum module.
+
+Ending = stem.util.enum.Enum('ELLIPSE', 'HYPHEN')
+
+
+def crop(msg, size, min_word_length = 4, min_crop = 0, ending = Ending.ELLIPSE, get_remainder = False):
+ """
+ Shortens a string to a given length.
+
+ If we crop content then a given ending is included (counting itself toward
+ the size limitation). This crops on word breaks so we only include a word if
+ we can display at least **min_word_length** characters of it.
+
+ If there isn't room for even a truncated single word (or one word plus the
+ ellipse if including those) then this provides an empty string.
+
+ If a cropped string ends with a comma or period then it's stripped (unless
+ we're providing the remainder back). For example...
+
+ >>> crop('This is a looooong message', 17)
+ 'This is a looo...'
+
+ >>> crop('This is a looooong message', 12)
+ 'This is a...'
+
+ >>> crop('This is a looooong message', 3)
+ ''
+
+ The whole point of this method is to provide human friendly croppings, and as
+ such details of how this works might change in the future. Callers should not
+ rely on the details of how this crops.
+
+ :param str msg: text to be processed
+ :param int size: space available for text
+ :param int min_word_length: minimum characters before which a word is
+ dropped, requires whole word if **None**
+ :param int min_crop: minimum characters that must be dropped if a word is
+ cropped
+ :param Ending ending: type of ending used when truncating, no special
+ truncation is used if **None**
+ :param bool get_remainder: returns a tuple with the second part being the
+ cropped portion of the message
+
+ :returns: **str** of the text truncated to the given length
+ """
+
+ # checks if there's room for the whole message
+
+ if len(msg) <= size:
+ return (msg, '') if get_remainder else msg
+
+ if size < 0:
+ raise ValueError("Crop size can't be negative (received %i)" % size)
+ elif min_word_length and min_word_length < 0:
+ raise ValueError("Crop's min_word_length can't be negative (received %i)" % min_word_length)
+ elif min_crop < 0:
+ raise ValueError("Crop's min_crop can't be negative (received %i)" % min_crop)
+
+ # since we're cropping, the effective space available is less with an
+ # ellipse, and cropping words requires an extra space for hyphens
+
+ if ending == Ending.ELLIPSE:
+ size -= 3
+ elif min_word_length and ending == Ending.HYPHEN:
+ min_word_length += 1
+
+ if min_word_length is None:
+ min_word_length = sys.maxint
+
+ # checks if there isn't the minimum space needed to include anything
+
+ last_wordbreak = msg.rfind(' ', 0, size + 1)
+
+ if last_wordbreak == -1:
+ # we're splitting the first word
+
+ if size < min_word_length:
+ return ('', msg) if get_remainder else ''
+
+ include_crop = True
+ else:
+ last_wordbreak = len(msg[:last_wordbreak].rstrip()) # drops extra ending whitespaces
+ include_crop = size - last_wordbreak - 1 >= min_word_length
+
+ # if there's a max crop size then make sure we're cropping at least that many characters
+
+ if include_crop and min_crop:
+ next_wordbreak = msg.find(' ', size)
+
+ if next_wordbreak == -1:
+ next_wordbreak = len(msg)
+
+ include_crop = next_wordbreak - size + 1 >= min_crop
+
+ if include_crop:
+ return_msg, remainder = msg[:size], msg[size:]
+
+ if ending == Ending.HYPHEN:
+ remainder = return_msg[-1] + remainder
+ return_msg = return_msg[:-1].rstrip() + '-'
+ else:
+ return_msg, remainder = msg[:last_wordbreak], msg[last_wordbreak:]
+
+ # if this is ending with a comma or period then strip it off
+
+ if not get_remainder and return_msg and return_msg[-1] in (',', '.'):
+ return_msg = return_msg[:-1]
+
+ if ending == Ending.ELLIPSE:
+ return_msg = return_msg.rstrip() + '...'
+
+ return (return_msg, remainder) if get_remainder else return_msg
+
+
def get_size_label(byte_count, decimal = 0, is_long = False, is_bytes = True):
"""
Converts a number of bytes into a human readable label in its most
diff --git a/test/unit/doctest.py b/test/unit/doctest.py
index 4692dd6..1c7c415 100644
--- a/test/unit/doctest.py
+++ b/test/unit/doctest.py
@@ -59,6 +59,7 @@ class TestDocumentation(unittest.TestCase):
elif path.endswith('/stem/util/str_tools.py'):
args['globs'] = {
'_to_camel_case': stem.util.str_tools._to_camel_case,
+ 'crop': stem.util.str_tools.crop,
'get_size_label': stem.util.str_tools.get_size_label,
'get_time_label': stem.util.str_tools.get_time_label,
'get_time_labels': stem.util.str_tools.get_time_labels,
diff --git a/test/unit/util/str_tools.py b/test/unit/util/str_tools.py
index 82d5a97..7abdedf 100644
--- a/test/unit/util/str_tools.py
+++ b/test/unit/util/str_tools.py
@@ -25,6 +25,12 @@ class TestStrTools(unittest.TestCase):
self.assertEquals('Hello\tworld', str_tools._to_camel_case('hello\tWORLD'))
self.assertEquals('Hello\t\tWorld', str_tools._to_camel_case('hello__world', '_', '\t'))
+ def test_crop(self):
+ # test the pydoc examples
+ self.assertEquals('This is a looo...', str_tools.crop('This is a looooong message', 17))
+ self.assertEquals('This is a...', str_tools.crop('This is a looooong message', 12))
+ self.assertEquals('', str_tools.crop('This is a looooong message', 3))
+
def test_get_size_label(self):
"""
Checks the get_size_label() function.
1
0