Merge pull request #645 from tahoe-lafs/3239.python2-new-style-regression-test

Fix the new-style class regression test

Fixes: ticket:3239
This commit is contained in:
Jean-Paul Calderone 2019-08-14 09:08:35 -04:00 committed by GitHub
commit 0723a2f4d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 76 additions and 39 deletions

0
newsfragments/3239.minor Normal file
View File

View File

@ -114,7 +114,7 @@ def check(options):
class FakeTransport(object): class FakeTransport(object):
disconnecting = False disconnecting = False
class DeepCheckOutput(LineOnlyReceiver): class DeepCheckOutput(LineOnlyReceiver, object):
delimiter = "\n" delimiter = "\n"
def __init__(self, streamer, options): def __init__(self, streamer, options):
self.streamer = streamer self.streamer = streamer
@ -173,7 +173,7 @@ class DeepCheckOutput(LineOnlyReceiver):
print("done: %d objects checked, %d healthy, %d unhealthy" \ print("done: %d objects checked, %d healthy, %d unhealthy" \
% (self.num_objects, self.files_healthy, self.files_unhealthy), file=stdout) % (self.num_objects, self.files_healthy, self.files_unhealthy), file=stdout)
class DeepCheckAndRepairOutput(LineOnlyReceiver): class DeepCheckAndRepairOutput(LineOnlyReceiver, object):
delimiter = "\n" delimiter = "\n"
def __init__(self, streamer, options): def __init__(self, streamer, options):
self.streamer = streamer self.streamer = streamer
@ -271,7 +271,7 @@ class DeepCheckAndRepairOutput(LineOnlyReceiver):
% (self.post_repair_files_healthy, % (self.post_repair_files_healthy,
self.post_repair_files_unhealthy), file=stdout) self.post_repair_files_unhealthy), file=stdout)
class DeepCheckStreamer(LineOnlyReceiver): class DeepCheckStreamer(LineOnlyReceiver, object):
def deepcheck_location(self, options, where): def deepcheck_location(self, options, where):
stdout = options.stdout stdout = options.stdout

View File

@ -12,7 +12,7 @@ from allmydata.util.encodingutil import quote_output, quote_path
class FakeTransport(object): class FakeTransport(object):
disconnecting = False disconnecting = False
class ManifestStreamer(LineOnlyReceiver): class ManifestStreamer(LineOnlyReceiver, object):
delimiter = "\n" delimiter = "\n"
def __init__(self): def __init__(self):

View File

@ -1,6 +1,6 @@
from foolscap.logging.incident import IncidentQualifier from foolscap.logging.incident import IncidentQualifier
class NonQualifier(IncidentQualifier): class NonQualifier(IncidentQualifier, object):
def check_event(self, ev): def check_event(self, ev):
return False return False

View File

@ -15,7 +15,7 @@ from io import BytesIO
from twisted.internet import protocol, defer from twisted.internet import protocol, defer
class _EverythingGetter(protocol.ProcessProtocol): class _EverythingGetter(protocol.ProcessProtocol, object):
def __init__(self, deferred, stdinBytes=None): def __init__(self, deferred, stdinBytes=None):
self.deferred = deferred self.deferred = deferred

View File

@ -270,4 +270,3 @@ while True:
f.write("directories-written: %d\n" % directories_written) f.write("directories-written: %d\n" % directories_written)
f.close() f.close()
os.rename(stats_out+".tmp", stats_out) os.rename(stats_out+".tmp", stats_out)

View File

@ -14,7 +14,7 @@ from allmydata.util.encodingutil import get_filesystem_encoding
from foolscap.api import Tub, fireEventually, flushEventualQueue from foolscap.api import Tub, fireEventually, flushEventualQueue
from twisted.python import log, procutils from twisted.python import log, procutils
class StallableHTTPGetterDiscarder(tw_client.HTTPPageGetter): class StallableHTTPGetterDiscarder(tw_client.HTTPPageGetter, object):
full_speed_ahead = False full_speed_ahead = False
_bytes_so_far = 0 _bytes_so_far = 0
stalled = None stalled = None
@ -41,7 +41,7 @@ class StallableHTTPGetterDiscarder(tw_client.HTTPPageGetter):
self.stalled = None self.stalled = None
return tw_client.HTTPPageGetter.handleResponseEnd(self) return tw_client.HTTPPageGetter.handleResponseEnd(self)
class StallableDiscardingHTTPClientFactory(tw_client.HTTPClientFactory): class StallableDiscardingHTTPClientFactory(tw_client.HTTPClientFactory, object):
protocol = StallableHTTPGetterDiscarder protocol = StallableHTTPGetterDiscarder
def discardPage(url, stall=False, *args, **kwargs): def discardPage(url, stall=False, *args, **kwargs):
@ -477,7 +477,7 @@ this file are ignored.
return d return d
class ClientWatcher(protocol.ProcessProtocol): class ClientWatcher(protocol.ProcessProtocol, object):
ended = False ended = False
def outReceived(self, data): def outReceived(self, data):
print("OUT:", data) print("OUT:", data)
@ -504,4 +504,3 @@ if __name__ == '__main__':
# removed each time we run. # removed each time we run.
sf = SystemFramework("_test_memory", mode) sf = SystemFramework("_test_memory", mode)
sf.run() sf.run()

View File

