Commit Graph

6293 Commits

Author SHA1 Message Date
Itamar Turner-Trauring
8e618b9383 Fix Python 2 issue. 2020-10-16 11:25:29 -04:00
Itamar Turner-Trauring
6aa96bbb8d Port test_node.py to Python 3. 2020-10-16 11:23:38 -04:00
Itamar Turner-Trauring
f7a89f76e7 All tests pass on Python 3. 2020-10-16 11:20:10 -04:00
Itamar Turner-Trauring
51d472e221 More progress towards passing tests on Python 3. 2020-10-16 11:13:11 -04:00
Itamar Turner-Trauring
f689d59a40 More passing tests on Python 3. 2020-10-16 10:55:33 -04:00
Itamar Turner-Trauring
bcd7cdf86f Some passing tests on Python 3. 2020-10-16 10:47:49 -04:00
Itamar Turner-Trauring
c2fe5a65a6
Merge pull request #847 from tahoe-lafs/3459.test-checker-python-3
Port test_checker.py to Python 3

Fixes ticket:3459
2020-10-16 10:31:25 -04:00
Jean-Paul Calderone
f15086d995
Merge pull request #844 from tahoe-lafs/3460.improved-got_announcement
Improved `_got_announcement`

Fixes: ticket:3460
2020-10-16 08:55:11 -04:00
Jean-Paul Calderone
99fe617069
Merge pull request #857 from tahoe-lafs/3470.oneshotobserverlist-immediately
Make OneShotObserverList immediate

Fixes: ticket:3470
2020-10-15 17:37:31 -04:00
Jean-Paul Calderone
733d393a07
Merge pull request #840 from tahoe-lafs/3454.unskip-test_python3
Unskip the Python 3 porting test on Python 2

Fixes: ticket:3454
2020-10-15 17:32:59 -04:00
Jean-Paul Calderone
4d56b5f4ed
Merge pull request #858 from tahoe-lafs/3471.immediate-localwrapper
Allow LocalWrapper to be immediate

Fixes: ticket:3471
2020-10-15 13:15:35 -04:00
Jean-Paul Calderone
2960a270ce Declare and document what LocalWrapper is/does 2020-10-15 12:00:03 -04:00
Itamar Turner-Trauring
707ab50606 Test BytesJSONEncoder with Unicode. 2020-10-15 08:37:09 -04:00
Itamar Turner-Trauring
1c976990a1 Make comment more meaningful. 2020-10-15 08:34:56 -04:00
Itamar Turner-Trauring
e6a196c144 Get rid of hopefully unnecessary sort. 2020-10-15 08:33:51 -04:00
Itamar Turner-Trauring
b658a66e7f Merge remote-tracking branch 'origin/master' into 3459.test-checker-python-3 2020-10-15 08:32:53 -04:00
Itamar Turner-Trauring
b094a00458
Merge pull request #860 from tahoe-lafs/3473-mutable-tests-part-1-python-3
Port allmydata.mutable.tests to Python 3: part 1 of N