@ -49,7 +49,7 @@ from ..util.eliotutil import (
inline_callbacks, inline_callbacks,
) )
class Expect(Protocol): class Expect(Protocol, object):
def __init__(self): def __init__(self):
self._expectations = [] self._expectations = []
@ -79,7 +79,7 @@ class Expect(Protocol):
d.errback(reason) d.errback(reason)
class _ProcessProtocolAdapter(ProcessProtocol): class _ProcessProtocolAdapter(ProcessProtocol, object):
def __init__(self, fds): def __init__(self, fds):
self._fds = fds self._fds = fds
@ -218,7 +218,7 @@ class CLINodeAPI(object):
return stopping return stopping
class _WaitForEnd(ProcessProtocol): class _WaitForEnd(ProcessProtocol, object):
def __init__(self, ended): def __init__(self, ended):
self._ended = ended self._ended = ended

View File

@ -1,32 +1,71 @@
""" """
Tests to check for Python2 regressions Tests to check for Python2 regressions
""" """
from twisted.trial import unittest
from inspect import isclass
from twisted.python.modules import getModule from twisted.python.modules import getModule
class PythonTwoRegressions(unittest.TestCase): from testtools import (
""" TestCase,
A test class to hold Python2 regression tests. )
""" from testtools.matchers import (
skip = "https://tahoe-lafs.org/trac/tahoe-lafs/ticket/3239" Equals,
)
def is_new_style(self, cls): BLACKLIST = {
"""check for being a new-style class""" "allmydata.test.check_load",
# another test could be: issubclass(value, type) "allmydata.watchdog._watchdog_541",
has_class_attr = hasattr(cls, '__class__') "allmydata.watchdog.inotify",
dict_or_slots = '__dict__' in dir(cls) or hasattr(cls, '__slots__') "allmydata.windows.inotify",
return has_class_attr and dict_or_slots "allmydata.windows.registry",
"allmydata.windows.tahoesvc",
}
def test_old_style_class(self):
def is_new_style(cls):
""" """
Check if all classes are new-style classes :return bool: ``True`` if and only if the given class is "new style".
""" """
# All new-style classes are instances of type. By definition.
return isinstance(cls, type)
def defined_here(cls, where):
"""
:return bool: ``True`` if and only if the given class was defined in a
module with the given name.
:note: Classes can lie about where they are defined. Try not to do that.
"""
return cls.__module__ == where
class PythonTwoRegressions(TestCase):
"""
Regression tests for Python 2 behaviors related to Python 3 porting.
"""
def test_new_style_classes(self):
"""
All classes in Tahoe-LAFS are new-style.
"""
newstyle = set()
classic = set()
for mod in getModule("allmydata").walkModules(): for mod in getModule("allmydata").walkModules():
if mod.name in BLACKLIST:
continue
# iterAttributes will only work on loaded modules. So, load it.
mod.load()
for attr in mod.iterAttributes(): for attr in mod.iterAttributes():
value = attr.load() value = attr.load()
if isinstance(value, str): if isclass(value) and defined_here(value, mod.name):
# apparently strings are note a new-style class (in Python 2.7) if is_new_style(value):
# so we skip testing them newstyle.add(value)
return else:
self.assertTrue(self.is_new_style(value), classic.add(value)
"{} does not seem to be a new-style class".format(attr.name))
self.assertThat(
classic,
Equals(set()),
"Expected to find no classic classes.",
)

View File

@ -1,7 +1,7 @@
import exceptions, os import exceptions, os
from repr import Repr from repr import Repr
class BetterRepr(Repr): class BetterRepr(Repr, object):
def __init__(self): def __init__(self):
Repr.__init__(self) Repr.__init__(self)

View File

@ -19,7 +19,7 @@ class SingleFileError(Exception):
"""You are not permitted to add a job to a full pipeline.""" """You are not permitted to add a job to a full pipeline."""
class ExpandableDeferredList(defer.Deferred): class ExpandableDeferredList(defer.Deferred, object):
# like DeferredList(fireOnOneErrback=True) with a built-in # like DeferredList(fireOnOneErrback=True) with a built-in
# gatherResults(), but you can add new Deferreds until you close it. This # gatherResults(), but you can add new Deferreds until you close it. This
# gives you a chance to add don't-complain-about-unhandled-error errbacks # gives you a chance to add don't-complain-about-unhandled-error errbacks

View File

@ -322,7 +322,7 @@ def humanize_failure(f):
return (f.getTraceback(), http.REQUEST_ENTITY_TOO_LARGE) return (f.getTraceback(), http.REQUEST_ENTITY_TOO_LARGE)
return (str(f), None) return (str(f), None)
class MyExceptionHandler(appserver.DefaultExceptionHandler): class MyExceptionHandler(appserver.DefaultExceptionHandler, object):
def simple(self, ctx, text, code=http.BAD_REQUEST): def simple(self, ctx, text, code=http.BAD_REQUEST):
req = IRequest(ctx) req = IRequest(ctx)
req.setResponseCode(code) req.setResponseCode(code)
@ -461,7 +461,7 @@ class MultiFormatPage(Page):
class TokenOnlyWebApi(resource.Resource): class TokenOnlyWebApi(resource.Resource, object):
""" """
I provide a rend.Page implementation that only accepts POST calls, I provide a rend.Page implementation that only accepts POST calls,
and only if they have a 'token=' arg with the correct and only if they have a 'token=' arg with the correct

View File

@ -20,7 +20,7 @@ from allmydata.web.common import IOpHandleTable, MyExceptionHandler
# surgery may induce a dependency upon a particular version of twisted.web # surgery may induce a dependency upon a particular version of twisted.web
parse_qs = http.parse_qs parse_qs = http.parse_qs
class MyRequest(appserver.NevowRequest): class MyRequest(appserver.NevowRequest, object):
fields = None fields = None
_tahoe_request_had_error = None _tahoe_request_had_error = None