Fixes ticket:3473
2020-10-15 08:27:45 -04:00
Itamar Turner-Trauring
fecbbb6733 Port to Python 3. 2020-10-14 16:05:02 -04:00
Itamar Turner-Trauring
7faea936df Tests pass on Python 3. 2020-10-14 16:03:53 -04:00
Itamar Turner-Trauring
b5e54f2ed2 Port to Python 3. 2020-10-14 15:50:02 -04:00
Itamar Turner-Trauring
fa92fde04a Port to Python 3. 2020-10-14 15:46:37 -04:00
Itamar Turner-Trauring
43f5a25ec2 Tests pass on Python 3. 2020-10-14 15:45:09 -04:00
Jean-Paul Calderone
b0159a898e Parameterize the callRemote scheduling 2020-10-14 11:08:40 -04:00
Jean-Paul Calderone
5974f5adf9 Stop using eventually in OneShotObserverList 2020-10-14 10:56:50 -04:00
Itamar Turner-Trauring
c0f486a9f6 Work on Python 3. 2020-10-13 09:51:25 -04:00
Itamar Turner-Trauring
50925fcec1 Get rid of more no-longer-needed moves. 2020-10-13 09:49:39 -04:00
Itamar Turner-Trauring
3ea18ca3fc As better alternative to common_py3, make common.py import on Python 3. 2020-10-13 09:45:03 -04:00
Chad Whitacre
a0963fc2da Keep future.builtins imports consistent
- remove int from a stock import
- comment a non-stock import
2020-10-13 08:39:25 -04:00
Itamar Turner-Trauring
17f0676b3f
Merge branch 'master' into 3459.test-checker-python-3 2020-10-09 10:22:17 -04:00
Ross Patterson
cc8c9c0bdf
Merge pull request #851 from tahoe-lafs/3464.cleanup-bbb-comments
#3455: Address feedback, BBB comments
2020-10-08 13:49:34 -07:00
Ross Patterson
95f2d53f92 chore(refs #3455) Address feedback, BBB comments
https://github.com/tahoe-lafs/tahoe-lafs/pull/845#issuecomment-704469561
2020-10-07 12:28:41 -07:00
Itamar Turner-Trauring
d519d4b2fa
Merge branch 'master' into 3463.more-immutable-python-3 2020-10-07 13:22:04 -04:00
Itamar Turner-Trauring
72cc37bb95
Merge pull request #843 from tahoe-lafs/3458.callremote-unicode
Fix callRemote unicode issues on Python 2 universally, using monkeypatching

Fixes ticket:3458
2020-10-07 13:21:19 -04:00
Itamar Turner-Trauring
5b76bf7f44 Fix trailing whitespace. 2020-10-07 10:12:31 -04:00
Itamar Turner-Trauring
f2e5688723 Port to Python 3. 2020-10-07 10:06:02 -04:00
Itamar Turner-Trauring
af95769927 Merge branch '3458.callremote-unicode' into 3463.more-immutable-python-3 2020-10-07 09:53:30 -04:00
Itamar Turner-Trauring
9dc4f98987 Port to Python 3. 2020-10-07 09:29:41 -04:00
Itamar Turner-Trauring
3e87ba368e Port to Python 3. 2020-10-06 11:32:19 -04:00
Chad Whitacre
e78afd877c
Merge pull request #846 from tahoe-lafs/3456.tweak-docstring
Tweak docstring on FakeCanary
2020-10-06 06:19:54 -04:00
Itamar Turner-Trauring
c680b1d971 Lint fixes. 2020-10-05 11:38:53 -04:00
Ross Patterson
e89bbe1601
Merge pull request #845 from tahoe-lafs/3455.python-3-port-node-round1
3455: Round 1 of porting `allmydata.node`
2020-10-05 08:32:28 -07:00
Itamar Turner-Trauring
dd863a003f Port test_checker.py to Python 3. 2020-10-05 11:12:06 -04:00
Itamar Turner-Trauring
96231fab5f Support bytes in JSON output. 2020-10-05 11:01:11 -04:00
Itamar Turner-Trauring
b60cd13054 Fix the integration test failure. 2020-10-05 10:43:48 -04:00
Itamar Turner-Trauring
fe6917b48b Merge remote-tracking branch 'origin/master' into 3458.callremote-unicode 2020-10-05 10:24:36 -04:00
Chad Whitacre
ad4d7f7612 Tweak docstring
Since this class is used in multiple test modules now, it makes sense to
keep it in common_util instead of test_storage.
2020-10-05 08:34:41 -04:00
Chad Whitacre
2fe2acf4c7
Merge pull request #842 from tahoe-lafs/3456.bye-bye-common_py3
Fold common_py3 back into other files
2020-10-05 08:03:18 -04:00
Ross Patterson
f1da68f340 feat(py3): Fix config from string compatibility
I did an audit of the code base and AFAICT the `node.config_from_string(...)` is only
used internally.  Much of that usage is in tests where most of the usages feed in
non-specific, simple `"..."` string literals (IOW, bytes under py2, unicode under py3) while one
test module used `b"..."` byte string literals.  Given all that it seems to me that the
best goal would be to use simple string literals throughout the usage of
`node.config_from_string(...)` and have only one special case in that function to handle
the difference between versions.

I just discovered that running the test with `TEST_SUITE=allmydata` doesn't run the
tests in `allmydata.test.test_node` but running them with
`TEST_SUITE=allmydata.test.test_node` does run them.  I'm trying to figure out why that
is, but in the meantime here are the differences in the Python 3 test output when
running just the `allmydata.test.test_node` tests.  This changes converts 11 tests from
errros to success, changes the specific errors for others and improves coverage a bit:

```diff
--- ../../.tox/make-test-py3-all-old.log	2020-10-01 11:56:15.428609940 -0700
+++ ../../.tox/make-test-py3-all-new.log	2020-10-01 11:56:55.052792565 -0700
@@ -95,9 +95,9 @@
     tor_provider,
   File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/introducer/server.py", line 87, in __init__
     node.Node.__init__(self, config, main_tub, control_tub, i2p_provider, tor_provider)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 734, in __init__
+  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 739, in __init__
     self.setup_logging()
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 826, in setup_logging
+  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 831, in setup_logging
     newmeth = types.UnboundMethodType(formatTimeTahoeStyle, ob, ob.__class__)
 builtins.AttributeError: module 'types' has no attribute 'UnboundMethodType'

@@ -158,53 +158,29 @@
 (#.### secs)
 allmydata.test.test_node.TestCase.test_config_required ... [OK]
 (#.### secs)
-allmydata.test.test_node.TestCase.test_location1 ... Traceback (most recent call last):
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 112, in test_location1
-    tub_location="192.0.2.0:1234")
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 99, in _test_location
-    tub = testing_tub(config_data)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 53, in testing_tub
-    config = config_from_string(basedir, 'DEFAULT_PORTNUMFILE_BLANK', config_data)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 209, in config_from_string
-    parser.readfp(BytesIO(config_str))
-builtins.TypeError: a bytes-like object is required, not 'str'
-[ERROR]
+allmydata.test.test_node.TestCase.test_location1 ... [OK]
 (#.### secs)
 allmydata.test.test_node.TestCase.test_location2 ... Traceback (most recent call last):
   File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 117, in test_location2
     tub_location="192.0.2.0:1234,example.org:8091")
   File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 99, in _test_location
     tub = testing_tub(config_data)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 53, in testing_tub
-    config = config_from_string(basedir, 'DEFAULT_PORTNUMFILE_BLANK', config_data)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 209, in config_from_string
-    parser.readfp(BytesIO(config_str))
-builtins.TypeError: a bytes-like object is required, not 'str'
+  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 65, in testing_tub
+    cert_filename='DEFAULT_CERTFILE_BLANK'
+  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 669, in create_main_tub
+    portlocation = _tub_portlocation(config)
+  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 596, in _tub_portlocation
+    tubport = _convert_tub_port(file_tubport)
+  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 552, in _convert_tub_port
+    if re.search(r'^\d+$', s):
+  File "/usr/lib/python3.6/re.py", line 182, in search
+    return _compile(pattern, flags).search(string)
+builtins.TypeError: cannot use a string pattern on a bytes-like object
 [ERROR]
 (#.### secs)
-allmydata.test.test_node.TestCase.test_location_auto_and_explicit ... Traceback (most recent call last):
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 142, in test_location_auto_and_explicit
-    local_addresses=["127.0.0.1", "192.0.2.0", "example.com:4321"],
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 99, in _test_location
-    tub = testing_tub(config_data)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 53, in testing_tub
-    config = config_from_string(basedir, 'DEFAULT_PORTNUMFILE_BLANK', config_data)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 209, in config_from_string
-    parser.readfp(BytesIO(config_str))
-builtins.TypeError: a bytes-like object is required, not 'str'
-[ERROR]
+allmydata.test.test_node.TestCase.test_location_auto_and_explicit ... [OK]
 (#.### secs)
-allmydata.test.test_node.TestCase.test_location_not_set ... Traceback (most recent call last):
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 128, in test_location_not_set
-    local_addresses=["127.0.0.1", "192.0.2.0"],
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 99, in _test_location
-    tub = testing_tub(config_data)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 53, in testing_tub
-    config = config_from_string(basedir, 'DEFAULT_PORTNUMFILE_BLANK', config_data)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 209, in config_from_string
-    parser.readfp(BytesIO(config_str))
-builtins.TypeError: a bytes-like object is required, not 'str'
-[ERROR]
+allmydata.test.test_node.TestCase.test_location_not_set ... [OK]
 (#.### secs)
 allmydata.test.test_node.TestCase.test_logdir_is_str ... Traceback (most recent call last):
   File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 340, in test_logdir_is_str
@@ -215,27 +191,31 @@
     storage_broker,
   File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/client.py", line 676, in __init__
     node.Node.__init__(self, config, main_tub, control_tub, i2p_provider, tor_provider)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 734, in __init__
+  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 739, in __init__
     self.setup_logging()
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 826, in setup_logging
+  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 831, in setup_logging
     newmeth = types.UnboundMethodType(formatTimeTahoeStyle, ob, ob.__class__)
 builtins.AttributeError: module 'types' has no attribute 'UnboundMethodType'
 [ERROR]
 (#.### secs)
 allmydata.test.test_node.TestCase.test_private_config ... Traceback (most recent call last):
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 259, in test_private_config
-    config = config_from_string(basedir, "", "")
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 209, in config_from_string
-    parser.readfp(BytesIO(config_str))
-builtins.TypeError: a bytes-like object is required, not 'str'
-[ERROR]
+  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 261, in test_private_config
+    self.assertEqual(config.get_private_config("already"), "secret")
+  File "/home/rpatterson/src/work/sfu/tahoe-lafs/.tox/py36-coverage/lib/python3.6/site-packages/twisted/trial/_synctest.py", line 434, in assertEqual
+    super(_Assertions, self).assertEqual(first, second, msg)
+  File "/usr/lib/python3.6/unittest/case.py", line 829, in assertEqual
+    assertion_func(first, second, msg=msg)
+  File "/usr/lib/python3.6/unittest/case.py", line 822, in _baseAssertEqual
+    raise self.failureException(msg)
+twisted.trial.unittest.FailTest: b'secret' != 'secret'
+[FAILURE]
 (#.### secs)
 allmydata.test.test_node.TestCase.test_private_config_missing ... [OK]
 (#.### secs)
 allmydata.test.test_node.TestCase.test_private_config_unreadable ... Traceback (most recent call last):
   File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 213, in test_private_config_unreadable
     config.get_or_create_private_config("foo", "contents")
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 369, in get_or_create_private_config
+  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 374, in get_or_create_private_config
     fileutil.write(privname, value)
   File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/util/fileutil.py", line 275, in write
     f.write(data)
@@ -258,77 +238,33 @@
 (#.### secs)
 allmydata.test.test_node.TestCase.test_timestamp ... [OK]
 (#.### secs)
-allmydata.test.test_node.TestCase.test_write_config_unwritable_file ... Traceback (most recent call last):
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 288, in test_write_config_unwritable_file
-    config = config_from_string(basedir, "", "")
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 209, in config_from_string
-    parser.readfp(BytesIO(config_str))
-builtins.TypeError: a bytes-like object is required, not 'str'
-[ERROR]
+allmydata.test.test_node.TestCase.test_write_config_unwritable_file ... [OK]
 (#.### secs)
-allmydata.test.test_node.TestMissingPorts.test_disabled_port_not_tub ... Traceback (most recent call last):
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 488, in test_disabled_port_not_tub
-    config = config_from_string(self.basedir, "portnum", config_data)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 209, in config_from_string
-    parser.readfp(BytesIO(config_str))
-builtins.TypeError: a bytes-like object is required, not 'str'
-[ERROR]
+allmydata.test.test_node.TestMissingPorts.test_disabled_port_not_tub ... [OK]
 (#.### secs)
-allmydata.test.test_node.TestMissingPorts.test_disabled_tub_not_port ... Traceback (most recent call last):
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 506, in test_disabled_tub_not_port
-    config = config_from_string(self.basedir, "portnum", config_data)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 209, in config_from_string
-    parser.readfp(BytesIO(config_str))
-builtins.TypeError: a bytes-like object is required, not 'str'
-[ERROR]
+allmydata.test.test_node.TestMissingPorts.test_disabled_tub_not_port ... [OK]
 (#.### secs)
-allmydata.test.test_node.TestMissingPorts.test_empty_tub_location ... Traceback (most recent call last):
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 470, in test_empty_tub_location
-    config = config_from_string(self.basedir, "portnum", config_data)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 209, in config_from_string
-    parser.readfp(BytesIO(config_str))
-builtins.TypeError: a bytes-like object is required, not 'str'
-[ERROR]
+allmydata.test.test_node.TestMissingPorts.test_empty_tub_location ... [OK]
 (#.### secs)
-allmydata.test.test_node.TestMissingPorts.test_empty_tub_port ... Traceback (most recent call last):
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 453, in test_empty_tub_port
-    config = config_from_string(self.basedir, "portnum", config_data)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 209, in config_from_string
-    parser.readfp(BytesIO(config_str))
-builtins.TypeError: a bytes-like object is required, not 'str'
-[ERROR]
+allmydata.test.test_node.TestMissingPorts.test_empty_tub_port ... [OK]
 (#.### secs)
-allmydata.test.test_node.TestMissingPorts.test_parsing_all_disabled ... Traceback (most recent call last):
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 439, in test_parsing_all_disabled
-    config = config_from_string(self.basedir, "portnum", config_data)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 209, in config_from_string
-    parser.readfp(BytesIO(config_str))
-builtins.TypeError: a bytes-like object is required, not 'str'
-[ERROR]
+allmydata.test.test_node.TestMissingPorts.test_parsing_all_disabled ... [OK]
 (#.### secs)
-allmydata.test.test_node.TestMissingPorts.test_parsing_defaults ... Traceback (most recent call last):
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 392, in test_parsing_defaults
-    config = config_from_string(self.basedir, "portnum", config_data)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 209, in config_from_string
-    parser.readfp(BytesIO(config_str))
-builtins.TypeError: a bytes-like object is required, not 'str'
-[ERROR]
+allmydata.test.test_node.TestMissingPorts.test_parsing_defaults ... [OK]
 (#.### secs)
 allmydata.test.test_node.TestMissingPorts.test_parsing_location_complex ... Traceback (most recent call last):
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 415, in test_parsing_location_complex
-    config = config_from_string(self.basedir, "portnum", config_data)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 209, in config_from_string
-    parser.readfp(BytesIO(config_str))
-builtins.TypeError: a bytes-like object is required, not 'str'
+  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 418, in test_parsing_location_complex
+    tubport, tublocation = _tub_portlocation(config)
+  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 596, in _tub_portlocation
+    tubport = _convert_tub_port(file_tubport)
+  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 552, in _convert_tub_port
+    if re.search(r'^\d+$', s):
+  File "/usr/lib/python3.6/re.py", line 182, in search
+    return _compile(pattern, flags).search(string)
+builtins.TypeError: cannot use a string pattern on a bytes-like object
 [ERROR]
 (#.### secs)
-allmydata.test.test_node.TestMissingPorts.test_parsing_tcp ... Traceback (most recent call last):
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 370, in test_parsing_tcp
-    config = config_from_string(self.basedir, "portnum", config_data)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 209, in config_from_string
-    parser.readfp(BytesIO(config_str))
-builtins.TypeError: a bytes-like object is required, not 'str'
-[ERROR]
+allmydata.test.test_node.TestMissingPorts.test_parsing_tcp ... [OK]
 (#.### secs)

 ===============================================================================
@@ -415,9 +351,9 @@
     tor_provider,
   File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/introducer/server.py", line 87, in __init__
     node.Node.__init__(self, config, main_tub, control_tub, i2p_provider, tor_provider)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 734, in __init__
+  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 739, in __init__
     self.setup_logging()
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 826, in setup_logging
+  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 831, in setup_logging
     newmeth = types.UnboundMethodType(formatTimeTahoeStyle, ob, ob.__class__)
 builtins.AttributeError: module 'types' has no attribute 'UnboundMethodType'

@@ -449,6 +385,20 @@

 allmydata.test.test_node.TestCase.test_config_items
 ===============================================================================
+[FAIL]
+Traceback (most recent call last):
+  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 261, in test_private_config
+    self.assertEqual(config.get_private_config("already"), "secret")
+  File "/home/rpatterson/src/work/sfu/tahoe-lafs/.tox/py36-coverage/lib/python3.6/site-packages/twisted/trial/_synctest.py", line 434, in assertEqual
+    super(_Assertions, self).assertEqual(first, second, msg)
+  File "/usr/lib/python3.6/unittest/case.py", line 829, in assertEqual
+    assertion_func(first, second, msg=msg)
+  File "/usr/lib/python3.6/unittest/case.py", line 822, in _baseAssertEqual
+    raise self.failureException(msg)
+twisted.trial.unittest.FailTest: b'secret' != 'secret'
+
+allmydata.test.test_node.TestCase.test_private_config
+===============================================================================
 [ERROR]
 Traceback (most recent call last):
   File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 657, in test_disabled
@@ -503,62 +453,26 @@
 ===============================================================================
 [ERROR]
 Traceback (most recent call last):
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 112, in test_location1
-    tub_location="192.0.2.0:1234")
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 99, in _test_location
-    tub = testing_tub(config_data)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 53, in testing_tub
-    config = config_from_string(basedir, 'DEFAULT_PORTNUMFILE_BLANK', config_data)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 209, in config_from_string
-    parser.readfp(BytesIO(config_str))
-builtins.TypeError: a bytes-like object is required, not 'str'
-
-allmydata.test.test_node.TestCase.test_location1
-===============================================================================
-[ERROR]
-Traceback (most recent call last):
   File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 117, in test_location2
     tub_location="192.0.2.0:1234,example.org:8091")
   File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 99, in _test_location
     tub = testing_tub(config_data)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 53, in testing_tub
-    config = config_from_string(basedir, 'DEFAULT_PORTNUMFILE_BLANK', config_data)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 209, in config_from_string
-    parser.readfp(BytesIO(config_str))
-builtins.TypeError: a bytes-like object is required, not 'str'
+  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 65, in testing_tub
+    cert_filename='DEFAULT_CERTFILE_BLANK'
+  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 669, in create_main_tub
+    portlocation = _tub_portlocation(config)
+  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 596, in _tub_portlocation
+    tubport = _convert_tub_port(file_tubport)
+  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 552, in _convert_tub_port
+    if re.search(r'^\d+$', s):
+  File "/usr/lib/python3.6/re.py", line 182, in search
+    return _compile(pattern, flags).search(string)
+builtins.TypeError: cannot use a string pattern on a bytes-like object

 allmydata.test.test_node.TestCase.test_location2
 ===============================================================================
 [ERROR]
 Traceback (most recent call last):
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 142, in test_location_auto_and_explicit
-    local_addresses=["127.0.0.1", "192.0.2.0", "example.com:4321"],
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 99, in _test_location
-    tub = testing_tub(config_data)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 53, in testing_tub
-    config = config_from_string(basedir, 'DEFAULT_PORTNUMFILE_BLANK', config_data)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 209, in config_from_string
-    parser.readfp(BytesIO(config_str))
-builtins.TypeError: a bytes-like object is required, not 'str'
-
-allmydata.test.test_node.TestCase.test_location_auto_and_explicit
-===============================================================================
-[ERROR]
-Traceback (most recent call last):
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 128, in test_location_not_set
-    local_addresses=["127.0.0.1", "192.0.2.0"],
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 99, in _test_location
-    tub = testing_tub(config_data)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 53, in testing_tub
-    config = config_from_string(basedir, 'DEFAULT_PORTNUMFILE_BLANK', config_data)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 209, in config_from_string
-    parser.readfp(BytesIO(config_str))
-builtins.TypeError: a bytes-like object is required, not 'str'
-
-allmydata.test.test_node.TestCase.test_location_not_set
-===============================================================================
-[ERROR]
-Traceback (most recent call last):
   File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 340, in test_logdir_is_str
     yield client.create_client(basedir)
   File "/home/rpatterson/src/work/sfu/tahoe-lafs/.tox/py36-coverage/lib/python3.6/site-packages/twisted/internet/defer.py", line 1418, in _inlineCallbacks
@@ -567,9 +481,9 @@
     storage_broker,
   File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/client.py", line 676, in __init__
     node.Node.__init__(self, config, main_tub, control_tub, i2p_provider, tor_provider)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 734, in __init__
+  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 739, in __init__
     self.setup_logging()
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 826, in setup_logging
+  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 831, in setup_logging
     newmeth = types.UnboundMethodType(formatTimeTahoeStyle, ob, ob.__class__)
 builtins.AttributeError: module 'types' has no attribute 'UnboundMethodType'

@@ -577,19 +491,9 @@
 ===============================================================================
 [ERROR]
 Traceback (most recent call last):
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 259, in test_private_config
-    config = config_from_string(basedir, "", "")
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 209, in config_from_string
-    parser.readfp(BytesIO(config_str))
-builtins.TypeError: a bytes-like object is required, not 'str'
-
-allmydata.test.test_node.TestCase.test_private_config
-===============================================================================
-[ERROR]
-Traceback (most recent call last):
   File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 213, in test_private_config_unreadable
     config.get_or_create_private_config("foo", "contents")
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 369, in get_or_create_private_config
+  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 374, in get_or_create_private_config
     fileutil.write(privname, value)
   File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/util/fileutil.py", line 275, in write
     f.write(data)
@@ -607,97 +511,21 @@
 ===============================================================================
 [ERROR]
 Traceback (most recent call last):
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 288, in test_write_config_unwritable_file
-    config = config_from_string(basedir, "", "")
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 209, in config_from_string
-    parser.readfp(BytesIO(config_str))
-builtins.TypeError: a bytes-like object is required, not 'str'
-
-allmydata.test.test_node.TestCase.test_write_config_unwritable_file
-===============================================================================
-[ERROR]
-Traceback (most recent call last):
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 488, in test_disabled_port_not_tub
-    config = config_from_string(self.basedir, "portnum", config_data)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 209, in config_from_string
-    parser.readfp(BytesIO(config_str))
-builtins.TypeError: a bytes-like object is required, not 'str'
-
-allmydata.test.test_node.TestMissingPorts.test_disabled_port_not_tub
-===============================================================================
-[ERROR]
-Traceback (most recent call last):
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 506, in test_disabled_tub_not_port
-    config = config_from_string(self.basedir, "portnum", config_data)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 209, in config_from_string
-    parser.readfp(BytesIO(config_str))
-builtins.TypeError: a bytes-like object is required, not 'str'
-
-allmydata.test.test_node.TestMissingPorts.test_disabled_tub_not_port
-===============================================================================
-[ERROR]
-Traceback (most recent call last):
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 470, in test_empty_tub_location
-    config = config_from_string(self.basedir, "portnum", config_data)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 209, in config_from_string
-    parser.readfp(BytesIO(config_str))
-builtins.TypeError: a bytes-like object is required, not 'str'
-
-allmydata.test.test_node.TestMissingPorts.test_empty_tub_location
-===============================================================================
-[ERROR]
-Traceback (most recent call last):
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 453, in test_empty_tub_port
-    config = config_from_string(self.basedir, "portnum", config_data)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 209, in config_from_string
-    parser.readfp(BytesIO(config_str))
-builtins.TypeError: a bytes-like object is required, not 'str'
-
-allmydata.test.test_node.TestMissingPorts.test_empty_tub_port
-===============================================================================
-[ERROR]
-Traceback (most recent call last):
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 439, in test_parsing_all_disabled
-    config = config_from_string(self.basedir, "portnum", config_data)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 209, in config_from_string
-    parser.readfp(BytesIO(config_str))
-builtins.TypeError: a bytes-like object is required, not 'str'
-
-allmydata.test.test_node.TestMissingPorts.test_parsing_all_disabled
-===============================================================================
-[ERROR]
-Traceback (most recent call last):
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 392, in test_parsing_defaults
-    config = config_from_string(self.basedir, "portnum", config_data)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 209, in config_from_string
-    parser.readfp(BytesIO(config_str))
-builtins.TypeError: a bytes-like object is required, not 'str'
-
-allmydata.test.test_node.TestMissingPorts.test_parsing_defaults
-===============================================================================
-[ERROR]
-Traceback (most recent call last):
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 415, in test_parsing_location_complex
-    config = config_from_string(self.basedir, "portnum", config_data)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 209, in config_from_string
-    parser.readfp(BytesIO(config_str))
-builtins.TypeError: a bytes-like object is required, not 'str'
+  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 418, in test_parsing_location_complex
+    tubport, tublocation = _tub_portlocation(config)
+  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 596, in _tub_portlocation
+    tubport = _convert_tub_port(file_tubport)
+  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 552, in _convert_tub_port
+    if re.search(r'^\d+$', s):
+  File "/usr/lib/python3.6/re.py", line 182, in search
+    return _compile(pattern, flags).search(string)
+builtins.TypeError: cannot use a string pattern on a bytes-like object

 allmydata.test.test_node.TestMissingPorts.test_parsing_location_complex
-===============================================================================
-[ERROR]
-Traceback (most recent call last):
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 370, in test_parsing_tcp
-    config = config_from_string(self.basedir, "portnum", config_data)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 209, in config_from_string
-    parser.readfp(BytesIO(config_str))
-builtins.TypeError: a bytes-like object is required, not 'str'
-
-allmydata.test.test_node.TestMissingPorts.test_parsing_tcp
 -------------------------------------------------------------------------------
-Ran 34 tests in 2.788s
+Ran 34 tests in 2.516s

-FAILED (failures=4, errors=21, successes=9)
+FAILED (failures=5, errors=9, successes=20)
 Name                                                 Stmts   Miss Branch BrPart  Cover   Missing
 ------------------------------------------------------------------------------------------------
 src/allmydata/__init__.py                               16      4      0      0    75%   18-22, 28-32
@@ -751,7 +579,7 @@
 src/allmydata/mutable/repairer.py                       57     37     18      0    29%   13, 15, 17, 19, 29-34, 65-71, 74-126, 129-131
 src/allmydata/mutable/retrieve.py                      489    411    120      0    13%   29-43, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 67-69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89-90, 105-160, 164, 167-171, 174-175, 186-193, 201-208, 211-212, 223-227, 230-232, 236-254, 257-275, 278-283, 286-332, 344-354, 362-454, 485-516, 529-540, 564-578, 586-597, 607-633, 643-663, 671-699, 712-729, 738-798, 806-829, 839-889, 897-905, 909-910, 919-941, 950-971, 981-994, 999-1005
 src/allmydata/mutable/servermap.py                     623    524    198      0    12%   26-38, 41-42, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 70, 72, 74, 76, 78, 80, 82, 116-124, 130-139, 142, 145, 148, 159-161, 165, 170-172, 175, 177, 180-181, 183, 186-199, 202, 206, 213, 217-220, 225-228, 231, 234-238, 243-252, 255-259, 263-265, 269-275, 280-290, 295-305, 311-315, 320-322, 328-350, 358-363, 370-372, 379, 390-450, 454, 457-461, 466-545, 549-557, 560-575, 578-593, 596-613, 623-638, 642-779, 787, 791-799, 803-804, 816-880, 883-904, 910-914, 919-920, 928-944, 960-974, 981-998, 1002-1012, 1020-1183, 1186-1205, 1209-1225, 1228-1229
-src/allmydata/node.py                                  388    106    146     39    69%   120, 132, 190, 211-213, 241, 243-245, 278, 284, 291-295, 303-306, 315, 320, 339, 341, 361, 368, 370, 377-379, 393-396, 422, 424, 449, 453, 490, 493, 500, 511-512, 547-549, 566, 574, 581, 583, 590-591, 597, 601, 612, 622-634, 679, 681, 736-750, 756, 764, 792-805, 808-809, 814-815, 827-846, 189->190, 204->208, 240->241, 242->243, 277->278, 314->315, 319->320, 338->339, 340->341, 360->361, 365->368, 391->393, 421->422, 423->424, 448->449, 451->453, 489->490, 492->493, 499->500, 510->511, 565->566, 567->570, 573->574, 575->578, 580->581, 582->583, 585->597, 589->590, 600->601, 603->606, 610->616, 611->612, 618->622, 673->679, 680->681, 763->764, 766->768, 821->830, 823->821
+src/allmydata/node.py                                  391     87    148     30    75%   20, 125, 137, 195, 246, 248-250, 283, 289, 308-311, 320, 325, 344, 346, 366, 373, 375, 382-384, 398-401, 427, 429, 454, 458, 495, 498, 505, 516-517, 606, 617, 634-638, 684, 686, 741-755, 761, 769, 797-810, 813-814, 819-820, 832-851, 19->20, 194->195, 209->213, 245->246, 247->248, 282->283, 319->320, 324->325, 343->344, 345->346, 365->366, 370->373, 396->398, 426->427, 428->429, 453->454, 456->458, 494->495, 497->498, 504->505, 515->516, 605->606, 616->617, 627->634, 678->684, 685->686, 768->769, 771->773, 826->835, 828->826
 src/allmydata/nodemaker.py                              97     71     38      0    21%   23-33, 36, 38, 41, 44-47, 49, 53-95, 98-115, 118-125, 129-138, 141-150
 src/allmydata/scripts/admin.py                          51     31      2      0    38%   9-14, 17-21, 25, 28, 31-37, 40-46, 56-57, 59, 61-66, 74-78
 src/allmydata/scripts/backupdb.py                      146    146     14      0     0%   1-341
@@ -810,7 +638,7 @@
 src/allmydata/util/dictutil.py                          38     22     12      1    34%   16, 21-24, 27-31, 34-38, 55-56, 59-60, 63-64, 71, 77-78, 12->16
 src/allmydata/util/eliotutil.py                        115     68     24      0    35%   82-85, 91-94, 104, 117-122, 129-139, 151, 155-159, 163-167, 179-186, 198-199, 202-210, 222-226, 231-247, 250, 266-294, 308-312
 src/allmydata/util/encodingutil.py                     217    123     80     12    36%   18, 37-38, 41, 43, 52-53, 69, 75-78, 102, 108, 114-122, 130-134, 145-155, 164, 173-175, 178-181, 187, 196-213, 217-231, 237-243, 279-282, 291-296, 314, 320-322, 327, 334-340, 343-355, 358-363, 366-367, 370-373, 379, 395-405, 412-420, 423, 429, 16->18, 36->37, 40->41, 42->43, 66->69, 72->74, 74->75, 278->279, 285->295, 288->291, 299->310, 319->320
-src/allmydata/util/fileutil.py                         343    244    120     13    25%   15, 23-25, 47-55, 71-85, 96-97, 100, 103, 106, 109, 115-116, 119-125, 128, 131, 134, 137-138, 142-145, 151-153, 158, 166-176, 179-184, 201-203, 214-237, 241-244, 247-254, 262, 279, 282-290, 293-304, 326, 328, 336-342, 348, 351, 358, 366-376, 382-400, 405, 410-426, 434-462, 486-529, 548-554, 566-568, 573-604, 608-612, 615-627, 633, 636-659, 13->15, 22->23, 200->201, 259->262, 325->326, 327->328, 332->336, 345->351, 347->348, 357->358, 380->382, 404->405, 571->573
+src/allmydata/util/fileutil.py                         343    243    120     13    25%   15, 23-25, 47-55, 71-85, 96-97, 100, 103, 106, 109, 115-116, 119-125, 128, 131, 134, 137-138, 142-145, 151-153, 158, 166-176, 179-184, 201-203, 214-237, 241-244, 247-254, 262, 282-290, 293-304, 326, 328, 336-342, 348, 351, 358, 366-376, 382-400, 405, 410-426, 434-462, 486-529, 548-554, 566-568, 573-604, 608-612, 615-627, 633, 636-659, 13->15, 22->23, 200->201, 259->262, 325->326, 327->328, 332->336, 345->351, 347->348, 357->358, 380->382, 404->405, 571->573
 src/allmydata/util/gcutil.py                            23      3      8      3    81%   20, 51-57, 19->20, 50->51, 64->exit
 src/allmydata/util/happinessutil.py                     77     62     42      1    13%   15, 25-54, 64-69, 82-92, 142-183, 207-223, 235-249, 13->15
 src/allmydata/util/hashutil.py                         157     76      8      1    50%   14, 40-42, 45-46, 49-56, 60-62, 66-68, 72-76, 118, 122, 126, 130, 134, 138, 142, 146, 150, 154, 158, 162, 166, 174-176, 180-183, 187, 191, 195, 199, 204, 209-210, 214-215, 219, 223-228, 232, 236, 240, 244, 248-250, 254, 258, 262, 266, 270-271, 278, 282, 12->14
@@ -818,7 +646,7 @@
 src/allmydata/util/i2p_provider.py                     121     73     36      5    35%   44-67, 72-81, 85-135, 151-161, 168, 176-180, 183-184, 187, 193-216, 219, 226, 167->168, 175->176, 182->183, 186->187, 192->193
 src/allmydata/util/idlib.py                              5      2      0      0    60%   6, 9
 src/allmydata/util/iputil.py                           172     74     56     12    52%   14, 63-102, 123-140, 151-184, 209, 216, 229, 237-238, 242, 246, 254-257, 271-277, 328-329, 353-354, 13->14, 215->216, 220->242, 226->229, 234->220, 239->234, 245->246, 249->259, 265->261, 291->329, 295->328, 360->exit
-src/allmydata/util/log.py                               52     27     16      1    38%   13, 38-41, 46-48, 51-61, 67-75, 78, 12->13
+src/allmydata/util/log.py                               52     23     16      2    46%   13, 46-48, 51-61, 67-75, 78, 12->13, 39->41
 src/allmydata/util/mathutil.py                          12      3      2      1    71%   16, 25-26, 15->16
 src/allmydata/util/netstring.py                         35     24     12      1    26%   13, 31-54, 12->13
 src/allmydata/util/observer.py                          91     56     20      1    32%   14, 29-32, 36-38, 41, 44, 47, 50-54, 57-60, 63-66, 69-70, 79, 82, 93-97, 103, 106, 109, 112-113, 119-121, 134, 137-139, 142-145, 148-151, 154-157, 13->14
@@ -854,7 +682,7 @@
 src/allmydata/windows/fixups.py                        133    133     54      0     0%   1-237
 src/allmydata/windows/registry.py                       42     42     12      0     0%   1-77
 ------------------------------------------------------------------------------------------------
-TOTAL                                                27467  22018   8248    184    17%
+TOTAL                                                27470  21994   8250    176    17%

 12 files skipped due to complete coverage.
 make[#]: Leaving directory '/home/rpatterson/src/work/sfu/tahoe-lafs'
```
2020-10-04 21:52:27 -07:00
Ross Patterson
da046108e2 feat(py3): Fix section name unicode type clash
Before this change, there was an error in the tests in python 3.  I couldn't find any
clues from the history as to why explicit byte-string literals were used here.  This
change addresses the error under Python 3 and doesn't cause any regressions under Python
2 in the test suite.  This changes two tests from failures to passing under Python 3 and
increases coverage a bit:

```diff
--- ../../.tox/make-test-py3-all-old.log	2020-10-04 21:42:22.931028265 -0700
+++ ../../.tox/make-test-py3-all-new.log	2020-10-04 21:49:19.164127097 -0700
@@ -313,7 +313,7 @@
 ####-##-##T##:##:##-###0 [twisted.scripts._twistd_unix.UnixAppLogger#info] twistd 20.3.0 (/home/rpatterson/src/work/sfu/tahoe-lafs/.tox/py36-coverage/bin/python 3.6.12) starting up.
 ####-##-##T##:##:##-###0 [twisted.scripts._twistd_unix.UnixAppLogger#info] reactor class: mock.mock.MagicMock.
 ####-##-##T##:##:##-###0 [twisted.scripts._twistd_unix.UnixAppLogger#info] Server Shut Down.
-                                         [FAIL]
+                                           [OK]
 allmydata.test
   cli
     test_status ...                                                     [ERROR]
@@ -1191,7 +1191,7 @@
     test_disabled_but_helper ...                                         [FAIL]
     test_disabled_but_storage ...                                        [FAIL]
   Configuration
-    test_create_client_invalid_config ...                                [FAIL]
+    test_create_client_invalid_config ...                                  [OK]
     test_read_invalid_config ...                                           [OK]
   IntroducerNotListening
     test_port_none_introducer ...                                        [FAIL]
@@ -2024,18 +2024,6 @@
 ===============================================================================
 [FAIL]
 Traceback (most recent call last):
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/.tox/py36-coverage/lib/python3.6/site-packages/mock/mock.py", line 1369, in patched
-    return func(*newargs, **newkeywargs)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/cli/test_start.py", line 265, in test_run_invalid_config
-    output,
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/.tox/py36-coverage/lib/python3.6/site-packages/twisted/trial/_synctest.py", line 494, in assertIn
-    % (containee, container))
-twisted.trial.unittest.FailTest: 'invalid section' not in '\nUnknown error\nTraceback (most recent call last):\n  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/cli/test_start.py", line 232, in cwr\n    fn()\n  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/scripts/run_common.py", line 155, in start\n    d = service_factory()\n  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/scripts/run_common.py", line 136, in <lambda>\n    u"client": lambda: maybeDeferred(namedAny("allmydata.client.create_client"), self.basedir),\n  File "/home/rpatterson/src/work/sfu/tahoe-lafs/.tox/py36-coverage/lib/python3.6/site-packages/twisted/internet/defer.py", line 151, in maybeDeferred\n    result = f(*args, **kw)\n--- <exception caught here> ---\n  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/client.py", line 243, in create_client\n    config = read_config(basedir, u"client.port")\n  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/client.py", line 219, in read_config\n    _valid_config=_valid_config(),\n  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 192, in read_config\n    configutil.validate_config(config_fname, parser, _valid_config)\n  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/util/configutil.py", line 72, in validate_config\n    if not valid_config.is_valid_section(section):\n  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/util/configutil.py", line 113, in is_valid_section\n    self._is_valid_section(section_name)\n  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/util/configutil.py", line 141, in <lambda>\n    return lambda *a, **kw: f(*a, **kw) or g(*a, **kw)\n  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/client.py", line 72, in _is_valid_section\n    section_name.startswith(b"storageserver.plugins.") or\nbuiltins.TypeError: startswith first arg must be str or a tuple of str, not bytes\n'
-
-allmydata.test.cli.test_start.RunTests.test_run_invalid_config
-===============================================================================
-[FAIL]
-Traceback (most recent call last):
   File "/home/rpatterson/src/work/sfu/tahoe-lafs/.tox/py36-coverage/lib/python3.6/site-packages/twisted/trial/_asynctest.py", line 75, in _eb
     raise self.failureException(output)
 twisted.trial.unittest.FailTest:
@@ -2222,34 +2210,6 @@
     result = result.throwExceptionIntoGenerator(g)
   File "/home/rpatterson/src/work/sfu/tahoe-lafs/.tox/py36-coverage/lib/python3.6/site-packages/twisted/python/failure.py", line 512, in throwExceptionIntoGenerator
     return g.throw(self.type, self.value, self.tb)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 741, in test_create_client_invalid_config
-    yield client.create_client(self.basedir)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/.tox/py36-coverage/lib/python3.6/site-packages/twisted/trial/_synctest.py", line 355, in __exit__
-    self._expectedName, reason.getTraceback()),
-twisted.trial.unittest.FailTest: builtins.TypeError raised instead of UnknownConfigError:
- Traceback (most recent call last):
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/.tox/py36-coverage/lib/python3.6/site-packages/twisted/internet/defer.py", line 1529, in _cancellableInlineCallbacks
-    _inlineCallbacks(None, g, status)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/.tox/py36-coverage/lib/python3.6/site-packages/twisted/internet/defer.py", line 1416, in _inlineCallbacks
-    result = result.throwExceptionIntoGenerator(g)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/.tox/py36-coverage/lib/python3.6/site-packages/twisted/python/failure.py", line 512, in throwExceptionIntoGenerator
-    return g.throw(self.type, self.value, self.tb)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 741, in test_create_client_invalid_config
-    yield client.create_client(self.basedir)
---- <exception caught here> ---
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 741, in test_create_client_invalid_config
-    yield client.create_client(self.basedir)
-builtins.TypeError: startswith first arg must be str or a tuple of str, not bytes
-
-
-allmydata.test.test_node.Configuration.test_create_client_invalid_config
-===============================================================================
-[FAIL]
-Traceback (most recent call last):
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/.tox/py36-coverage/lib/python3.6/site-packages/twisted/internet/defer.py", line 1416, in _inlineCallbacks
-    result = result.throwExceptionIntoGenerator(g)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/.tox/py36-coverage/lib/python3.6/site-packages/twisted/python/failure.py", line 512, in throwExceptionIntoGenerator
-    return g.throw(self.type, self.value, self.tb)
   File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 704, in test_port_none_introducer
     yield create_introducer(basedir)
   File "/home/rpatterson/src/work/sfu/tahoe-lafs/.tox/py36-coverage/lib/python3.6/site-packages/twisted/trial/_synctest.py", line 355, in __exit__
@@ -8717,7 +8677,7 @@
 -------------------------------------------------------------------------------
 Ran 1300 tests in ###.###s

-FAILED (skips=42, expectedFailures=1, failures=35, errors=531, successes=707)
+FAILED (skips=42, expectedFailures=1, failures=33, errors=531, successes=709)

 Unknown error
 Traceback (most recent call last):
@@ -8806,7 +8766,7 @@
 src/allmydata/scripts/create_node.py                   302     98    114     10    66%   224-229, 235, 257-260, 262-265, 268-269, 289-292, 295-298, 329, 339, 347-380, 391-445, 461-477, 223->224, 234->235, 256->257, 261->262, 266->277, 267->268, 288->289, 294->295, 328->329, 338->339
 src/allmydata/scripts/debug.py                         719    638    202      0     9%   14, 31-32, 35-49, 52-60, 63-142, 146-154, 157-164, 168-217, 220-304, 307-401, 407, 417, 437-465, 468-485, 488-602, 606, 609-611, 637-648, 653-656, 659, 683-689, 692-810, 813-842, 845-848, 851-865, 869, 888, 891-940, 946, 949-950, 957, 960-961, 967-972, 984-985, 999-1000, 1003-1004, 1020-1021, 1025-1031, 1046-1050
 src/allmydata/scripts/default_nodedir.py                15      5      6      2    57%   10-14, 9->10, 16->exit
-src/allmydata/scripts/run_common.py                    135     18     24      6    85%   37, 41-46, 59-60, 149, 158, 192-193, 216-220, 226-227, 55->62, 135->exit, 135->exit, 148->149, 191->192, 225->226
+src/allmydata/scripts/run_common.py                    135     17     24      5    86%   37, 41-46, 59-60, 158, 192-193, 216-220, 226-227, 55->62, 135->exit, 135->exit, 191->192, 225->226
 src/allmydata/scripts/runner.py                        138     49     42      5    61%   84-85, 91, 97-99, 150, 153-160, 174-181, 188-192, 202-232, 237-252, 255, 31->36, 149->150, 151->153, 185->188, 254->255
 src/allmydata/scripts/slow_operation.py                 69     56     22      0    14%   15-44, 47-52, 55-61, 64-83
 src/allmydata/scripts/stats_gatherer.py                 44     16     12      3    59%   8, 30, 75-79, 84-93, 7->8, 29->30, 74->75
@@ -8893,7 +8853,7 @@
 src/allmydata/windows/fixups.py                        133    133     54      0     0%   1-237
 src/allmydata/windows/registry.py                       42     42     12      0     0%   1-77
 ------------------------------------------------------------------------------------------------
-TOTAL                                                27477  11782   8244    605    54%
+TOTAL                                                27477  11781   8244    604    54%

 18 files skipped due to complete coverage.
 + '[' '!' -z 1 ']'
```
2020-10-04 21:50:09 -07:00
Ross Patterson
a89715ebe8 feat(py3): feat(py3): Fix use of deprecated type
Python 3 did away with the unbound method type entirely, they're just functions under
Python 3, and IIUC the unbound type is just an alias for the method type in Python 2.
As such, this approach should preserve the behavior under Python 2 and should work under
Python 3.

With this change, the diff in test output shows one test error converted to a failure,
increases coverage in all the modules that have a coverage change, and reveals the next
porting bug:

```
...
  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 740, in __init__
    self.config.write_config_file("my_nodeid", b32encode(self.nodeid).lower() + "\n")
builtins.TypeError: can't concat str to bytes
```

There are no regressions I see under Python 2, so this seems like the right fix to this
particular issue AFAICT.

```diff
--- ../../.tox/make-test-py3-all-old.log	2020-10-04 15:59:59.355692613 -0700
+++ ../../.tox/make-test-py3-all-new.log	2020-10-04 16:59:27.870208496 -0700
@@ -1206,7 +1206,7 @@
     test_location2 ...                                                  [ERROR]
     test_location_auto_and_explicit ...                                 [ERROR]
     test_location_not_set ...                                           [ERROR]
-    test_logdir_is_str ...                                              [ERROR]
+    test_logdir_is_str ...                                               [FAIL]
     test_private_config ...                                             [ERROR]
     test_private_config_missing ...                                        [OK]
     test_private_config_unreadable ...                                  [ERROR]
@@ -2254,7 +2254,7 @@
     yield create_introducer(basedir)
   File "/home/rpatterson/src/work/sfu/tahoe-lafs/.tox/py36-coverage/lib/python3.6/site-packages/twisted/trial/_synctest.py", line 355, in __exit__
     self._expectedName, reason.getTraceback()),
-twisted.trial.unittest.FailTest: builtins.AttributeError raised instead of ValueError:
+twisted.trial.unittest.FailTest: builtins.TypeError raised instead of ValueError:
  Traceback (most recent call last):
   File "/home/rpatterson/src/work/sfu/tahoe-lafs/.tox/py36-coverage/lib/python3.6/site-packages/twisted/internet/defer.py", line 1529, in _cancellableInlineCallbacks
     _inlineCallbacks(None, g, status)
@@ -2271,11 +2271,9 @@
     tor_provider,
   File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/introducer/server.py", line 87, in __init__
     node.Node.__init__(self, config, main_tub, control_tub, i2p_provider, tor_provider)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 734, in __init__
-    self.setup_logging()
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 826, in setup_logging
-    newmeth = types.UnboundMethodType(formatTimeTahoeStyle, ob, ob.__class__)
-builtins.AttributeError: module 'types' has no attribute 'UnboundMethodType'
+  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 740, in __init__
+    self.config.write_config_file("my_nodeid", b32encode(self.nodeid).lower() + "\n")
+builtins.TypeError: can't concat str to bytes

 allmydata.test.test_node.IntroducerNotListening.test_port_none_introducer
@@ -2307,6 +2305,30 @@
 ===============================================================================
 [FAIL]
 Traceback (most recent call last):
+  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 340, in test_logdir_is_str
+    yield client.create_client(basedir)
+  File "/home/rpatterson/src/work/sfu/tahoe-lafs/.tox/py36-coverage/lib/python3.6/site-packages/twisted/internet/defer.py", line 1418, in _inlineCallbacks
+    result = g.send(result)
+  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/client.py", line 298, in create_client_from_config
+    storage_broker,
+  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/client.py", line 676, in __init__
+    node.Node.__init__(self, config, main_tub, control_tub, i2p_provider, tor_provider)
+  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 734, in __init__
+    self.setup_logging()
+  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 842, in setup_logging
+    foolscap.logging.log.setLogDir(incident_dir.encode(get_filesystem_encoding()))
+  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 336, in call_setLogDir
+    self.failUnless(isinstance(logdir, str), logdir)
+  File "/home/rpatterson/src/work/sfu/tahoe-lafs/.tox/py36-coverage/lib/python3.6/site-packages/twisted/trial/_synctest.py", line 397, in assertTrue
+    super(_Assertions, self).assertTrue(condition, msg)
+  File "/usr/lib/python3.6/unittest/case.py", line 682, in assertTrue
+    raise self.failureException(msg)
+twisted.trial.unittest.FailTest: False is not true : b'/home/rpatterson/src/work/sfu/tahoe-lafs/_trial_temp/test_node/test_logdir_is_str/logs/incidents'
+
+allmydata.test.test_node.TestCase.test_logdir_is_str
+===============================================================================
+[FAIL]
+Traceback (most recent call last):
   File "/home/rpatterson/src/work/sfu/tahoe-lafs/.tox/py36-coverage/lib/python3.6/site-packages/twisted/internet/defer.py", line 1418, in _inlineCallbacks
     result = g.send(result)
   File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_runner.py", line 192, in test_eliot_destination
@@ -5933,11 +5955,9 @@
     storage_broker,
   File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/client.py", line 676, in __init__
     node.Node.__init__(self, config, main_tub, control_tub, i2p_provider, tor_provider)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 734, in __init__
-    self.setup_logging()
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 826, in setup_logging
-    newmeth = types.UnboundMethodType(formatTimeTahoeStyle, ob, ob.__class__)
-builtins.AttributeError: module 'types' has no attribute 'UnboundMethodType'
+  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 740, in __init__
+    self.config.write_config_file("my_nodeid", b32encode(self.nodeid).lower() + "\n")
+builtins.TypeError: can't concat str to bytes

 allmydata.test.test_client.Basic.test_web_apiauthtoken
 ===============================================================================
@@ -7130,8 +7150,12 @@
 ===============================================================================
 [ERROR]
 Traceback (most recent call last):
-Failure: testtools.testresult.real._StringException: Empty attachments:
-  twisted-log
+Failure: testtools.testresult.real._StringException: twisted-log: {{{
+2020-10-04 23:57:37.636Z [-] Foolscap logging initialized
+2020-10-04 23:57:37.636Z [-] Note to developers: twistd.log does not receive very much.
+2020-10-04 23:57:37.636Z [-] Use 'flogtool tail -c NODEDIR/private/logport.furl' instead
+2020-10-04 23:57:37.636Z [-] and read docs/logging.rst
+}}}

 Traceback (most recent call last):
   File "/home/rpatterson/src/work/sfu/tahoe-lafs/.tox/py36-coverage/lib/python3.6/site-packages/twisted/internet/defer.py", line 1416, in _inlineCallbacks
@@ -7144,19 +7168,21 @@
     tor_provider,
   File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/introducer/server.py", line 87, in __init__
     node.Node.__init__(self, config, main_tub, control_tub, i2p_provider, tor_provider)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 734, in __init__
-    self.setup_logging()
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 826, in setup_logging
-    newmeth = types.UnboundMethodType(formatTimeTahoeStyle, ob, ob.__class__)
-AttributeError: module 'types' has no attribute 'UnboundMethodType'
+  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 740, in __init__
+    self.config.write_config_file("my_nodeid", b32encode(self.nodeid).lower() + "\n")
+TypeError: can't concat str to bytes

 allmydata.test.test_introducer.Node.test_create
 ===============================================================================
 [ERROR]
 Traceback (most recent call last):
-Failure: testtools.testresult.real._StringException: Empty attachments:
-  twisted-log
+Failure: testtools.testresult.real._StringException: twisted-log: {{{
+2020-10-04 23:57:38.284Z [-] Foolscap logging initialized
+2020-10-04 23:57:38.284Z [-] Note to developers: twistd.log does not receive very much.
+2020-10-04 23:57:38.284Z [-] Use 'flogtool tail -c NODEDIR/private/logport.furl' instead
+2020-10-04 23:57:38.284Z [-] and read docs/logging.rst
+}}}

 Traceback (most recent call last):
   File "/home/rpatterson/src/work/sfu/tahoe-lafs/.tox/py36-coverage/lib/python3.6/site-packages/twisted/internet/defer.py", line 1416, in _inlineCallbacks
@@ -7169,11 +7195,9 @@
     tor_provider,
   File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/introducer/server.py", line 87, in __init__
     node.Node.__init__(self, config, main_tub, control_tub, i2p_provider, tor_provider)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 734, in __init__
-    self.setup_logging()
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 826, in setup_logging
-    newmeth = types.UnboundMethodType(formatTimeTahoeStyle, ob, ob.__class__)
-AttributeError: module 'types' has no attribute 'UnboundMethodType'
+  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 740, in __init__
+    self.config.write_config_file("my_nodeid", b32encode(self.nodeid).lower() + "\n")
+TypeError: can't concat str to bytes

 allmydata.test.test_introducer.Node.test_furl
@@ -7540,24 +7564,6 @@
 ===============================================================================
 [ERROR]
 Traceback (most recent call last):
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 340, in test_logdir_is_str
-    yield client.create_client(basedir)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/.tox/py36-coverage/lib/python3.6/site-packages/twisted/internet/defer.py", line 1418, in _inlineCallbacks
-    result = g.send(result)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/client.py", line 298, in create_client_from_config
-    storage_broker,
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/client.py", line 676, in __init__
-    node.Node.__init__(self, config, main_tub, control_tub, i2p_provider, tor_provider)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 734, in __init__
-    self.setup_logging()
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 826, in setup_logging
-    newmeth = types.UnboundMethodType(formatTimeTahoeStyle, ob, ob.__class__)
-builtins.AttributeError: module 'types' has no attribute 'UnboundMethodType'
-
-allmydata.test.test_node.TestCase.test_logdir_is_str
-===============================================================================
-[ERROR]
-Traceback (most recent call last):
   File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/test/test_node.py", line 259, in test_private_config
     config = config_from_string(basedir, "", "")
   File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 209, in config_from_string
@@ -8446,11 +8452,9 @@
     tor_provider,
   File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/introducer/server.py", line 87, in __init__
     node.Node.__init__(self, config, main_tub, control_tub, i2p_provider, tor_provider)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 734, in __init__
-    self.setup_logging()
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 826, in setup_logging
-    newmeth = types.UnboundMethodType(formatTimeTahoeStyle, ob, ob.__class__)
-builtins.AttributeError: module 'types' has no attribute 'UnboundMethodType'
+  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 740, in __init__
+    self.config.write_config_file("my_nodeid", b32encode(self.nodeid).lower() + "\n")
+builtins.TypeError: can't concat str to bytes

 allmydata.test.test_system.Connections.test_rref
 allmydata.test.test_system.SystemTest.test_filesystem
@@ -8565,11 +8569,9 @@
     tor_provider,
   File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/introducer/server.py", line 87, in __init__
     node.Node.__init__(self, config, main_tub, control_tub, i2p_provider, tor_provider)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 734, in __init__
-    self.setup_logging()
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 826, in setup_logging
-    newmeth = types.UnboundMethodType(formatTimeTahoeStyle, ob, ob.__class__)
-builtins.AttributeError: module 'types' has no attribute 'UnboundMethodType'
+  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 740, in __init__
+    self.config.write_config_file("my_nodeid", b32encode(self.nodeid).lower() + "\n")
+builtins.TypeError: can't concat str to bytes

 allmydata.test.web.test_introducer.IntroducerWeb.test_basic_information
 ===============================================================================
@@ -8587,11 +8589,9 @@
     tor_provider,
   File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/introducer/server.py", line 87, in __init__
     node.Node.__init__(self, config, main_tub, control_tub, i2p_provider, tor_provider)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 734, in __init__
-    self.setup_logging()
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 826, in setup_logging
-    newmeth = types.UnboundMethodType(formatTimeTahoeStyle, ob, ob.__class__)
-builtins.AttributeError: module 'types' has no attribute 'UnboundMethodType'
+  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 740, in __init__
+    self.config.write_config_file("my_nodeid", b32encode(self.nodeid).lower() + "\n")
+builtins.TypeError: can't concat str to bytes

 allmydata.test.web.test_introducer.IntroducerWeb.test_json_front_page
 ===============================================================================
@@ -8609,11 +8609,9 @@
     tor_provider,
   File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/introducer/server.py", line 87, in __init__
     node.Node.__init__(self, config, main_tub, control_tub, i2p_provider, tor_provider)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 734, in __init__
-    self.setup_logging()
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 826, in setup_logging
-    newmeth = types.UnboundMethodType(formatTimeTahoeStyle, ob, ob.__class__)
-builtins.AttributeError: module 'types' has no attribute 'UnboundMethodType'
+  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 740, in __init__
+    self.config.write_config_file("my_nodeid", b32encode(self.nodeid).lower() + "\n")
+builtins.TypeError: can't concat str to bytes

 allmydata.test.web.test_introducer.IntroducerWeb.test_tahoe_css
 ===============================================================================
@@ -8631,11 +8629,9 @@
     tor_provider,
   File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/introducer/server.py", line 87, in __init__
     node.Node.__init__(self, config, main_tub, control_tub, i2p_provider, tor_provider)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 734, in __init__
-    self.setup_logging()
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 826, in setup_logging
-    newmeth = types.UnboundMethodType(formatTimeTahoeStyle, ob, ob.__class__)
-builtins.AttributeError: module 'types' has no attribute 'UnboundMethodType'
+  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 740, in __init__
+    self.config.write_config_file("my_nodeid", b32encode(self.nodeid).lower() + "\n")
+builtins.TypeError: can't concat str to bytes

 allmydata.test.web.test_introducer.IntroducerWeb.test_welcome
 ===============================================================================
@@ -8721,7 +8717,7 @@
 -------------------------------------------------------------------------------
 Ran 1300 tests in ###.###s

-FAILED (skips=42, expectedFailures=1, failures=34, errors=532, successes=707)
+FAILED (skips=42, expectedFailures=1, failures=35, errors=531, successes=707)

 Unknown error
 Traceback (most recent call last):
@@ -8740,11 +8736,9 @@
     storage_broker,
   File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/client.py", line 676, in __init__
     node.Node.__init__(self, config, main_tub, control_tub, i2p_provider, tor_provider)
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 734, in __init__
-    self.setup_logging()
-  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 826, in setup_logging
-    newmeth = types.UnboundMethodType(formatTimeTahoeStyle, ob, ob.__class__)
-builtins.AttributeError: module 'types' has no attribute 'UnboundMethodType'
+  File "/home/rpatterson/src/work/sfu/tahoe-lafs/src/allmydata/node.py", line 740, in __init__
+    self.config.write_config_file("my_nodeid", b32encode(self.nodeid).lower() + "\n")
+builtins.TypeError: can't concat str to bytes
 + test_exit=1
 + ./.tox/py36-coverage/bin/coverage combine
 + ./.tox/py36-coverage/bin/coverage html
@@ -8775,11 +8769,11 @@
 src/allmydata/immutable/downloader/__init__.py           7      1      2      1    78%   12, 11->12
 src/allmydata/immutable/downloader/common.py            14      1      2      1    88%   12, 11->12
 src/allmydata/immutable/downloader/fetcher.py          147      1     56      1    99%   12, 11->12
-src/allmydata/immutable/downloader/finder.py           143     11     40      5    91%   11, 88-89, 108, 115, 170-173, 231-232, 10->11, 87->88, 107->108, 113->115, 165->exit
+src/allmydata/immutable/downloader/finder.py           143      9     40      5    92%   11, 88-89, 108, 115, 170-173, 10->11, 87->88, 107->108, 113->115, 165->exit
 src/allmydata/immutable/downloader/node.py             282      9     66      9    94%   11, 170-172, 224-235, 271, 10->11, 43->exit, 60->68, 165->169, 169->170, 256->exit, 270->271, 517->exit, 537->exit
 src/allmydata/immutable/downloader/segmentation.py     118      1     22      1    99%   11, 10->11
-src/allmydata/immutable/downloader/share.py            453     23    154     11    94%   11, 210, 239-250, 289-290, 354, 399-400, 430-437, 518, 722-725, 775, 862, 10->11, 209->210, 222->239, 288->289, 352->354, 397->399, 515->518, 660->663, 710->722, 762->exit, 774->775
-src/allmydata/immutable/downloader/status.py           154     12     36      1    93%   11, 65-67, 223, 226, 230, 232, 234, 274, 285, 287, 10->11
+src/allmydata/immutable/downloader/share.py            453     15    154      8    96%   11, 210, 248-250, 354, 430-437, 518, 722-725, 862, 10->11, 209->210, 239->248, 352->354, 515->518, 660->663, 710->722, 762->exit
+src/allmydata/immutable/downloader/status.py           154      9     36      1    95%   11, 223, 226, 230, 232, 234, 274, 285, 287, 10->11
 src/allmydata/immutable/encode.py                      421     13    124     10    95%   114, 197-200, 278-280, 405, 412, 462, 509, 562, 687, 102->104, 113->114, 195->197, 404->405, 411->412, 461->462, 499->509, 505->511, 561->562, 685->687
 src/allmydata/immutable/filenode.py                    196     48     30      5    72%   77-78, 83, 85, 88, 94-101, 104-124, 127-172, 254, 258, 315, 40->42, 224->227, 227->229, 251->254, 257->258
 src/allmydata/immutable/happiness_upload.py            214      1    132      3    99%   15, 13->15, 213->211, 280->279
@@ -8802,7 +8796,7 @@
 src/allmydata/mutable/repairer.py                       57     37     18      0    29%   13, 15, 17, 19, 29-34, 65-71, 74-126, 129-131
 src/allmydata/mutable/retrieve.py                      489    123    120     33    71%   46, 48, 50, 52, 56, 58, 60, 62, 64, 89-90, 133, 186-193, 204-208, 211-212, 224-226, 231, 240, 251, 312, 318, 344-354, 377, 385-386, 399-400, 425-434, 490, 501, 515-516, 529-540, 564-578, 591-592, 629-630, 653-654, 674-675, 681-682, 698, 712-729, 758-760, 765, 772-774, 790-792, 871, 883, 909-910, 919-941, 965-966, 981-994, 999-1005, 129->133, 167->169, 169->171, 201->204, 223->224, 230->231, 237->239, 239->240, 243->247, 249->251, 309->312, 317->318, 376->377, 381->385, 391->394, 396->399, 424->425, 489->490, 499->501, 514->515, 590->591, 628->629, 652->653, 673->674, 677->687, 680->681, 687->694, 694->698, 755->764, 764->765, 868->871, 880->883, 964->965
 src/allmydata/mutable/servermap.py                     612    240    186     26    56%   45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 74, 130-139, 142, 148, 159-161, 175, 177, 183, 186-199, 206, 213, 217-220, 231, 234-238, 243-252, 255-259, 315, 328-350, 358-363, 370-372, 379, 429, 433, 443-447, 495, 498, 506-508, 514-516, 569-570, 603-611, 623-638, 718-721, 732-741, 792, 796, 803-804, 850-851, 872-874, 911-915, 929-945, 961-975, 982-999, 1003-1013, 1043-1045, 1050-1052, 1060-1064, 1069-1070, 1093-1100, 1106-1186, 1214-1215, 1232-1233, 313->315, 427->429, 432->433, 439->443, 459->461, 493->495, 497->498, 504->506, 509->514, 566->569, 597->603, 687->exit, 702->exit, 710->exit, 717->718, 727->732, 759->exit, 791->792, 795->796, 869->872, 1039->1043, 1047->1050, 1059->1060, 1066->1069, 1092->1093, 1213->1214
-src/allmydata/node.py                                  388     82    146     33    76%   120, 132, 190, 241, 243-245, 278, 284, 294-295, 303-306, 315, 320, 339, 341, 361, 393-396, 422, 449, 453, 490, 493, 500, 511-512, 548, 566, 574, 581, 583, 590-591, 601, 612, 629-633, 679, 681, 738-741, 747, 756, 764, 792-805, 808-809, 814-815, 827-846, 189->190, 240->241, 242->243, 277->278, 314->315, 319->320, 338->339, 340->341, 360->361, 391->393, 421->422, 448->449, 451->453, 489->490, 492->493, 499->500, 510->511, 547->548, 565->566, 573->574, 580->581, 582->583, 589->590, 600->601, 611->612, 622->629, 673->679, 680->681, 737->738, 746->747, 763->764, 821->830, 823->821
+src/allmydata/node.py                                  388     66    146     33    80%   120, 132, 190, 241, 243-245, 278, 284, 294-295, 303-306, 315, 320, 339, 341, 361, 393-396, 422, 449, 453, 490, 493, 500, 511-512, 548, 566, 574, 581, 583, 590-591, 601, 612, 629-633, 679, 681, 741, 747, 756, 764, 792-805, 808-809, 814-815, 832, 837, 189->190, 240->241, 242->243, 277->278, 314->315, 319->320, 338->339, 340->341, 360->361, 391->393, 421->422, 448->449, 451->453, 489->490, 492->493, 499->500, 510->511, 547->548, 565->566, 573->574, 580->581, 582->583, 589->590, 600->601, 611->612, 622->629, 673->679, 680->681, 746->747, 763->764, 823->821, 831->832, 835->837
 src/allmydata/nodemaker.py                              97     23     38     10    70%   49, 61, 66, 70, 81, 94, 107-115, 130-138, 141-150, 57->61, 65->66, 69->70, 79->81, 86->95, 90->94, 104->107, 124->exit, 129->130, 129->133
 src/allmydata/scripts/admin.py                          51     20      2      1    60%   9-14, 25, 28, 31-37, 40-46, 57, 59, 61-66, 56->57
 src/allmydata/scripts/backupdb.py                      146     91     14      1    36%   84-91, 94-96, 99, 103, 106, 111-114, 117-119, 122, 125, 128, 176-221, 231-242, 245-263, 266-272, 308-324, 327-333, 336-341, 306->308
@@ -8837,7 +8831,7 @@
 src/allmydata/storage/common.py                         24      1      4      2    89%   11, 10->11, 36->39
 src/allmydata/storage/crawler.py                       222      1     64      3    99%   16, 13->16, 96->99, 496->505
 src/allmydata/storage/expirer.py                       240      1     81      2    99%   9, 7->9, 250->exitp
-src/allmydata/storage/immutable.py                     198      2     48      6    97%   12, 101, 11->12, 100->101, 142->140, 155->160, 187->197, 273->exit
+src/allmydata/storage/immutable.py                     198      1     48      5    98%   12, 11->12, 142->140, 155->160, 187->197, 273->exit
 src/allmydata/storage/lease.py                          35      1      4      1    95%   12, 11->12
 src/allmydata/storage/mutable.py                       289      8     90      6    96%   12, 162, 252, 289, 362-367, 11->12, 160->162, 247->252, 307->311, 354->362, 448->exit
 src/allmydata/storage/server.py                        371      9    120      9    96%   13, 92, 222, 243, 329, 349, 375, 422-423, 10->13, 91->92, 221->222, 241->243, 289->300, 317->329, 325->305, 346->349, 374->375
@@ -8899,7 +8893,7 @@
 src/allmydata/windows/fixups.py                        133    133     54      0     0%   1-237
 src/allmydata/windows/registry.py                       42     42     12      0     0%   1-77
 ------------------------------------------------------------------------------------------------
-TOTAL                                                27477  11798   8244    605    54%
+TOTAL                                                27477  11768   8244    601    54%

 18 files skipped due to complete coverage.
 + '[' '!' -z 1 ']'
```
2020-10-04 20:56:14 -07:00