diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..f59e9d11 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +build +dist +*dropin.cache +*egg-info +*_temp diff --git a/NEWS.rst b/NEWS.rst index db9b575d..0d6758a9 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -1,3 +1,19 @@ +Nevow 1.0 (2018-02-01) +====================== + +Features +-------- + +This release is compatible with python3, and actually incompatible with +python2. + +- _flat.flatten no longer worries about encoding strings; this has + to be done by the write function passed. +- htmlfile and htmlstr are now aliases for xmlfile and xmlstr and + consequently require well-formed XML. This change results from the + microdom being effecively dropped from twisted.web for python3 + + Nevow 0.14.3 (2017-07-26) ========================= diff --git a/benchmarks/json_string_tokenizer.py b/benchmarks/json_string_tokenizer.py index 65f7059c..0b0b9000 100644 --- a/benchmarks/json_string_tokenizer.py +++ b/benchmarks/json_string_tokenizer.py @@ -22,7 +22,7 @@ def postOptions(self): self['scale'] = int(self['scale']) -BASE = u'Hello, world. "Quotes".' +BASE = 'Hello, world. "Quotes".' def benchmark(iterations, scale): """ Deserialize a string C{iterations} times. Make the string longer based @@ -32,10 +32,10 @@ def benchmark(iterations, scale): """ s = serialize(BASE * scale) before = time() - for i in xrange(iterations): + for i in range(iterations): parse(s) after = time() - print (after - before) / iterations, 'per call' + print((after - before) / iterations, 'per call') diff --git a/doc/strings_and_bytes.rst b/doc/strings_and_bytes.rst new file mode 100644 index 00000000..e5865a5b --- /dev/null +++ b/doc/strings_and_bytes.rst @@ -0,0 +1,62 @@ +===================================== +Strings vs. Bytes in Nevow on python3 +===================================== + +Twisted.web decided to have represent several items in their Request +class – which is used quite frequently in nevow and exposed to user code +– as bytes. Also, at some point nevow has to produce bytes, as that is +what needs to go down the line. + +In between, however, I'd like to keep out bytes as much as possible and +let people work with strings as far as possible. This document attempts +to delineate the string/bytes perimeter. + +Given that, unfortunately, that perimeter is long and twisted, the plan +is to accept bytes and strings in several places (in particular, always +for URIs), where bytes, for these purposes, are supposed to be in a +(perhaps at some poin configurable) default encoding, which for now is +utf-8 independent of the enviroment. + +Use utils.toBytes or utils.toString to turn function arguments into +strings or bytes as requrired. + + +Bytes within Twisted we're concerned with +========================================= + +The most important items that are byte strings within request, include: + +* uri +* keys and values in args (this hurts a lot) +* header keys (but header values are decoded) +* prePath -- this is where segments come from; segments, however, are + nevow interface and hence strings. +* the arguments to write (in nevow, we accept strings, too) + + +At least cred.checkers.InMemoryUsernamePasswordDatabaseDontUse +explicitly ASCII-encodes their usernames right now. Since that's +what's used in the unit tests, I'm following ASCII-encoded usernames +in guard. This seems insane. Anyone actually working with guard +should look into this. + + +Bytes usage within nevow itself +=============================== + +While flatteners still return strings, what is passed on to +twisted.web requests' write methods must, of course, be bytes. +nevow.appserver.Requests make that translation using utils.toBytes; user +code requiring non-UTF-8 encodings needs to translate to bytes itself at +this point. + +Since renderHTTP can (and is, indeed, encouraged to) write strings and +the translation is done within nevow.Request.write (or similar), +Page.renderSynchronously and Page.renderString return strings rather +than bytes. + +This is particularly relevant for unit tests: what is in the +FakeRequest's accumulator is bytes. + + +.. vim:tw=72 diff --git a/examples/advanced_manualform/advanced_manualform.py b/examples/advanced_manualform/advanced_manualform.py index 3a472174..a1d84688 100644 --- a/examples/advanced_manualform/advanced_manualform.py +++ b/examples/advanced_manualform/advanced_manualform.py @@ -61,7 +61,7 @@ def redirectAfterPost(aspects): magicCookie = str(now()) refpath = refpath.replace('_nevow_carryover_', magicCookie) _CARRYOVER[magicCookie] = C = tpc.Componentized() - for k, v in aspects.iteritems(): + for k, v in aspects.items(): C.setComponent(k, v) request.redirect(str(refpath)) from nevow import static @@ -99,8 +99,8 @@ class Page(ManualFormMixin, rend.Page): def form_post_btn1(self, what=None): # 'what' is a keyword argument, and must be the same name that you # give to the widget. - print "btn1:", what + print("btn1:", what) def form_post_btn2(self, what=None): # see above for 'what'. - print "btn2:", what + print("btn2:", what) diff --git a/examples/athenademo/benchmark.py b/examples/athenademo/benchmark.py index 34d7f9d8..710df9f6 100644 --- a/examples/athenademo/benchmark.py +++ b/examples/athenademo/benchmark.py @@ -1,5 +1,5 @@ -from __future__ import division + from twisted.python import filepath @@ -31,7 +31,7 @@ def render_body(self, ctx, data): yield top class InitializationBenchmark(athena.LiveFragment): - jsClass = u'Nevow.Benchmarks.InitializationBenchmark' + jsClass = 'Nevow.Benchmarks.InitializationBenchmark' docFactory = loaders.stan( tags.div(render=tags.directive('liveFragment'))[ diff --git a/examples/athenademo/calculator.py b/examples/athenademo/calculator.py index 21d1fdbe..996caf35 100644 --- a/examples/athenademo/calculator.py +++ b/examples/athenademo/calculator.py @@ -28,8 +28,8 @@ class Calculator(object): entered into the calculator. For example, if the buttons '3', '5', and '+' have been pressed (in that order), C{expression} will be C{'35+'}. """ - defaultExpression = u'0' - errorExpression = u'E' + defaultExpression = '0' + errorExpression = 'E' def __init__(self): self.expression = self.defaultExpression @@ -57,7 +57,7 @@ def buttonClicked(self, symbol): # Evaluate the expression if symbol == '=': try: - self.expression = unicode(eval(self.expression)) + self.expression = str(eval(self.expression)) except ZeroDivisionError: self.expression = self.errorExpression return self.expression @@ -86,7 +86,7 @@ class CalculatorElement(LiveElement): """ docFactory = xmlfile(sibling('calculator.html').path, 'CalculatorPattern') - jsClass = u"CalculatorDemo.Calculator" + jsClass = "CalculatorDemo.Calculator" validSymbols = '0123456789/*-=+.C' @@ -123,7 +123,7 @@ def __init__(self, *a, **kw): # Update the mapping of known JavaScript modules so that the # client-side code for this example can be found and served to the # browser. - self.jsModules.mapping[u'CalculatorDemo'] = sibling( + self.jsModules.mapping['CalculatorDemo'] = sibling( 'calculator.js').path diff --git a/examples/athenademo/typeahead.py b/examples/athenademo/typeahead.py index e738cf18..9e8c523b 100644 --- a/examples/athenademo/typeahead.py +++ b/examples/athenademo/typeahead.py @@ -3,10 +3,10 @@ from formless import annotate, webform from twisted.python import util -animals = {u'elf' : u'Pointy ears. Bad attitude regarding trees.', - u'chipmunk': u'Cute. Fuzzy. Sings horribly.', - u'chupacabra': u'It sucks goats.', - u'ninja': u'Stealthy and invisible, and technically an animal.', +animals = {'elf' : 'Pointy ears. Bad attitude regarding trees.', + 'chipmunk': 'Cute. Fuzzy. Sings horribly.', + 'chupacabra': 'It sucks goats.', + 'ninja': 'Stealthy and invisible, and technically an animal.', } @@ -26,8 +26,8 @@ class TypeAheadFieldFragment(athena.LiveFragment): ]) def loadDescription(self, typed): - if typed == u'': - return None, u'--' + if typed == '': + return None, '--' matches = [] for key in animals: if key.startswith(typed): @@ -35,9 +35,9 @@ def loadDescription(self, typed): if len(matches) == 1: return matches[0], animals[matches[0]] elif len(matches) > 1: - return None, u"(Multiple found)" + return None, "(Multiple found)" else: - return None, u'--' + return None, '--' athena.expose(loadDescription) class DataEntry(rend.Page): @@ -75,7 +75,7 @@ def animals(self, animal, description): return url.here def data_animals(self, ctx, data): - return animals.keys() + return list(animals.keys()) def child_typeahead(self, ctx): return TypeAheadPage(None, None) diff --git a/examples/athenademo/widgets.py b/examples/athenademo/widgets.py index 8669f948..02a74188 100644 --- a/examples/athenademo/widgets.py +++ b/examples/athenademo/widgets.py @@ -7,7 +7,7 @@ from nevow import athena, loaders, static class Clock(athena.LiveFragment): - jsClass = u"WidgetDemo.Clock" + jsClass = "WidgetDemo.Clock" docFactory = loaders.xmlstr('''\
",t.strong[inside_counter.next()+1],"<==="] + t.p(style="text-align: center")["===>",t.strong[next(inside_counter)+1],"<==="] ] class Root(Base): @@ -21,7 +21,7 @@ class Root(Base): def macro_content(self, ctx): return t.invisible[ t.p["This macro has been called ", - counter1.next()+1, + next(counter1)+1, " time(s)"], loaders.xmlfile(util.sibpath(__file__,'root_macro.html'), ignoreDocType=True).load() ] @@ -35,7 +35,7 @@ class Child(Base): def macro_content(self, ctx): return t.invisible[ t.p["This macro has been called ", - counter2.next()+1, + next(counter2)+1, " time(s)"], loaders.xmlfile(util.sibpath(__file__,'child_macro.html'), ignoreDocType=True).load() ] diff --git a/examples/manualform/manualform.py b/examples/manualform/manualform.py index 8019d86c..4a4ce8c4 100644 --- a/examples/manualform/manualform.py +++ b/examples/manualform/manualform.py @@ -17,7 +17,7 @@ def locateChild(self, ctx, segments): # Handle the form post if segments[0] == SUBMIT: # Just print out the name - print '*** name:', ctx.arg('name') + print('*** name:', ctx.arg('name')) # Redirect away from the POST return url.URL.fromContext(ctx), () diff --git a/examples/most_basic/most_basic.py b/examples/most_basic/most_basic.py index 70947d1b..f78b6019 100644 --- a/examples/most_basic/most_basic.py +++ b/examples/most_basic/most_basic.py @@ -1,4 +1,4 @@ -from zope.interface import implements +from zope.interface import implementer from nevow import inevow @@ -15,8 +15,8 @@ # tuple of (page, remaining_segments) # if there is no page, and you want to display a 404 page, you will need to return # a None, () tuple. +@implementer(inevow.IResource) class Root(object): - implements(inevow.IResource) def locateChild(self, ctx, segments): # This locateChild is 'stupid' since it can only work if the tree of @@ -42,8 +42,8 @@ def renderHTTP(self, ctx): foo """ +@implementer(inevow.IResource) class Foo(object): - implements(inevow.IResource) def locateChild(self, ctx, segments): # segments is the remaining segments returned by the root locateChild @@ -58,8 +58,8 @@ def renderHTTP(self, ctx): baz """ +@implementer(inevow.IResource) class Baz(object): - implements(inevow.IResource) def locateChild(self, ctx, segments): return None, () def renderHTTP(self, ctx): diff --git a/examples/pastebin/pastebin/service.py b/examples/pastebin/pastebin/service.py index fcae84eb..34c63d1e 100644 --- a/examples/pastebin/pastebin/service.py +++ b/examples/pastebin/pastebin/service.py @@ -1,7 +1,7 @@ -import cPickle as pickle +import pickle as pickle import os.path import time -from zope.interface import implements +from zope.interface import implementer from twisted.application import service from twisted.python import log @@ -19,9 +19,9 @@ def __init__(self, oid, author, time): self.version = 0 +@implementer(interfaces.IPasteBin) class FSPasteBinService(service.Service): - implements(interfaces.IPasteBin) def __init__(self, storageDir): self._dir = storageDir @@ -37,12 +37,12 @@ def _makeFilename(self, name): return os.path.join(self._dir, name) def _loadPastingData(self, oid): - f = file(self._makeFilename(str(oid)), 'rb') - return pickle.load(f) + with open(self._makeFilename(str(oid)), 'rb') as f: + return pickle.load(f) def _savePastingData(self, oid, data): - f = file(self._makeFilename(str(oid)), 'wb') - pickle.dump(data, f, pickle.HIGHEST_PROTOCOL) + with open(self._makeFilename(str(oid)), 'wb') as f: + pickle.dump(data, f, pickle.HIGHEST_PROTOCOL) def getPasting(self, oid): data = self._loadPastingData(oid) @@ -70,8 +70,8 @@ def updatePasting(self, oid, author, text): def startService(self): log.msg('Loading index') try: - f = file(self._makeFilename('index'), 'rb') - d = pickle.load(f) + with open(self._makeFilename('index'), 'rb') as f: + d = pickle.load(f) self._index = d['index'] self._nextOid = d['nextOid'] except IOError: @@ -81,12 +81,12 @@ def startService(self): def stopService(self): log.msg('Storing index') d = {'index':self._index, 'nextOid':self._nextOid} - f = file(self._makeFilename('index'), 'wb') - pickle.dump(d, f, pickle.HIGHEST_PROTOCOL) + with open(self._makeFilename('index'), 'wb'): + pickle.dump(d, f, pickle.HIGHEST_PROTOCOL) +@implementer(pasting.IPasting) class Pasting(object): - implements(pasting.IPasting) def __init__(self, data): self._data = data @@ -103,9 +103,9 @@ def getHistory(self): return history +@implementer(pasting.IVersion) class Version: - implements(pasting.IVersion) def __init__(self, data): self._data = data diff --git a/examples/pastebin/pastebin/web/pages.py b/examples/pastebin/pastebin/web/pages.py index 23bd662b..bc8ac659 100644 --- a/examples/pastebin/pastebin/web/pages.py +++ b/examples/pastebin/pastebin/web/pages.py @@ -1,6 +1,6 @@ -from cStringIO import StringIO +from io import StringIO import time -from zope.interface import implements +from zope.interface import implementer from twisted.python import htmlizer from twisted.web import static @@ -107,8 +107,8 @@ def render_content(self, context, data): return tag +@implementer(IAddPasting) class RootPage(BasePage): - implements(IAddPasting) addSlash = True @@ -132,9 +132,9 @@ def addPasting(self, request, author, text): request.setComponent(iformless.IRedirectAfterPost, '/'+str(oid)) +@implementer(IEditPasting) class Pasting(BasePage): - implements(IEditPasting) contentTemplateFile = 'pasting.html' def __init__(self, pastebin, pastingOid, version=-1): diff --git a/examples/postit/store.py b/examples/postit/store.py index 13c0ecdb..accfa28f 100644 --- a/examples/postit/store.py +++ b/examples/postit/store.py @@ -1,4 +1,4 @@ -from zope.interface import implements, Interface +from zope.interface import implementer, Interface from axiom import item, store from axiom.attributes import text, timestamp @@ -18,8 +18,8 @@ class Post(item.Item): author = text() created = timestamp() +@implementer(IPostit) class Application(item.Item, item.InstallableMixin): - implements(IPostit) name = text() @@ -37,11 +37,11 @@ def initialize(): s = store.Store('postit.axiom') postit = IPostit(s, None) if not postit: - Application(store=s, name=u'Postit').installOn(s) + Application(store=s, name='Postit').installOn(s) Post(store=s, - title=u"This is the title", - url=u"http://www.divmod.org", - content=u"Here is the content for the link", - author=u"dialtone", + title="This is the title", + url="http://www.divmod.org", + content="Here is the content for the link", + author="dialtone", created=Time()) return s diff --git a/examples/todo/controller.py b/examples/todo/controller.py index 7316e476..1f24a669 100644 --- a/examples/todo/controller.py +++ b/examples/todo/controller.py @@ -1,4 +1,4 @@ -from zope.interface import implements +from zope.interface import implementer from nevow import rend, loaders, tags as t from formless import annotate, webform @@ -21,8 +21,8 @@ def update(ctx=annotate.Context(), pass update = annotate.autocallable(update, invisible=True) +@implementer(ITodo) class Root(rend.Page): - implements(ITodo) child_css = webform.defaultCSS diff --git a/examples/todo/dispatcher.py b/examples/todo/dispatcher.py index 4254f1f2..5b02af98 100644 --- a/examples/todo/dispatcher.py +++ b/examples/todo/dispatcher.py @@ -1,3 +1,5 @@ +import imp + from nevow import rend import itodo import controller @@ -9,5 +11,5 @@ class Dispatch(rend.Page): def locateChild(self, ctx, segments): if itodo.IEnv(ctx).development: - reload(controller) + imp.reload(controller) return controller.root.locateChild(ctx,segments) diff --git a/examples/todo/store.py b/examples/todo/store.py index 021331f0..2c5c1b44 100644 --- a/examples/todo/store.py +++ b/examples/todo/store.py @@ -1,9 +1,9 @@ -from zope.interface import implements +from zope.interface import implementer import pgasync import itodo +@implementer(itodo.ITodos) class Todos(object): - implements(itodo.ITodos) def __init__(self, dbname, user, password, host): self.original = pgasync.ConnectionPool("pgasync", dbname=dbname, user=user, password=password, host=host) diff --git a/examples/tree/tree.py b/examples/tree/tree.py index 9abc3254..53002d0d 100644 --- a/examples/tree/tree.py +++ b/examples/tree/tree.py @@ -1,4 +1,4 @@ -from zope.interface import implements +from zope.interface import implementer from twisted.python.components import registerAdapter @@ -13,7 +13,7 @@ def __init__(self, name, description, *children): self.add(child) def add(self, child): self[child.name] = child - def __nonzero__(self): + def __bool__(self): return True class ITreeEdit(annotate.TypedInterface): @@ -28,8 +28,8 @@ def addChild(name=annotate.String(required=True), pass addChild = annotate.autocallable(addChild) +@implementer(ITreeEdit) class TreeRenderer(rend.Page): - implements(ITreeEdit) addSlash = True docFactory = loaders.htmlstr(""" @@ -55,7 +55,7 @@ def deleteChild(self, name): def data_description(self, context, data): return self.original.description def data_children(self, context, data): - return self.original.items() + return list(self.original.items()) def render_childLink(self, context, data): return T.a(href='subtree_%s/'%data[0])[data[1].description] def childFactory(self, ctx, name): @@ -63,7 +63,8 @@ def childFactory(self, ctx, name): return self.original[name[len('subtree_'):]] def render_descriptionForm(self, context, data): return webform.renderForms() - def render_childDel(self, context, (name, _)): + def render_childDel(self, context, xxx_todo_changeme): + (name, _) = xxx_todo_changeme ret = T.form(action="./freeform_post!!deleteChild", enctype="multipart/form-data", method="POST")[ T.input(type="hidden", name="name", value=name), diff --git a/examples/with_axiom/powerups.py b/examples/with_axiom/powerups.py index 61f617e4..312f674d 100644 --- a/examples/with_axiom/powerups.py +++ b/examples/with_axiom/powerups.py @@ -1,4 +1,4 @@ -from zope.interface import implements, Interface +from zope.interface import implementer, Interface from axiom import store, item, attributes @@ -12,8 +12,8 @@ class Book(item.Item): class ILibrary(Interface): pass +@implementer(ILibrary) class Library(item.Item, item.InstallableMixin): - implements(ILibrary) typeName = 'library' schemaVersion = 1 @@ -28,16 +28,16 @@ def addNewBook(self, title): newBook = Book(store=self.store, title=title) def getBookByTitle(self, title): - books = self.store.query(Book, Book.title == unicode(title)) + books = self.store.query(Book, Book.title == str(title)) for book in books: return book def initialize(dbdir): # This is store initialization. s = store.Store(dbdir) - l = Library(store=s, name=u"Great Library") + l = Library(store=s, name="Great Library") l.installOn(s) - descr = u"""This book is totally useless, in fact nobody would + descr = """This book is totally useless, in fact nobody would borrow it""" - Book(store=s, title=u"Title: 1", description=descr) + Book(store=s, title="Title: 1", description=descr) return s diff --git a/formless/annotate.py b/formless/annotate.py index 385b4332..6c436ac0 100644 --- a/formless/annotate.py +++ b/formless/annotate.py @@ -10,7 +10,7 @@ import sys import inspect import warnings -from zope.interface import implements +from zope.interface import implementer from zope.interface.interface import InterfaceClass, Attribute from nevow import util @@ -22,11 +22,11 @@ class count(object): def __init__(self): self.id = 0 - def next(self): + def __next__(self): self.id += 1 return self.id -nextId = count().next +nextId = count().__next__ class InputError(Exception): @@ -69,6 +69,7 @@ def __str__(self): +@implementer(iformless.ITyped) class Typed(Attribute): """A typed value. Subclasses of Typed are constructed inside of TypedInterface class definitions to describe the types of properties, @@ -92,7 +93,6 @@ class Typed(Attribute): of the data from the browser and pass unicode strings to coerce. """ - implements(iformless.ITyped) complexType = False strip = False @@ -102,7 +102,7 @@ class Typed(Attribute): required = False requiredFailMessage = 'Please enter a value' null = None - unicode = False + str = False __name__ = '' @@ -114,7 +114,7 @@ def __init__( required=None, requiredFailMessage=None, null=None, - unicode=None, + str=None, **attributes): self.id = nextId() @@ -130,15 +130,15 @@ def __init__( self.requiredFailMessage = requiredFailMessage if null is not None: self.null = null - if unicode is not None: - self.unicode = unicode + if str is not None: + self.str = str self.attributes = attributes def getAttribute(self, name, default=None): return self.attributes.get(name, default) def coerce(self, val, configurable): - raise NotImplementedError, "Implement in %s" % util.qual(self.__class__) + raise NotImplementedError("Implement in %s" % util.qual(self.__class__)) ####################################### @@ -209,7 +209,7 @@ def coerce(self, val, configurable): except ValueError: if sys.version_info < (2,3): # Long/Int aren't integrated try: - return long(val) + return int(val) except ValueError: raise InputError("'%s' is not an integer." % val) @@ -358,8 +358,8 @@ def __repr__(self): +@implementer(iformless.IActionableType) class List(Object): - implements(iformless.IActionableType) complexType = True def __init__(self, actions=None, header='', footer='', separator='', *args, **kw): @@ -489,6 +489,7 @@ def autocallable(method, action=None, visible=False, **kw): ####################################### +@implementer(iformless.IBinding) class Binding(object): """Bindings bind a Typed instance to a name. When TypedInterface is subclassed, the metaclass looks through the dict looking for all properties and methods. @@ -508,7 +509,6 @@ class Binding(object): Binding when it is constructed to keep track of what the method is supposed to return. """ - implements(iformless.IBinding) label = None description = '' @@ -540,7 +540,7 @@ def getViewName(self): return self.original.__class__.__name__.lower() def configure(self, boundTo, results): - raise NotImplementedError, "Implement in %s" % util.qual(self.__class__) + raise NotImplementedError("Implement in %s" % util.qual(self.__class__)) def coerce(self, val, configurable): if hasattr(self.original, 'coerce'): @@ -617,11 +617,7 @@ def __init__(self, name, typedValue, id=0): self.complexType = typedValue.complexType def configure(self, boundTo, group): - print "CONFIGURING GROUP BINDING", boundTo, group - - -def _sorter(x, y): - return cmp(x.id, y.id) + print("CONFIGURING GROUP BINDING", boundTo, group) class _Marker(object): @@ -670,13 +666,22 @@ def nameToLabel(mname): def labelAndDescriptionFromDocstring(docstring): if docstring is None: docstring = '' - docs = filter(lambda x: x, [x.strip() for x in docstring.split('\n')]) + docs = [x for x in [x.strip() for x in docstring.split('\n')] if x] if len(docs) > 1: return docs[0], '\n'.join(docs[1:]) else: return None, '\n'.join(docs) +def _getKeyForObject(ob): + """returns an object's id. + + This is used to have a reliable ordering of functions and properties + below. + """ + return ob.id + + class MetaTypedInterface(InterfaceClass): """The metaclass for TypedInterface. When TypedInterface is subclassed, this metaclass' __new__ method is invoked. The Typed Binding introspection @@ -723,7 +728,7 @@ def __new__(cls, name, bases, dct): cls.complexType = True possibleActions = [] actionAttachers = [] - for key, value in dct.items(): + for key, value in list(dct.items()): if key[0] == '_': continue if isinstance(value, MetaTypedInterface): @@ -813,10 +818,10 @@ def __new__(cls, name, bases, dct): ) for attacher in actionAttachers: attacher.attachActionBindings(possibleActions) - methods.sort(_sorter) - properties.sort(_sorter) + methods.sort(key=_getKeyForObject) + properties.sort(key=_getKeyForObject) cls.__spec__ = spec = methods + properties - spec.sort(_sorter) + spec.sort(key=_getKeyForObject) cls.name = name # because attributes "label" and "description" would become Properties, diff --git a/formless/configurable.py b/formless/configurable.py index f2904d1f..4c004937 100644 --- a/formless/configurable.py +++ b/formless/configurable.py @@ -1,7 +1,7 @@ # Copyright (c) 2004 Divmod. # See LICENSE for details. -from zope.interface import implements, providedBy +from zope.interface import implementer, providedBy from formless.iformless import IConfigurable, IActionableType, IBinding from formless.annotate import Argument, ElementBinding, GroupBinding, Object, TypedInterface @@ -9,8 +9,8 @@ from nevow import inevow from nevow.context import WovenContext +@implementer(IConfigurable) class Configurable(object): - implements(IConfigurable) bindingDict = None @@ -66,7 +66,7 @@ def getBinding(self, context, name): try: binding = self.bindingDict[name] except KeyError: - raise RuntimeError, "%s is not an exposed binding on object %s." % (name, self.boundTo) + raise RuntimeError("%s is not an exposed binding on object %s." % (name, self.boundTo)) binding.boundTo = self.boundTo return binding @@ -125,7 +125,7 @@ def summary(self): class NotFoundConfigurable(Configurable): def getBinding(self, context, name): - raise RuntimeError, self.original + raise RuntimeError(self.original) class TypedInterfaceConfigurable(Configurable): diff --git a/formless/formutils.py b/formless/formutils.py index 3e327159..381e1475 100644 --- a/formless/formutils.py +++ b/formless/formutils.py @@ -1,9 +1,9 @@ # Copyright (c) 2004 Divmod. # See LICENSE for details. -from __future__ import generators -from zope.interface import implements + +from zope.interface import implementer from twisted.python import components @@ -20,7 +20,7 @@ def enumerate(collection): i = 0 it = iter(collection) while 1: - yield (i, it.next()) + yield (i, next(it)) i += 1 @@ -48,7 +48,7 @@ def __getitem__(self, key): return self.errors[pfxkey] def update(self, other): - for key, value in other.items(): + for key, value in list(other.items()): self[key] = value @@ -86,10 +86,10 @@ def clearAll(self): self.defaults = {} +@implementer(iformless.IFormErrors) class FormErrors(components.Adapter): """An object which keeps track of which forms have which errors """ - implements(iformless.IFormErrors) def __init__(self): self.errors = {} @@ -107,7 +107,7 @@ def updateErrors(self, formName, errors): PrefixerDict(formName, self.errors).update(errors) def clearErrors(self, formName): - for key in self.errors.keys(): + for key in list(self.errors.keys()): if key.startswith(formName): del self.errors[key] diff --git a/formless/processors.py b/formless/processors.py index 10e807f5..4f945524 100644 --- a/formless/processors.py +++ b/formless/processors.py @@ -2,7 +2,7 @@ # See LICENSE for details. import warnings -from zope.interface import implements +from zope.interface import implementer from twisted.python import components @@ -21,7 +21,7 @@ def exceptblock(f, handler, exception, *a, **kw): try: result = f(*a, **kw) - except exception, e: + except exception as e: return handler(e) if isinstance(result, Deferred): def _(fail): @@ -32,8 +32,8 @@ def _(fail): return result +@implementer(iformless.IInputProcessor) class ProcessGroupBinding(components.Adapter): - implements(iformless.IInputProcessor) def process(self, context, boundTo, data): ## THE SPEC: self.original.typedValue.iface.__spec__ @@ -79,8 +79,8 @@ def _finish(ignored): raise formless.ValidateError(failures, 'Error:', results) return DeferredList(waiters).addBoth(_finish) +@implementer(iformless.IInputProcessor) class ProcessMethodBinding(components.Adapter): - implements(iformless.IInputProcessor) def process(self, context, boundTo, data, autoConfigure = True): """Knows how to process a dictionary of lists @@ -91,7 +91,7 @@ def process(self, context, boundTo, data, autoConfigure = True): typedValue = self.original.typedValue results = {} failures = {} - if data.has_key('----'): + if '----' in data: ## ---- is the "direct object", the one argument you can specify using the command line without saying what the argument name is data[typedValue.arguments[0].name] = data['----'] del data['----'] @@ -101,7 +101,7 @@ def process(self, context, boundTo, data, autoConfigure = True): context = WovenContext(context, faketag) context.remember(binding, iformless.IBinding) results[name] = iformless.IInputProcessor(binding.typedValue).process(context, boundTo, data.get(name, [''])) - except formless.InputError, e: + except formless.InputError as e: results[name] = data.get(name, [''])[0] failures[name] = e.reason @@ -117,8 +117,8 @@ def _except(e): boundTo, results) return results +@implementer(iformless.IInputProcessor) class ProcessPropertyBinding(components.Adapter): - implements(iformless.IInputProcessor) def process(self, context, boundTo, data, autoConfigure = True): """Knows how to process a dictionary of lists @@ -130,27 +130,27 @@ def process(self, context, boundTo, data, autoConfigure = True): result = {} try: result[binding.name] = iformless.IInputProcessor(binding.typedValue).process(context, boundTo, data.get(binding.name, [''])) - except formless.InputError, e: + except formless.InputError as e: result[binding.name] = data.get(binding.name, ['']) raise formless.ValidateError({binding.name: e.reason}, e.reason, result) if autoConfigure: try: return self.original.configure(boundTo, result) - except formless.InputError, e: + except formless.InputError as e: result[binding.name] = data.get(binding.name, ['']) raise formless.ValidateError({binding.name: e.reason}, e.reason, result) return result +@implementer(iformless.IInputProcessor) class ProcessTyped(components.Adapter): - implements(iformless.IInputProcessor) def process(self, context, boundTo, data): """data is a list of strings at this point """ typed = self.original val = data[0] - if typed.unicode: + if typed.str: try: val = val.decode(getPOSTCharset(context), 'replace') except LookupError: @@ -164,12 +164,12 @@ def process(self, context, boundTo, data): return typed.null try: return typed.coerce(val, boundTo) - except TypeError, e: + except TypeError as e: warnings.warn('Typed.coerce takes two values now, the value to coerce and the configurable in whose context the coerce is taking place. %s %s' % (typed.__class__, typed)) return typed.coerce(val) +@implementer(iformless.IInputProcessor) class ProcessPassword(components.Adapter): - implements(iformless.IInputProcessor) def process(self, context, boundTo, data): """Password needs to look at two passwords in the data, @@ -190,7 +190,7 @@ def process(self, context, boundTo, data): else: return typed.null val = data[0] - if typed.unicode: + if typed.str: try: val = val.decode(getPOSTCharset(context), 'replace') except LookupError: @@ -201,22 +201,22 @@ def process(self, context, boundTo, data): warnings.warn('Typed.coerce takes two values now, the value to coerce and the configurable in whose context the coerce is taking place. %s %s' % (typed.__class__, typed)) return typed.coerce(data[0]) +@implementer(iformless.IInputProcessor) class ProcessRequest(components.Adapter): - implements(iformless.IInputProcessor) def process(self, context, boundTo, data): return context.locate(inevow.IRequest) +@implementer(iformless.IInputProcessor) class ProcessContext(components.Adapter): - implements(iformless.IInputProcessor) def process(self, context, boundTo, data): return context +@implementer(iformless.IInputProcessor) class ProcessUpload(components.Adapter): - implements(iformless.IInputProcessor) def process(self, context, boundTo, data): diff --git a/formless/test/test_formless.py b/formless/test/test_formless.py index 146acbf9..74d54038 100644 --- a/formless/test/test_formless.py +++ b/formless/test/test_formless.py @@ -16,60 +16,60 @@ def process(typed, value): class Typed(TestCase): def testString(self): s = formless.String() - self.assertEquals(process(s, ''), None) - self.assertEquals(process(s, "Fooo"), "Fooo") - self.assertEquals(process(s, "This is a string"), "This is a string") - self.assertEquals(process(s, 'C\xc3\xa9sar'), 'C\xc3\xa9sar') + self.assertEqual(process(s, ''), None) + self.assertEqual(process(s, "Fooo"), "Fooo") + self.assertEqual(process(s, "This is a string"), "This is a string") + self.assertEqual(process(s, 'C\xc3\xa9sar'), 'C\xc3\xa9sar') - s = formless.String(unicode=True) - self.assertEquals(process(s, 'C\xc3\xa9sar'), u'C\u00e9sar') + s = formless.String(str=True) + self.assertEqual(process(s, 'C\xc3\xa9sar'), 'C\u00e9sar') s = formless.String(required=True) self.assertRaises(formless.InputError, process, s, "") s = formless.String(required=False) - self.assertEquals(process(s, "Bar"), "Bar") - self.assertEquals(process(s, ""), None) + self.assertEqual(process(s, "Bar"), "Bar") + self.assertEqual(process(s, ""), None) s = formless.String() - self.assertEquals(process(s, ' abc '), ' abc ') + self.assertEqual(process(s, ' abc '), ' abc ') s = formless.String(strip=True, required=True) - self.assertEquals(process(s, ' abc '), 'abc') - self.assertEquals(process(s, '\t abc \t \n '), 'abc') + self.assertEqual(process(s, ' abc '), 'abc') + self.assertEqual(process(s, '\t abc \t \n '), 'abc') self.assertRaises(formless.InputError, process, s, ' ') s = formless.String(required=False, strip=True) - self.assertEquals(process(s, ' abc '), 'abc') - self.assertEquals(process(s, ' '), None) + self.assertEqual(process(s, ' abc '), 'abc') + self.assertEqual(process(s, ' '), None) def testText(self): s = formless.Text() - self.assertEquals(process(s, ""), None) - self.assertEquals(process(s, "Fooo"), "Fooo") - self.assertEquals(process(s, "This is a string"), "This is a string") - self.assertEquals(process(s, 'C\xc3\xa9sar'), 'C\xc3\xa9sar') + self.assertEqual(process(s, ""), None) + self.assertEqual(process(s, "Fooo"), "Fooo") + self.assertEqual(process(s, "This is a string"), "This is a string") + self.assertEqual(process(s, 'C\xc3\xa9sar'), 'C\xc3\xa9sar') - s = formless.Text(unicode=True) - self.assertEquals(process(s, 'C\xc3\xa9sar'), u'C\u00e9sar') + s = formless.Text(str=True) + self.assertEqual(process(s, 'C\xc3\xa9sar'), 'C\u00e9sar') s = formless.Text(required=True) self.assertRaises(formless.InputError, process, s, "") s = formless.Text(required=False) - self.assertEquals(process(s, "Bar"), "Bar") - self.assertEquals(process(s, ""), None) + self.assertEqual(process(s, "Bar"), "Bar") + self.assertEqual(process(s, ""), None) s = formless.Text() - self.assertEquals(process(s, ' abc '), ' abc ') + self.assertEqual(process(s, ' abc '), ' abc ') s = formless.Text(strip=True, required=True) - self.assertEquals(process(s, ' abc '), 'abc') + self.assertEqual(process(s, ' abc '), 'abc') self.assertRaises(formless.InputError, process, s, ' ') s = formless.Text(required=False, strip=True) - self.assertEquals(process(s, ' abc '), 'abc') - self.assertEquals(process(s, ' '), None) + self.assertEqual(process(s, ' abc '), 'abc') + self.assertEqual(process(s, ' '), None) def testPassword(self): @@ -80,64 +80,64 @@ def process(pw, val, val2=None): {'password': [val], 'password____2': [val2]})['password'] s = formless.Password() - self.assertEquals(process(s, "Fooo"), "Fooo") - self.assertEquals(process(s, "This is a string"), "This is a string") - self.assertEquals(process(s, "This is a string"), "This is a string") - self.assertEquals(process(s, 'C\xc3\xa9sar'), 'C\xc3\xa9sar') + self.assertEqual(process(s, "Fooo"), "Fooo") + self.assertEqual(process(s, "This is a string"), "This is a string") + self.assertEqual(process(s, "This is a string"), "This is a string") + self.assertEqual(process(s, 'C\xc3\xa9sar'), 'C\xc3\xa9sar') - s = formless.Password(unicode=True) - self.assertEquals(process(s, 'C\xc3\xa9sar'), u'C\u00e9sar') + s = formless.Password(str=True) + self.assertEqual(process(s, 'C\xc3\xa9sar'), 'C\u00e9sar') s = formless.Password(required=True) self.assertRaises(formless.ValidateError, process, s, "") s = formless.Password(required=False) - self.assertEquals(process(s, "Bar"), "Bar") - self.assertEquals(process(s, ""), None) + self.assertEqual(process(s, "Bar"), "Bar") + self.assertEqual(process(s, ""), None) s = formless.Password() - self.assertEquals(process(s, ' abc '), ' abc ') + self.assertEqual(process(s, ' abc '), ' abc ') s = formless.Password(strip=True, required=True) - self.assertEquals(process(s, ' abc '), 'abc') + self.assertEqual(process(s, ' abc '), 'abc') self.assertRaises(formless.ValidateError, process, s, ' ') s = formless.Password(required=False, strip=True) - self.assertEquals(process(s, ' abc '), 'abc') - self.assertEquals(process(s, ' '), None) + self.assertEqual(process(s, ' abc '), 'abc') + self.assertEqual(process(s, ' '), None) def testPasswordEntry(self): s = formless.PasswordEntry() - self.assertEquals(process(s, ''), None) - self.assertEquals(process(s, 'abc'), 'abc') - self.assertEquals(process(s, ' blah blah blah '), ' blah blah blah ') - self.assertEquals(process(s, 'C\xc3\xa9sar'), 'C\xc3\xa9sar') + self.assertEqual(process(s, ''), None) + self.assertEqual(process(s, 'abc'), 'abc') + self.assertEqual(process(s, ' blah blah blah '), ' blah blah blah ') + self.assertEqual(process(s, 'C\xc3\xa9sar'), 'C\xc3\xa9sar') - s = formless.PasswordEntry(unicode=True) - self.assertEquals(process(s, 'C\xc3\xa9sar'), u'C\u00e9sar') + s = formless.PasswordEntry(str=True) + self.assertEqual(process(s, 'C\xc3\xa9sar'), 'C\u00e9sar') s = formless.PasswordEntry(strip=True) - self.assertEquals(process(s, ''), None) - self.assertEquals(process(s, 'abc'), 'abc') - self.assertEquals(process(s, ' blah blah blah '), 'blah blah blah') + self.assertEqual(process(s, ''), None) + self.assertEqual(process(s, 'abc'), 'abc') + self.assertEqual(process(s, ' blah blah blah '), 'blah blah blah') s = formless.PasswordEntry(strip=True, required=True) self.assertRaises(formless.InputError, process, s, '') self.assertRaises(formless.InputError, process, s, ' ') - self.assertEquals(process(s, 'abc'), 'abc') - self.assertEquals(process(s, ' blah blah blah '), 'blah blah blah') + self.assertEqual(process(s, 'abc'), 'abc') + self.assertEqual(process(s, ' blah blah blah '), 'blah blah blah') def testInteger(self): i = formless.Integer(required=True) - self.assertEquals(process(i, "0"), 0) - self.assertEquals(process(i, "3409823098"), 3409823098) + self.assertEqual(process(i, "0"), 0) + self.assertEqual(process(i, "3409823098"), 3409823098) self.assertRaises(formless.InputError, process, i, "") self.assertRaises(formless.InputError, process, i, "a string") self.assertRaises(formless.InputError, process, i, "1.5") i = formless.Integer(required=False) - self.assertEquals(process(i, "1234567"), 1234567) - self.assertEquals(process(i, ""), None) + self.assertEqual(process(i, "1234567"), 1234567) + self.assertEqual(process(i, ""), None) def testReal(self): i = formless.Real(required=True) @@ -149,7 +149,7 @@ def testReal(self): i = formless.Real(required=False) self.assertApproximates(process(i, "1234.567"), 1234.567, 1e-10) - self.assertEquals(process(i, ""), None) + self.assertEqual(process(i, ""), None) def testBoolean(self): b = formless.Boolean(required=True) @@ -157,19 +157,19 @@ def testBoolean(self): self.assertRaises(formless.InputError, process, b, True) self.assertRaises(formless.InputError, process, b, 54) self.assertRaises(formless.InputError, process, b, "") - self.assertEquals(process(b, "True"), True) - self.assertEquals(process(b, "False"), False) + self.assertEqual(process(b, "True"), True) + self.assertEqual(process(b, "False"), False) b = formless.Boolean(required=False) self.assertRaises(formless.InputError, process, b, "zoom") - self.assertEquals(process(b, ""), None) - self.assertEquals(process(b, "True"), True) - self.assertEquals(process(b, "False"), False) + self.assertEqual(process(b, ""), None) + self.assertEqual(process(b, "True"), True) + self.assertEqual(process(b, "False"), False) def testFixedDigitInteger(self): d = formless.FixedDigitInteger(3, required=True) - self.assertEquals(process(d, "123"), 123) - self.assertEquals(process(d, "567"), 567) + self.assertEqual(process(d, "123"), 123) + self.assertEqual(process(d, "567"), 567) self.assertRaises(formless.InputError, process, d, "12") self.assertRaises(formless.InputError, process, d, "1234") self.assertRaises(formless.InputError, process, d, "012") @@ -178,9 +178,9 @@ def testFixedDigitInteger(self): self.assertRaises(formless.InputError, process, d, "") d = formless.FixedDigitInteger(3, required=False) - self.assertEquals(process(d, "123"), 123) + self.assertEqual(process(d, "123"), 123) self.assertRaises(formless.InputError, process, d, "foo") - self.assertEquals(process(d, ""), None) + self.assertEqual(process(d, ""), None) def testDirectory(self): p1 = self.mktemp() @@ -188,14 +188,14 @@ def testDirectory(self): p2 = self.mktemp() d = formless.Directory(required=True) - self.assertEquals(process(d, p1), p1) + self.assertEqual(process(d, p1), p1) self.assertRaises(formless.InputError, process, d, p2) self.assertRaises(formless.InputError, process, d, "") d = formless.Directory(required=False) - self.assertEquals(process(d, p1), p1) + self.assertEqual(process(d, p1), p1) self.assertRaises(formless.InputError, process, d, p2) - self.assertEquals(process(d, ""), None) + self.assertEqual(process(d, ""), None) class Annotation(TestCase): @@ -209,20 +209,20 @@ class Test(formless.TypedInterface): baz = formless.Integer() quux = formless.Object(interface=_indirectOther()) - self.assertEquals(Test.__properties__, Test.__spec__) + self.assertEqual(Test.__properties__, Test.__spec__) bfoo, bbar, bbaz, quux = Test.__properties__ - self.assertEquals(bfoo.name, 'foo') - self.assertEquals(bbar.name, 'bar') - self.assertEquals(bbaz.name, 'baz') + self.assertEqual(bfoo.name, 'foo') + self.assertEqual(bbar.name, 'bar') + self.assertEqual(bbaz.name, 'baz') - self.assertEquals(bfoo.typedValue.__class__, formless.String) - self.assertEquals(bbar.typedValue.__class__, formless.Text) - self.assertEquals(bbaz.typedValue.__class__, formless.Integer) - self.assertEquals(quux.typedValue.__class__, formless.Object) + self.assertEqual(bfoo.typedValue.__class__, formless.String) + self.assertEqual(bbar.typedValue.__class__, formless.Text) + self.assertEqual(bbaz.typedValue.__class__, formless.Integer) + self.assertEqual(quux.typedValue.__class__, formless.Object) - self.assertEquals(quux.typedValue.iface, Other) + self.assertEqual(quux.typedValue.iface, Other) def testTypedInterfaceMethods(self): @@ -249,47 +249,47 @@ def baz(bazfoo=formless.Boolean(label="The Foo", description="The foo to baz.")) return IFoo baz = formless.autocallable(baz) - self.assertEquals(Test2.__methods__, Test2.__spec__) + self.assertEqual(Test2.__methods__, Test2.__spec__) bfoo, bbar, bbaz = Test2.__methods__ - self.assertEquals(bfoo.name, 'foo') - self.assertEquals(bbar.name, 'bar') - self.assertEquals(bbar.getAttribute('someAttribute'), "Hello") - self.assertEquals(bbaz.name, 'baz') + self.assertEqual(bfoo.name, 'foo') + self.assertEqual(bbar.name, 'bar') + self.assertEqual(bbar.getAttribute('someAttribute'), "Hello") + self.assertEqual(bbaz.name, 'baz') - self.assertEquals(bfoo.label, 'Foo') - self.assertEquals(bfoo.description, 'This is a description of foo') + self.assertEqual(bfoo.label, 'Foo') + self.assertEqual(bfoo.description, 'This is a description of foo') - self.assertEquals(bbar.label, 'Bar') - self.assertEquals(bbar.description, '') + self.assertEqual(bbar.label, 'Bar') + self.assertEqual(bbar.description, '') - self.assertEquals(bbaz.label, 'The Label') - self.assertEquals(bbaz.description, 'The description') + self.assertEqual(bbaz.label, 'The Label') + self.assertEqual(bbaz.description, 'The description') def getArgTypes(mbinding): return [x.typedValue.__class__ for x in mbinding.arguments] - self.assertEquals(getArgTypes(bfoo), [formless.String]) - self.assertEquals(bfoo.returnValue.iface, None) + self.assertEqual(getArgTypes(bfoo), [formless.String]) + self.assertEqual(bfoo.returnValue.iface, None) - self.assertEquals(getArgTypes(bbar), [formless.Integer]) - self.assertEquals(bbar.returnValue.__class__, formless.String) + self.assertEqual(getArgTypes(bbar), [formless.Integer]) + self.assertEqual(bbar.returnValue.__class__, formless.String) - self.assertEquals(getArgTypes(bbaz), [formless.Boolean]) - self.assertEquals(bbaz.returnValue.iface, IFoo) + self.assertEqual(getArgTypes(bbaz), [formless.Boolean]) + self.assertEqual(bbaz.returnValue.iface, IFoo) def firstArg(mbinding): return mbinding.arguments[0] - self.assertEquals(firstArg(bfoo).label, 'Foobar') - self.assertEquals(firstArg(bfoo).description, '') + self.assertEqual(firstArg(bfoo).label, 'Foobar') + self.assertEqual(firstArg(bfoo).description, '') - self.assertEquals(firstArg(bbar).label, 'The Baz') - self.assertEquals(firstArg(bbar).description, '') + self.assertEqual(firstArg(bbar).label, 'The Baz') + self.assertEqual(firstArg(bbar).description, '') - self.assertEquals(firstArg(bbaz).label, 'The Foo') - self.assertEquals(firstArg(bbaz).description, 'The foo to baz.') + self.assertEqual(firstArg(bbaz).label, 'The Foo') + self.assertEqual(firstArg(bbaz).description, 'The foo to baz.') def testTypedInterfaceMethods_actionLabel(self): """When no label was given, docstring is given preference compared to action.""" @@ -302,13 +302,13 @@ def foo(foobar=formless.String()): pass foo = formless.autocallable(foo, action="Do something!") - self.assertEquals(Test.__methods__, Test.__spec__) + self.assertEqual(Test.__methods__, Test.__spec__) (bfoo,) = Test.__methods__ - self.assertEquals(bfoo.name, 'foo') + self.assertEqual(bfoo.name, 'foo') - self.assertEquals(bfoo.label, 'Label for foo') - self.assertEquals(bfoo.description, 'Description for foo') + self.assertEqual(bfoo.label, 'Label for foo') + self.assertEqual(bfoo.description, 'Description for foo') def testTypedInterfaceMethods_explicitLabel(self): """When a label was given, it is given preference compared to docstring.""" @@ -324,13 +324,13 @@ def foo(foobar=formless.String()): label="Explicit label for foo", ) - self.assertEquals(Test.__methods__, Test.__spec__) + self.assertEqual(Test.__methods__, Test.__spec__) (bfoo,) = Test.__methods__ - self.assertEquals(bfoo.name, 'foo') + self.assertEqual(bfoo.name, 'foo') - self.assertEquals(bfoo.label, 'Explicit label for foo') - self.assertEquals(bfoo.description, 'Description for foo') + self.assertEqual(bfoo.label, 'Explicit label for foo') + self.assertEqual(bfoo.description, 'Description for foo') def testTypedInterfaceMethods_deprecated(self): class Test(formless.TypedInterface): @@ -342,19 +342,19 @@ def oneArg(self, someParam=formless.String()): pass oneArg = formless.autocallable(oneArg) - self.assertEquals(Test.__methods__, Test.__spec__) + self.assertEqual(Test.__methods__, Test.__spec__) m_noArgs, m_oneArg = Test.__methods__ - self.assertEquals(len(m_noArgs.arguments), 0) - self.assertEquals(len(m_oneArg.arguments), 1) + self.assertEqual(len(m_noArgs.arguments), 0) + self.assertEqual(len(m_oneArg.arguments), 1) def testTypedInterfaceMethods_nonAutocallable(self): class Test(formless.TypedInterface): def notAutocallable(arg1, arg2): pass - self.assertEquals(Test.__methods__, Test.__spec__) - self.assertEquals(Test.__methods__, []) + self.assertEqual(Test.__methods__, Test.__spec__) + self.assertEqual(Test.__methods__, []) class IListWithActions(formless.TypedInterface): def actionOne(theSubset = formless.List()): @@ -370,8 +370,8 @@ def test_listActionMetadata(self): ## IListWithActions only has one binding, a Property binding ## of theListOfStuff to a List with some actions. actions = IListWithActions.__spec__[0].typedValue.actions - self.failUnless(reduce, (lambda x: x.name == 'actionOne', actions)) - self.failUnless(reduce, (lambda x: x.name == 'actionTwo', actions)) + self.assertTrue(reduce, (lambda x: x.name == 'actionOne', actions)) + self.assertTrue(reduce, (lambda x: x.name == 'actionTwo', actions)) class TestPropertyGroups(TestCase): @@ -386,5 +386,5 @@ class Inner(formless.TypedInterface): """ anInnerProperty = formless.Integer() - self.assertEquals(Outer.__spec__[1].typedValue.iface, Outer.Inner) + self.assertEqual(Outer.__spec__[1].typedValue.iface, Outer.Inner) inn = Outer.__spec__[1].typedValue.iface diff --git a/formless/test/test_freeform.py b/formless/test/test_freeform.py index 3bba7522..eccfde5f 100644 --- a/formless/test/test_freeform.py +++ b/formless/test/test_freeform.py @@ -1,7 +1,7 @@ # Copyright (c) 2004 Divmod. # See LICENSE for details. -from zope.interface import implements +from zope.interface import implementer from twisted.python import components @@ -17,8 +17,8 @@ from nevow.test import test_flatstan +@implementer(iformless.IConfigurableFactory) class Base(test_flatstan.Base): - implements(iformless.IConfigurableFactory) synchronousLocateConfigurable = False @@ -69,8 +69,8 @@ def test_configureProperty(self): class IStupid(formless.TypedInterface): foo = formless.String() + @implementer(IStupid) class StupidThing(configurable.Configurable): - implements(IStupid) def __init__(self): configurable.Configurable.__init__(self, None) @@ -92,8 +92,8 @@ def foo(bar=formless.String()): return formless.String() foo = formless.autocallable(foo) + @implementer(IDumb) class DumbThing(configurable.Configurable): - implements(IDumb) def foo(self, bar): return "baz" @@ -184,8 +184,8 @@ def test_2_renderWithObjectPropertyValues(self): class IDefaultProperty(formless.TypedInterface): default = formless.Integer(default=2) + @implementer(IDefaultProperty) class Foo(configurable.Configurable): - implements(IDefaultProperty) default = 54 def later(val): @@ -200,8 +200,8 @@ class IDefaultProperty(formless.TypedInterface): class Adaptee(object): default = 69 + @implementer(IDefaultProperty) class Bar(configurable.Configurable): - implements(IDefaultProperty) def later(val): self.failIfSubstring('2', val) @@ -216,8 +216,8 @@ def aMethod(foo=formless.String(default="The foo")): aProperty = formless.String(default="The property") + @implementer(IBindingDefaults) class Implements(configurable.Configurable): - implements(IBindingDefaults) def later(val): self.assertSubstring("The foo", val) @@ -233,8 +233,8 @@ def bMethod(foo=formless.String(default="NOTBAR")): aMethod = formless.autocallable(aMethod) bMethod = formless.autocallable(bMethod) + @implementer(IDynamicDefaults) class Implements(configurable.Configurable): - implements(IDynamicDefaults) def later(val): self.assertSubstring("YESFOO", val) @@ -256,7 +256,7 @@ def aMethod(aString = formless.String()): aMethod = formless.autocallable(aMethod) class ANonConfigurable(object): # Not subclassing Configurable - implements(ISimpleTypedInterface) # But implements a TypedInterface + @implementer(ISimpleTypedInterface) # But implements a TypedInterface def later(val): self.assertSubstring('anInt', val) @@ -273,8 +273,8 @@ def password(pword = formless.Password(), integer=formless.Integer()): pass password = formless.autocallable(password) + @implementer(IAPasswordMethod) class APasswordImplementation(object): - implements(IAPasswordMethod) matched = False def password(self, pword, integer): self.matched = True @@ -285,7 +285,7 @@ def password(self, pword, integer): D = self.postForm(ctx, theObj, "password", {"pword": ["these passwords"], "pword____2": ["don't match"], 'integer': ['Not integer']}) def after(result): - self.assertEquals(theObj.matched, False) + self.assertEqual(theObj.matched, False) def later(val): self.assertSubstring("Passwords do not match. Please reenter.", val) self.assertSubstring('value="Not integer"', val) @@ -296,8 +296,8 @@ def test_2_propertyFailed(self): class IAProperty(formless.TypedInterface): prop = formless.Integer() + @implementer(IAProperty) class Impl(object): - implements(IAProperty) prop = 5 theObj = Impl() @@ -325,8 +325,8 @@ def buriedAlive(): pass buriedAlive = formless.autocallable(buriedAlive) + @implementer(Outer) class Implementation(object): - implements(Outer) one = 1 two = 2 buckled = False @@ -344,10 +344,10 @@ def later(val): def after(result): - self.assertEquals(impl.one, 1) - self.assertEquals(impl.two, 2) - self.assertEquals(impl.buckled, False) - self.assertEquals(impl.buried, False) + self.assertEqual(impl.one, 1) + self.assertEqual(impl.two, 2) + self.assertEqual(impl.buckled, False) + self.assertEqual(impl.buried, False) def evenlater(moreval): self.assertSubstring("is not an integer", moreval) @@ -355,10 +355,10 @@ def evenlater(moreval): #self.assertSubstring('value="Not an integer"', moreval) DD = self.postForm(ctx, impl, "Inner", {'one': ['11'], 'two': ['22']}) def afterafter(ign): - self.assertEquals(impl.one, 11) - self.assertEquals(impl.two, 22) - self.assertEquals(impl.buckled, True) - self.assertEquals(impl.buried, True) + self.assertEqual(impl.one, 11) + self.assertEqual(impl.two, 22) + self.assertEqual(impl.buckled, True) + self.assertEqual(impl.buried, True) return DD.addCallback(afterafter) return self.renderForms(impl, ctx).addCallback(evenlater) return D.addCallback(after) @@ -373,8 +373,8 @@ def foo(abc=formless.String()): pass foo = formless.autocallable(foo) + @implementer(IFoo) class Impl: - implements(IFoo) def later(val): self.assertSubstring('value="Foo"', val) @@ -389,8 +389,8 @@ def foo(abc=formless.String()): pass foo = formless.autocallable(foo, action='FooFooFoo') + @implementer(IFoo) class Impl: - implements(IFoo) def later(val): self.assertSubstring('value="FooFooFoo"', val) @@ -405,8 +405,8 @@ def sig(abc=formless.String()): foo = formless.autocallable(sig) bar = formless.autocallable(sig, action='FooFooFOo') + @implementer(IFoo) class Impl: - implements(IFoo) def later1(val): self.assertSubstring('value="Foo"', val) @@ -434,8 +434,8 @@ def theFunc(test=typedinst): pass theFunc = formless.autocallable(theFunc) + @implementer(IMyInterface) class Implementation(object): - implements(IMyInterface) called = False def theFunc(self, test): self.called = True @@ -444,9 +444,9 @@ def theFunc(self, test): ctx = self.setupContext() D = self.postForm(ctx, inst, 'theFunc', {'test': ['a test value']}) def after(result): - self.assertEquals(typedinst.passed, True) - self.assertEquals(typedinst.wasBoundTo, inst) - self.assertEquals(inst.called, True) + self.assertEqual(typedinst.passed, True) + self.assertEqual(typedinst.wasBoundTo, inst) + self.assertEqual(inst.called, True) return D.addCallback(after) @@ -455,8 +455,8 @@ def test_uneditable(self): class Uneditable(formless.TypedInterface): aProp = formless.String(description="the description", immutable=True) + @implementer(Uneditable) class Impl(object): - implements(Uneditable) aProp = property(lambda self: "HELLO") @@ -477,8 +477,8 @@ def test_property(self): class IThing(formless.TypedInterface): foo = formless.Integer() + @implementer(IThing) class Thing: - implements(IThing) foo = 1 inst = Thing() @@ -504,8 +504,8 @@ class IMethod(formless.TypedInterface): def foo(): pass foo = formless.autocallable(foo) + @implementer(IMethod) class Method(object): - implements(IMethod) def foo(self): return returnResult @@ -513,8 +513,8 @@ def foo(self): ctx = self.setupContext() D = self.postForm(ctx, inst, 'foo', {}) def after(result): - self.assertEquals(ctx.locate(inevow.IHand), returnResult) - self.assertEquals(ctx.locate(inevow.IStatusMessage), "'foo' success.") + self.assertEqual(ctx.locate(inevow.IHand), returnResult) + self.assertEqual(ctx.locate(inevow.IStatusMessage), "'foo' success.") return D.addCallback(after) def test_handFactory(self): @@ -532,8 +532,8 @@ def setupRequest(r): return r ctx = self.setupContext(setupRequest=setupRequest) - self.assertEquals(ctx.locate(inevow.IHand), returnResult) - self.assertEquals(ctx.locate(inevow.IStatusMessage), status) + self.assertEqual(ctx.locate(inevow.IHand), returnResult) + self.assertEqual(ctx.locate(inevow.IStatusMessage), status) class TestCharsetDetectionSupport(Base): @@ -543,8 +543,8 @@ def test_property(self): class ITest(formless.TypedInterface): foo = formless.String() + @implements(ITest) class Impl: - implements(ITest) impl = Impl() ctx = self.setupContext() @@ -560,8 +560,8 @@ class ITest(formless.TypedInterface): class Group(formless.TypedInterface): foo = formless.String() + @implementer(ITest) class Impl: - implements(ITest) impl = Impl() ctx = self.setupContext() @@ -578,8 +578,8 @@ def foo(foo = formless.String()): pass foo = formless.autocallable(foo) + @implementer(ITest) class Impl: - implements(ITest) impl = Impl() ctx = self.setupContext() @@ -594,16 +594,16 @@ class TestUnicode(Base): def test_property(self): class IThing(formless.TypedInterface): - aString = formless.String(unicode=True) + aString = formless.String(str=True) + @implementer(IThing) class Impl(object): - implements(IThing) aString = None inst = Impl() ctx = self.setupContext() D = self.postForm(ctx, inst, 'aString', {'aString':['\xc2\xa3']}) - return D.addCallback(lambda result: self.assertEquals(inst.aString, u'\xa3')) + return D.addCallback(lambda result: self.assertEqual(inst.aString, '\xa3')) class TestChoice(Base): """Test various behaviors of submitting values to a Choice Typed. @@ -619,8 +619,8 @@ def choiceyFunc(arg = formless.Choice(["one", "two"], required=True)): pass choiceyFunc = formless.autocallable(choiceyFunc) + @implementer(IFormyThing) class Impl(object): - implements(IFormyThing) def choiceyFunc(innerSelf, arg): self.called.append(arg) @@ -628,7 +628,7 @@ def choiceyFunc(innerSelf, arg): inst = Impl() ctx = self.setupContext() D = self.postForm(ctx, inst, 'choiceyFunc', {}) - return D.addCallback(lambda result: self.assertEquals(self.called, [])) + return D.addCallback(lambda result: self.assertEqual(self.called, [])) class mg(Base): @@ -645,14 +645,14 @@ def meth(foo = formless.String()): pass meth = formless.autocallable(meth) + @implementer(ITest) class Impl: - implements(ITest) foo = 'fooFOOfoo' impl = Impl() ctx = self.setupContext() def later(val): - self.assertEquals(val.count('fooFOOfoo'), 1) + self.assertEqual(val.count('fooFOOfoo'), 1) return self.renderForms(impl, ctx) diff --git a/formless/webform.py b/formless/webform.py index 3293ffa7..5fef42b6 100644 --- a/formless/webform.py +++ b/formless/webform.py @@ -4,10 +4,10 @@ # See LICENSE for details. -from __future__ import generators + import warnings -from zope.interface import implements, Interface +from zope.interface import implementer, Interface from twisted.python import components @@ -26,8 +26,8 @@ defaultCSS = File(util.resource_filename('formless', 'freeform-default.css'), 'text/css') +@implementer(inevow.IRenderer, iformless.ITypedRenderer) class DefaultRenderer(object): - implements(inevow.IRenderer, iformless.ITypedRenderer) complexType = False def rend(self, context, data): return StringRenderer(data) @@ -35,8 +35,8 @@ def rend(self, context, data): defaultBindingRenderer = DefaultRenderer() +@implementer(inevow.IRenderer, iformless.ITypedRenderer) class BaseInputRenderer(components.Adapter): - implements(inevow.IRenderer, iformless.ITypedRenderer) complexType = False def rend(self, context, data): defaults = context.locate(iformless.IFormDefaults) @@ -66,7 +66,7 @@ def rend(self, context, data): return context.tag def input(self, context, slot, data, name, value): - raise NotImplementedError, "Implement in subclass" + raise NotImplementedError("Implement in subclass") class PasswordRenderer(BaseInputRenderer): def input(self, context, slot, data, name, value): @@ -177,24 +177,24 @@ class RadioRenderer(ChoiceRenderer): lambda c, d: iformless.ITyped(c).stringify(d)]]] +@implementer(inevow.IRenderer, iformless.ITypedRenderer) class ObjectRenderer(components.Adapter): - implements(inevow.IRenderer, iformless.ITypedRenderer) complexType = True def rend(self, context, data): configurable = context.locate(iformless.IConfigurable) return getattr(configurable, data.name) +@implementer(inevow.IRenderer, iformless.ITypedRenderer) class NullRenderer(components.Adapter): """Use a NullRenderer as the ITypedRenderer adapter when nothing should be included in the output. """ - implements(inevow.IRenderer, iformless.ITypedRenderer) def rend(self, context, data): return '' +@implementer(inevow.IRenderer) class GroupBindingRenderer(components.Adapter): - implements(inevow.IRenderer) def rend(self, context, data): context.remember(data, iformless.IBinding) @@ -230,8 +230,8 @@ def generateBindings(): tags.input(type="submit")]] +@implementer(inevow.IRenderer) class BaseBindingRenderer(components.Adapter): - implements(inevow.IRenderer) isGrouped = False needsSkin = False @@ -360,8 +360,8 @@ def generateArguments(self, context, args): yield pat +@implementer(inevow.IRenderer) class ButtonRenderer(components.Adapter): - implements(inevow.IRenderer) def rend(self, context, data): return tags.input(id=keyToXMLID(context.key), type='submit', value=data.label, name=data.name, class_="freeform-button") @@ -437,7 +437,7 @@ def _innerFormRenderIt(context, data): if bindingDefaults is None: available = configurable.getBindingNames(context) else: - available = bindingDefaults.iterkeys() + available = iter(bindingDefaults.keys()) def _callback(binding): renderer = iformless.IBindingRenderer(binding, defaultBindingRenderer) diff --git a/nevow/__init__.py b/nevow/__init__.py index 45ac0a7e..197eedf2 100644 --- a/nevow/__init__.py +++ b/nevow/__init__.py @@ -2,6 +2,7 @@ # Copyright (c) 2004-2006 Divmod. # See LICENSE for details. + def _versions(): import re from nevow._version import get_versions @@ -70,16 +71,13 @@ def _versions(): import sys from twisted.python.components import registerAdapter -from nevow import flat -from nevow.util import _namedAnyWithBuiltinTranslation - -# Python2.2 has a stupidity where instance methods have name -# '__builtin__.instance method' instead of '__builtin__.instancemethod' -# Workaround this error. -def clean(o): - if o == '__builtin__.instancemethod' and sys.version_info < (2,3): - return '__builtin__.instance method' - return o +# all of these need to be imported explictly because they're used +# further down when registering standard adapters. +from . import accessors +from . import flat +from . import inevow +from . import stan +from .util import _namedAnyWithBuiltinTranslation def load(S): @@ -88,7 +86,7 @@ def load(S): if line and not line.startswith('#'): (a, o, i) = line.split() registerAdapter(_namedAnyWithBuiltinTranslation(a), - _namedAnyWithBuiltinTranslation(clean(o)), + _namedAnyWithBuiltinTranslation(o), _namedAnyWithBuiltinTranslation(i)) @@ -97,7 +95,7 @@ def loadFlatteners(S): line = line.strip() if line and not line.startswith('#'): f, o = line.split() - flat.registerFlattener(f, clean(o)) + flat.registerFlattener(f, o) namespace = "http://nevow.com/ns/nevow/0.1" @@ -205,12 +203,12 @@ def loadFlatteners(S): flatteners = """ -nevow.flat.flatmdom.MicroDomDocumentSerializer twisted.web.microdom.Document -nevow.flat.flatmdom.MicroDomTextSerializer twisted.web.microdom.Text -nevow.flat.flatmdom.MicroDomCommentSerializer twisted.web.microdom.Comment -nevow.flat.flatmdom.MicroDomElementSerializer twisted.web.microdom.Element -nevow.flat.flatmdom.MicroDomEntityReferenceSerializer twisted.web.microdom.EntityReference -nevow.flat.flatmdom.MicroDomCDATASerializer twisted.web.microdom.CDATASection +#nevow.flat.flatmdom.MicroDomDocumentSerializer twisted.web.microdom.Document +#nevow.flat.flatmdom.MicroDomTextSerializer twisted.web.microdom.Text +#nevow.flat.flatmdom.MicroDomCommentSerializer twisted.web.microdom.Comment +#nevow.flat.flatmdom.MicroDomElementSerializer twisted.web.microdom.Element +#nevow.flat.flatmdom.MicroDomEntityReferenceSerializer twisted.web.microdom.EntityReference +#nevow.flat.flatmdom.MicroDomCDATASerializer twisted.web.microdom.CDATASection nevow.flat.flatstan.ProtoSerializer nevow.stan.Proto nevow.flat.flatstan.TagSerializer nevow.stan.Tag @@ -219,11 +217,10 @@ def loadFlatteners(S): nevow.flat.flatstan.XmlSerializer nevow.stan.xml nevow.flat.flatstan.RawSerializer nevow.stan.raw nevow.flat.flatstan.StringSerializer __builtin__.str -nevow.flat.flatstan.StringSerializer __builtin__.unicode +nevow.flat.flatstan.BytesSerializer __builtin__.bytes nevow.flat.flatstan.NoneWarningSerializer __builtin__.NoneType nevow.flat.flatstan.StringCastSerializer __builtin__.int nevow.flat.flatstan.StringCastSerializer __builtin__.float -nevow.flat.flatstan.StringCastSerializer __builtin__.long nevow.flat.flatstan.BooleanSerializer __builtin__.bool nevow.flat.flatstan.ListSerializer __builtin__.list nevow.flat.flatstan.StringCastSerializer __builtin__.dict @@ -251,11 +248,11 @@ def loadFlatteners(S): nevow.flat.flatstan.ListSerializer itertools.count nevow.flat.flatstan.ListSerializer itertools.cycle nevow.flat.flatstan.ListSerializer itertools.dropwhile -nevow.flat.flatstan.ListSerializer itertools.ifilter -nevow.flat.flatstan.ListSerializer itertools.ifilterfalse -nevow.flat.flatstan.ListSerializer itertools.imap +nevow.flat.flatstan.ListSerializer __builtin__.filter +nevow.flat.flatstan.ListSerializer itertools.filterfalse +nevow.flat.flatstan.ListSerializer __builtin__.map nevow.flat.flatstan.ListSerializer itertools.islice -nevow.flat.flatstan.ListSerializer itertools.izip +nevow.flat.flatstan.ListSerializer __builtin__.zip nevow.flat.flatstan.ListSerializer itertools.repeat nevow.flat.flatstan.ListSerializer itertools.starmap nevow.flat.flatstan.ListSerializer itertools.takewhile diff --git a/nevow/_flat.py b/nevow/_flat.py index b0c7e03e..68a5f157 100644 --- a/nevow/_flat.py +++ b/nevow/_flat.py @@ -44,7 +44,10 @@ class FlattenerError(Exception): def __init__(self, exception, roots, traceback): self._exception = exception self._roots = roots - self._traceback = traceback + # we mangle the traceback object to retain the python 2 format + self._traceback = [ + (frame.filename, frame.lineno, frame.name, frame.line) + for frame in traceback] Exception.__init__(self, exception, roots, traceback) @@ -61,7 +64,7 @@ def _formatRoot(self, obj): @return: A string representation of C{obj}. @rtype: L{str} """ - if isinstance(obj, (str, unicode)): + if isinstance(obj, str): # It's somewhat unlikely that there will ever be a str in the roots # list. However, something like a MemoryError during a str.replace # call (eg, replacing " with ") could possibly cause this. @@ -224,9 +227,7 @@ def _flatten(request, write, root, slotData, renderFactory, inAttribute, inXML): @return: An iterator which yields C{str}, L{Deferred}, and more iterators of the same type. """ - if isinstance(root, unicode): - root = root.encode('utf-8') - elif isinstance(root, WovenContext): + if isinstance(root, WovenContext): # WovenContext is supported via the getFlattener case, but that is a # very slow case. Checking here is an optimization. It also lets us # avoid the deprecation warning which would be emitted whenever a @@ -268,24 +269,22 @@ def _flatten(request, write, root, slotData, renderFactory, inAttribute, inXML): False, True) else: write('<') - if isinstance(root.tagName, unicode): - tagName = root.tagName.encode('ascii') - else: - tagName = str(root.tagName) - write(tagName) - for k, v in sorted(root.attributes.iteritems()): - if isinstance(k, unicode): - k = k.encode('ascii') + # bomb out if tagName has non-ascii + root.tagName.encode('ascii') + write(root.tagName) + for k, v in sorted(root.attributes.items()): + # Bomb out if k has non-ascii + k.encode('ascii') write(" " + k + "=\"") yield _flatten(request, write, v, slotData, renderFactory, True, True) write("\"") - if root.children or tagName not in allowSingleton: + if root.children or root.tagName not in allowSingleton: write('>') yield _flatten(request, write, root.children, slotData, renderFactory, False, True) - write('') + write('') else: write(' />') else: @@ -310,10 +309,7 @@ def _flatten(request, write, root, slotData, renderFactory, inAttribute, inXML): write(root.num) write(';') elif isinstance(root, xml): - if isinstance(root.content, unicode): - write(root.content.encode('utf-8')) - else: - write(root.content) + write(root.content) elif isinstance(root, Deferred): yield root.addCallback( lambda result: (result, _flatten(request, write, result, slotData, @@ -409,10 +405,10 @@ def flatten(request, write, root, inAttribute, inXML): # In Python 2.5, after an exception, a generator's gi_frame is # None. frame = stack[-1].gi_frame - element = stack[-1].next() + element = next(stack[-1]) except StopIteration: stack.pop() - except Exception, e: + except Exception as e: stack.pop() roots = [] for generator in stack: @@ -423,7 +419,8 @@ def flatten(request, write, root, inAttribute, inXML): if type(element) is str: write(element) elif isinstance(element, Deferred): - def cbx((original, toFlatten)): + def cbx(args): + (original, toFlatten) = args stack.append(toFlatten) return original yield element.addCallback(cbx) @@ -456,7 +453,7 @@ def _flattensome(state, write, schedule, result): """ while True: try: - element = state.next() + element = next(state) except StopIteration: result.callback(None) except: diff --git a/nevow/accessors.py b/nevow/accessors.py index 2a991ce8..b156e3cb 100644 --- a/nevow/accessors.py +++ b/nevow/accessors.py @@ -12,7 +12,7 @@ methods found in the stan tree. """ -from zope.interface import implements +from zope.interface import implementer import twisted.python.components as tpc @@ -41,38 +41,39 @@ class NoAccessor(NotImplementedError): pass +@implementer(IGettable) class DirectiveAccessor(tpc.Adapter): - implements(IGettable) def get(self, context): data = context.locate(IData) container = IContainer(data, None) if container is None: - raise NoAccessor, "%r does not implement IContainer, and there is no registered adapter." % data + raise NoAccessor("%r does not implement IContainer, and there is no registered adapter." % data) child = container.child(context, self.original.name) return child +@implementer(IGettable) class SlotAccessor(tpc.Adapter): - implements(IGettable) def get(self, context): return context.locateSlotData(self.original.name) +@implementer(IGettable) class FunctionAccessor(tpc.Adapter): - implements(IGettable) def get(self, context): return self.original(context, context.locate(IData)) +@implementer(IContainer) class DictionaryContainer(tpc.Adapter): - implements(IContainer) def child(self, context, name): return self.original[name] +@implementer(IContainer) class ObjectContainer(tpc.Adapter): """Retrieve object attributes in response to a data directive; providing easy access to your application objects' attributes. @@ -104,7 +105,6 @@ class ObjectContainer(tpc.Adapter):
""" - implements(IContainer) def child(self, context, name): if name[:1] == '_': @@ -119,8 +119,8 @@ def intOrNone(s): return None +@implementer(IContainer) class ListContainer(tpc.Adapter): - implements(IContainer) def child(self, context, name): if ':' in name: diff --git a/nevow/appserver.py b/nevow/appserver.py index 63f8cb69..a3487a95 100644 --- a/nevow/appserver.py +++ b/nevow/appserver.py @@ -9,9 +9,9 @@ import cgi import warnings from collections import MutableMapping -from urllib import unquote +from urllib.parse import unquote_to_bytes -from zope.interface import implements, classImplements +from zope.interface import implementer, classImplements import twisted.python.components as tpc from twisted.web import server @@ -29,6 +29,7 @@ from nevow import url from nevow import flat from nevow import stan +from nevow import util @@ -106,8 +107,8 @@ def has_key(self, key): +@implementer(inevow.ICanHandleException) class UninformativeExceptionHandler: - implements(inevow.ICanHandleException) def renderHTTP_exception(self, ctx, reason): request = inevow.IRequest(ctx) @@ -122,18 +123,18 @@ def renderInlineException(self, context, reason): return """
[[ERROR]]
""" +@implementer(inevow.ICanHandleException) class DefaultExceptionHandler: - implements(inevow.ICanHandleException) def renderHTTP_exception(self, ctx, reason): log.err(reason) request = inevow.IRequest(ctx) request.setResponseCode(http.INTERNAL_SERVER_ERROR) - request.write("Exception") + request.write(b"Exception") from nevow import failure result = failure.formatFailure(reason) - request.write(''.join(flat.flatten(result))) - request.write("") + request.write((''.join(flat.flatten(result))).encode('ascii')) + request.write(b"") request.finishRequest( False ) @@ -173,8 +174,34 @@ def processingFailed(reason, request, ctx): def defaultExceptionHandlerFactory(ctx): return DefaultExceptionHandler() +########################################################## +# changes introduced by wth are below +class Encoder(): + """ + plugged into the encode slot this class makes sure for uniformly + sending byte arrays only to tranport level write functions + """ + def encode(self, data): + if isinstance(data, bytes): + return data + return data.encode() + + def finish(self): + pass + +class FieldStorage(cgi.FieldStorage): + """ + attempting to rewrite the original cgi.FieldStorage into + something which addresses the problem mentioned in the + class comments for NevowRequest + """ + def read_binary(self): + """Internal: read binary data.""" + self._binary_file = True # force binary mode on file storage + super().read_binary() -class NevowRequest(tpc.Componentized, server.Request): +@implementer(inevow.IRequest) +class NevowRequest(server.Request): """ A Request subclass which does additional processing if a form was POSTed. When a form is POSTed, @@ -195,18 +222,17 @@ class NevowRequest(tpc.Componentized, server.Request): lost) or not. C{False} until this happens, C{True} afterwards. @type _lostConnection: L{bool} """ - implements(inevow.IRequest) fields = None _lostConnection = False def __init__(self, *args, **kw): + # twisted request wants path a bytes instance server.Request.__init__(self, *args, **kw) tpc.Componentized.__init__(self) - + self._encoder = Encoder() self.notifyFinish().addErrback(self._flagLostConnection) - def _flagLostConnection(self, error): """ Observe and record an error trying to deliver the response for this @@ -217,10 +243,10 @@ def _flagLostConnection(self, error): def process(self): # extra request parsing - if self.method == 'POST': + if self.method == b'POST': t = self.content.tell() self.content.seek(0) - self.fields = cgi.FieldStorage( + self.fields = FieldStorage( self.content, _DictHeaders(self.requestHeaders), environ={'REQUEST_METHOD': 'POST'}) self.content.seek(t) @@ -235,14 +261,16 @@ def process(self): # Resource Identification self.prepath = [] - self.postpath = map(unquote, self.path[1:].split('/')) + self.postpath = [unquote_to_bytes(p) + for p in self.path[1:].split(b'/')] self.sitepath = [] self.deferred = defer.Deferred() requestContext = context.RequestContext(parent=self.site.context, tag=self) requestContext.remember( (), inevow.ICurrentSegments) - requestContext.remember(tuple(self.postpath), inevow.IRemainingSegments) + requestContext.remember(tuple(util.toString(s) for s in self.postpath), + inevow.IRemainingSegments) return self.site.getPageContextForRequestContext( requestContext @@ -252,6 +280,9 @@ def process(self): self.gotPageContext ) + def write(self, data): + super().write(data) + def gotPageContext(self, pageContext): if pageContext is not errorMarker: return defer.maybeDeferred( @@ -294,6 +325,9 @@ def _cbFinishRender(self, html, ctx): # No response can be sent at this point. pass elif isinstance(html, str): + self.write(html.encode("utf-8")) + self.finishRequest( True ) + elif isinstance(html, bytes): self.write(html) self.finishRequest( True ) elif html is errorMarker: @@ -445,14 +479,16 @@ def handleSegment(self, result, request, path, pageContext): assert len(newpath) < len(path), "Infinite loop impending..." ## We found a Resource... update the request.prepath and postpath - for x in xrange(len(path) - len(newpath)): + for x in range(len(path) - len(newpath)): if request.postpath: request.prepath.append(request.postpath.pop(0)) ## Create a context object to represent this new resource ctx = context.PageContext(tag=newres, parent=pageContext) - ctx.remember(tuple(request.prepath), inevow.ICurrentSegments) - ctx.remember(tuple(request.postpath), inevow.IRemainingSegments) + ctx.remember(tuple(util.toString(s) for s in request.prepath), + inevow.ICurrentSegments) + ctx.remember(tuple(util.toString(s) for s in request.postpath), + inevow.IRemainingSegments) res = newres path = newpath @@ -470,15 +506,26 @@ def handleSegment(self, result, request, path, pageContext): def log(self, request): if request._logger is None: - server.Site.log(self, request) + # TODO: as of twisted 16.6, http.HTTPFactory.log tries + # to write strings (rather than bytes). I'm simply overriding + # this here for now -- this needs to become + # server.Site.log(self, request) + # again when twisted is fixed. + try: + logFile = self.logFile + except AttributeError: + pass + else: + line = self._logFormatter(self._logDateTime, request) + u"\n" + logFile.write(line.encode("utf-8")) else: request._logger() ## This should be moved somewhere else, it's cluttering up this module. +@implementer(inevow.IResource) class OldResourceAdapter(object): - implements(inevow.IResource) # This is required to properly handle the interaction between # original.isLeaf and request.postpath, from which PATH_INFO is set in diff --git a/nevow/athena.py b/nevow/athena.py index 1ce9ce83..59f9bc75 100644 --- a/nevow/athena.py +++ b/nevow/athena.py @@ -1,15 +1,15 @@ # -*- test-case-name: nevow.test.test_athena -*- -import itertools, os, re, warnings, StringIO +import itertools, os, re, warnings, io -from zope.interface import implements +from zope.interface import implementer from twisted.internet import defer, error, reactor from twisted.python import log, failure, context from twisted.python.util import sibpath from twisted import plugin -from nevow import inevow, plugins, flat, _flat +from nevow import inevow, plugins, flat, _flat, json from nevow import rend, loaders, static from nevow import json, util, tags, guard, stan from nevow.util import CachedFile @@ -19,7 +19,7 @@ from nevow.page import Element, renderer ATHENA_XMLNS_URI = "http://divmod.org/ns/athena/0.7" -ATHENA_RECONNECT = "__athena_reconnect__" +ATHENA_RECONNECT = b"__athena_reconnect__" expose = util.Expose( """ @@ -49,7 +49,7 @@ class LivePageError(Exception): """ Base exception for LivePage errors. """ - jsClass = u'Divmod.Error' + jsClass = 'Divmod.Error' @@ -58,7 +58,7 @@ class NoSuchMethod(LivePageError): Raised when an attempt is made to invoke a method which is not defined or exposed. """ - jsClass = u'Nevow.Athena.NoSuchMethod' + jsClass = 'Nevow.Athena.NoSuchMethod' def __init__(self, objectID, methodName): self.objectID = objectID @@ -86,6 +86,7 @@ def activeChannel(request): +@implementer(inevow.IResource) class MappingResource(object): """ L{inevow.IResource} which looks up segments in a mapping between symbolic @@ -96,7 +97,6 @@ class MappingResource(object): 'Nevow.Athena') and C{str} instances which name files containing data which should be served in response. """ - implements(inevow.IResource) def __init__(self, mapping): self.mapping = mapping @@ -177,7 +177,7 @@ def __repr__(self): def _extractImports(self, fileObj): s = fileObj.read() for m in self._importExpression.finditer(s): - yield self.getOrCreate(m.group(1).decode('ascii'), self.mapping) + yield self.getOrCreate(m.group(1), self.mapping) @@ -185,8 +185,9 @@ def _getDeps(self, jsFile): """ Calculate our dependencies given the path to our source. """ - depgen = self._extractImports(file(jsFile, 'rU')) - return self.packageDeps + dict.fromkeys(depgen).keys() + with open(jsFile, 'rU') as f: + depgen = self._extractImports(f) + return self.packageDeps + list(dict.fromkeys(depgen).keys()) def dependencies(self): @@ -252,6 +253,7 @@ class CSSModule(AthenaModule): +@implementer(plugin.IPlugin, inevow.IJavascriptPackage) class JSPackage(object): """ A Javascript package. @@ -260,7 +262,6 @@ class JSPackage(object): @ivar mapping: Mapping between JS module names and C{str} representing filesystem paths containing their implementations. """ - implements(plugin.IPlugin, inevow.IJavascriptPackage) def __init__(self, mapping): self.mapping = mapping @@ -300,7 +301,7 @@ def _collectPackageBelow(baseDir, extension): path = os.path.join(root, dir, '__init__.' + extension) if not os.path.exists(path): path = EMPTY - mapping[unicode(name, 'ascii')] = path + mapping[name] = path _revMap[os.path.join(root, dir)] = name + '.' for fn in filenames: @@ -315,11 +316,12 @@ def _collectPackageBelow(baseDir, extension): name = stem + fn[:-(len(extension) + 1)] path = os.path.join(root, fn) - mapping[unicode(name, 'ascii')] = path + mapping[name] = path return mapping +@implementer(plugin.IPlugin, inevow.IJavascriptPackage) class AutoJSPackage(object): """ A L{inevow.IJavascriptPackage} implementation that scans an on-disk @@ -329,19 +331,19 @@ class AutoJSPackage(object): @ivar baseDir: A path to the root of a JavaScript packages/modules filesystem hierarchy. """ - implements(plugin.IPlugin, inevow.IJavascriptPackage) def __init__(self, baseDir): self.mapping = _collectPackageBelow(baseDir, 'js') + +@implementer(plugin.IPlugin, inevow.ICSSPackage) class AutoCSSPackage(object): """ Like L{AutoJSPackage}, but for CSS packages. Modules within this package can be referenced by L{LivePage.cssModule} or L{LiveElement.cssModule}. """ - implements(plugin.IPlugin, inevow.ICSSPackage) def __init__(self, baseDir): self.mapping = _collectPackageBelow(baseDir, 'css') @@ -540,18 +542,18 @@ def getJSFailure(exc, modules): """ Convert a serialized client-side exception to a Failure. """ - text = '%s: %s' % (exc[u'name'], exc[u'message']) + text = '%s: %s' % (exc['name'], exc['message']) frames = [] - if u'stack' in exc: - frames = parseStack(exc[u'stack']) + if 'stack' in exc: + frames = parseStack(exc['stack']) return failure.Failure(JSException(text), exc_tb=buildTraceback(frames, modules)) +@implementer(inevow.IResource) class LivePageTransport(object): - implements(inevow.IResource) def __init__(self, messageDeliverer, useActiveChannels=True): self.messageDeliverer = messageDeliverer @@ -569,10 +571,10 @@ def renderHTTP(self, ctx): activeChannel(req) requestContent = req.content.read() - messageData = json.parse(requestContent) + messageData = json.loads(requestContent) response = self.messageDeliverer.basketCaseReceived(ctx, messageData) - response.addCallback(json.serialize) + response.addCallback(json.dumps) req.notifyFinish().addErrback(lambda err: self.messageDeliverer._unregisterDeferredAsOutputChannel(response)) return response @@ -618,8 +620,8 @@ class ConnectionLost(Exception): pass -CLOSE = u'close' -UNLOAD = u'unload' +CLOSE = 'close' +UNLOAD = 'unload' class ReliableMessageDelivery(object): """ @@ -775,8 +777,8 @@ def close(self): def _unregisterDeferredAsOutputChannel(self, deferred): - for i in xrange(len(self.outputs)): - if self.outputs[i][0].im_self is deferred: + for i in range(len(self.outputs)): + if self.outputs[i][0].__self__ is deferred: output, timeout = self.outputs.pop(i) timeout.cancel() break @@ -1007,7 +1009,7 @@ class LivePage(rend.Page, _HasJSClass, _HasCSSModule): @ivar _localObjectIDCounter: A callable that will return a new locally-unique object ID each time it is called. """ - jsClass = u'Nevow.Athena.PageWidget' + jsClass = 'Nevow.Athena.PageWidget' cssModule = None factory = LivePageFactory() @@ -1149,7 +1151,7 @@ def _becomeLive(self, location): if self.cssModuleRoot is None: self.cssModuleRoot = location.child(self.clientID).child('cssmodule') - self._requestIDCounter = itertools.count().next + self._requestIDCounter = itertools.count().__next__ self._messageDeliverer = ReliableMessageDelivery( self, @@ -1160,7 +1162,7 @@ def _becomeLive(self, location): connectionMade=self._connectionMade) self._remoteCalls = {} self._localObjects = {} - self._localObjectIDCounter = itertools.count().next + self._localObjectIDCounter = itertools.count().__next__ self.addLocalObject(self) @@ -1253,7 +1255,7 @@ def renderHTTP(self, ctx): neverEverCache(request) if request.args.get(ATHENA_RECONNECT): - return json.serialize(self.clientID.decode("ascii")) + return json.dumps(self.clientID) return rend.Page.renderHTTP(self, ctx) @@ -1283,7 +1285,7 @@ def _disconnected(self, reason): d.errback(reason) calls = self._remoteCalls self._remoteCalls = {} - for (reqID, resD) in calls.iteritems(): + for (reqID, resD) in calls.items(): resD.errback(reason) if self._didConnect: for widget in self._localObjects.values(): @@ -1325,8 +1327,8 @@ def removeLocalObject(self, objID): def callRemote(self, methodName, *args): - requestID = u's2c%i' % (self._requestIDCounter(),) - message = (u'call', (unicode(methodName, 'ascii'), requestID, args)) + requestID = 's2c%i' % (self._requestIDCounter(),) + message = ('call', (str(methodName, 'ascii'), requestID, args)) resultD = defer.Deferred() self._remoteCalls[requestID] = resultD self.addMessage(message) @@ -1403,10 +1405,10 @@ def _bootstraps(self, ctx): """ return [ ("Divmod.bootstrap", - [flat.flatten(self.transportRoot, ctx).decode("ascii"), + [flat.flatten(self.transportRoot, ctx), self.TRANSPORT_CLIENT_IDLE_TIMEOUT]), ("Nevow.Athena.bootstrap", - [self.jsClass, self.clientID.decode('ascii')])] + [self.jsClass, self.clientID])] def _bootstrapCall(self, methodName, args): @@ -1420,7 +1422,7 @@ def _bootstrapCall(self, methodName, args): arguments to the named method. """ return '%s(%s);' % ( - methodName, ', '.join([json.serialize(arg) for arg in args])) + methodName, ', '.join([json.dumps(arg) for arg in args])) def child_jsmodule(self, ctx): @@ -1449,12 +1451,13 @@ def locateMethod(self, ctx, methodName): raise AttributeError(methodName) - def liveTransportMessageReceived(self, ctx, (action, args)): + def liveTransportMessageReceived(self, ctx, action_and_args): """ A message was received from the reliable transport layer. Process it by dispatching it first to myself, then later to application code if applicable. """ + (action, args) = action_and_args method = getattr(self, 'action_' + action) method(ctx, *args) @@ -1482,11 +1485,11 @@ def _cbCall(result): result.value.args) else: result = ( - u'Divmod.Error', - [u'%s: %s' % ( - result.type.__name__.decode('ascii'), - result.getErrorMessage().decode('ascii'))]) - message = (u'respond', (unicode(requestId), success, result)) + 'Divmod.Error', + ['%s: %s' % ( + result.type.__name__, + result.getErrorMessage())]) + message = ('respond', (str(requestId), success, result)) self.addMessage(message) result.addBoth(_cbCall) @@ -1527,14 +1530,14 @@ def _rewriteEventHandlerToAttribute(tag): """ if isinstance(tag, stan.Tag): extraAttributes = {} - for i in xrange(len(tag.children) - 1, -1, -1): + for i in range(len(tag.children) - 1, -1, -1): if isinstance(tag.children[i], stan.Tag) and tag.children[i].tagName == 'athena:handler': info = tag.children.pop(i) - name = info.attributes['event'].encode('ascii') + name = info.attributes['event'] handler = info.attributes['handler'] extraAttributes[name] = _handlerFormat % { - 'handler': json.serialize(handler.decode('ascii')), - 'event': json.serialize(name.decode('ascii'))} + 'handler': json.dumps(handler), + 'event': json.dumps(name)} tag(**extraAttributes) return tag @@ -1575,7 +1578,7 @@ def _rewriteAthenaId(tag): if headers is not None: ids = headers.split() headers = [_mangleId(headerId) for headerId in ids] - for n in xrange(len(headers) - 1, 0, -1): + for n in range(len(headers) - 1, 0, -1): headers.insert(n, ' ') tag.attributes['headers'] = headers return tag @@ -1590,7 +1593,7 @@ def rewriteAthenaIds(root): class _LiveMixin(_HasJSClass, _HasCSSModule): - jsClass = u'Nevow.Athena.Widget' + jsClass = 'Nevow.Athena.Widget' cssModule = None preprocessors = [rewriteEventHandlerNodes, rewriteAthenaIds] @@ -1643,7 +1646,7 @@ def _prepare(self, tag): C{self.page}, add this object to the page and fill the I{athena:id} slot with this object's Athena identifier. """ - assert isinstance(self.jsClass, unicode), "jsClass must be a unicode string" + assert isinstance(self.jsClass, str), "jsClass must be a unicode string" if self.page is None: raise OrphanedFragment(self) @@ -1691,7 +1694,7 @@ def _flatten(self, what): # different module from whence nevow.athena and nevow.testutil could # import it. -exarkun from nevow.testutil import FakeRequest - s = StringIO.StringIO() + s = io.StringIO() for _ in _flat.flatten(FakeRequest(), s.write, what, False, False): pass return s.getvalue() @@ -1718,20 +1721,20 @@ def _structured(self): {'children': children, 'requiredModules': requiredModules, 'requiredCSSModules': requiredCSSModules}, - self._flatten, tags.div(xmlns="http://www.w3.org/1999/xhtml")[self]).decode('utf-8') + self._flatten, tags.div(xmlns="http://www.w3.org/1999/xhtml")[self]) del children[0] self._structuredCache = { - u'requiredModules': [(name, flat.flatten(url).decode('utf-8')) + 'requiredModules': [(name, flat.flatten(url)) for (name, url) in requiredModules], - u'requiredCSSModules': [flat.flatten(url).decode('utf-8') + 'requiredCSSModules': [flat.flatten(url) for url in requiredCSSModules], - u'class': self.jsClass, - u'id': self._athenaID, - u'initArguments': tuple(self.getInitialArguments()), - u'markup': markup, - u'children': children} + 'class': self.jsClass, + 'id': self._athenaID, + 'initArguments': tuple(self.getInitialArguments()), + 'markup': markup, + 'children': children} return self._structuredCache @@ -1751,9 +1754,9 @@ def liveElement(self, request, tag): # This will only be set if _structured() is being run. if context.get('children') is not None: context.get('children').append({ - u'class': self.jsClass, - u'id': self._athenaID, - u'initArguments': self.getInitialArguments()}) + 'class': self.jsClass, + 'id': self._athenaID, + 'initArguments': self.getInitialArguments()}) context.get('requiredModules').extend(requiredModules) context.get('requiredCSSModules').extend(requiredCSSModules) return tag @@ -1768,7 +1771,7 @@ def liveElement(self, request, tag): # where it can easily be found. tags.textarea(id='athena-init-args-' + str(self._athenaID), style="display: none")[ - json.serialize(self.getInitialArguments())], + json.dumps(self.getInitialArguments())], # Arrange to be instantiated tags.script(type='text/javascript')[ @@ -1802,7 +1805,7 @@ def callRemote(self, methodName, *varargs): return self.page.callRemote( "Nevow.Athena.callByAthenaID", self._athenaID, - unicode(methodName, 'ascii'), + str(methodName, 'ascii'), varargs) @@ -1814,7 +1817,7 @@ def _athenaDetachServer(self): """ if self.fragmentParent is None: raise OrphanedFragment(self) - for ch in list(self.liveFragmentChildren): + for ch in self.liveFragmentChildren: ch._athenaDetachServer() self.fragmentParent.liveFragmentChildren.remove(self) self.fragmentParent = None @@ -2008,7 +2011,7 @@ class IntrospectionFragment(LiveFragment): the state of a live page. """ - jsClass = u'Nevow.Athena.IntrospectionWidget' + jsClass = 'Nevow.Athena.IntrospectionWidget' docFactory = loaders.stan( tags.span(render=tags.directive('liveFragment'))[ diff --git a/nevow/blocks.py b/nevow/blocks.py index c2a9f76a..70e1b190 100644 --- a/nevow/blocks.py +++ b/nevow/blocks.py @@ -34,7 +34,7 @@ It doesn't appear to be possible to set the vertical-align in some cases in mozilla. """ -from zope.interface import implements +from zope.interface import implementer from nevow import static from nevow import inevow @@ -147,6 +147,7 @@ def __call__(self, **kw): line = _Blocks(tags.div, 'nevow-blocks-line') +@implementer(inevow.IRenderer) class collapser(object): """Render a fragment of html with a head and a body. The body can be in two states, expanded and collapsed. @@ -159,7 +160,6 @@ class collapser(object): and a div, and you can omit the visibility image if desired (js would have to change too) """ - implements(inevow.IRenderer) def __init__(self, headCollapsed, headExpanded, body, collapsed=True): self.headCollapsed = headCollapsed diff --git a/nevow/canvas.py b/nevow/canvas.py index 2d32e0ed..bb3ecac2 100755 --- a/nevow/canvas.py +++ b/nevow/canvas.py @@ -1,7 +1,7 @@ # Copyright (c) 2004 Divmod. # See LICENSE for details. -from zope.interface import implements +from zope.interface import implementer from twisted.internet import defer from twisted.python import log @@ -11,7 +11,7 @@ from nevow.stan import Proto, Tag from itertools import count -cn = count().next +cn = count().__next__ cookie = lambda: str(cn()) _hookup = {} @@ -212,7 +212,7 @@ def image(self, where): cook = cookie() I = Image(cook, self) self.call('image', cook, where) - print "IMAGE", where + print("IMAGE", where) return I def sound(self, where, stream=True): @@ -283,11 +283,11 @@ def depth(self): return 0 +@implementer(inevow.IResource) class CanvasSocket(GroupBase): """An object which represents the client-side canvas. Defines APIs for drawing on the canvas. An instance of this class will be passed to your onload callback. """ - implements(inevow.IResource) groupName = 'canvas' @@ -354,18 +354,18 @@ def handle_onKeyUp(self, info): def handle_onMouseUp(self, info): if self.delegate.onMouseUp: - self.delegate.onMouseUp(self, *map(int, map(float, info.split()))) + self.delegate.onMouseUp(self, *list(map(int, list(map(float, info.split()))))) def handle_onMouseDown(self, info): if self.delegate.onMouseDown: - self.delegate.onMouseDown(self, *map(int, map(float, info.split()))) + self.delegate.onMouseDown(self, *list(map(int, list(map(float, info.split()))))) def handle_onMouseMove(self, info): if self.delegate.onMouseMove: - self.delegate.onMouseMove(self, *map(int, map(float, info.split()))) + self.delegate.onMouseMove(self, *list(map(int, list(map(float, info.split()))))) def handle_diagnostic(self, info): - print "Trace", info + print("Trace", info) canvasServerMessage = loaders.stan(tags.html["This server dispatches for nevow canvas events."]) diff --git a/nevow/compression.py b/nevow/compression.py index 16e681e3..e0780e53 100644 --- a/nevow/compression.py +++ b/nevow/compression.py @@ -4,7 +4,7 @@ """ from gzip import GzipFile -from zope.interface import implements +from zope.interface import implementer from twisted.internet.defer import maybeDeferred, Deferred from twisted.internet.interfaces import IConsumer @@ -89,6 +89,7 @@ def _makeBase(): d[attrName] = _ProxyDescriptor(attrName) return type('_CompressionRequestWrapperBase', (object,), d) +@implementer(IRequest) class CompressingRequestWrapper(_makeBase()): """ A request wrapper with support for transport encoding compression. @@ -100,7 +101,6 @@ class CompressingRequestWrapper(_makeBase()): @ivar compressLevel: the level of gzip compression to apply. @type compressLevel: C{int} """ - implements(IRequest) encoding = 'gzip' compressLevel = 6 @@ -146,12 +146,13 @@ def finishRequest(self, success): Finish off gzip stream. """ if self._gzipFile is None: - self.write('') + self.write(b'') self._gzipFile.close() self.underlying.finishRequest(success) +@implementer(IResource) class CompressingResourceWrapper(object): """ A resource wrapper with support for transport encoding compression. @@ -159,7 +160,6 @@ class CompressingResourceWrapper(object): @ivar underlying: the resource being wrapped. @type underlying: L{IResource} """ - implements(IResource) def __init__(self, underlying): self.underlying = underlying @@ -190,6 +190,13 @@ def renderHTTP(self, ctx): def _cbDoneRendering(html): if isinstance(html, str): + # TODO: Auto-encoding is probably a bad idea + # Let's see how badly it bites us. For now + # nevow.test.test_compression depends on this (and + # probably more as long as we work with strings + # in request). + html = html.encode("utf-8") + if isinstance(html, bytes): req.write(html) req.finishRequest(True) return errorMarker diff --git a/nevow/compy.py b/nevow/compy.py index 4f894e5e..1d59abaf 100644 --- a/nevow/compy.py +++ b/nevow/compy.py @@ -35,8 +35,7 @@ def registerAdapter(adapterFactory, origInterface, *interfaceClasses): origInterface = _namedAnyWithBuiltinTranslation(origInterface) interfaceClasses = [_namedAnyWithBuiltinTranslation(x) for x in interfaceClasses] - if 'nevow.inevow.ISerializable' in interfaceClasses or filter( - lambda o: getattr(o, '__name__', None) == 'ISerializable', interfaceClasses): + if 'nevow.inevow.ISerializable' in interfaceClasses or [o for o in interfaceClasses if getattr(o, '__name__', None) == 'ISerializable']: warnings.warn("ISerializable is deprecated. Please use nevow.flat.registerFlattener instead.", stacklevel=2) from nevow import flat flat.registerFlattener(adapterFactory, origInterface) diff --git a/nevow/context.py b/nevow/context.py index f3fc4b0c..33a4eebf 100644 --- a/nevow/context.py +++ b/nevow/context.py @@ -2,7 +2,7 @@ # Copyright (c) 2004 Divmod. # See LICENSE for details. -from __future__ import generators + import warnings @@ -109,7 +109,7 @@ def locate(self, interface, depth=1, _default=object()): contextParent = currentContext.parent if contextParent is None: - raise KeyError, "Interface %s was not remembered." % key + raise KeyError("Interface %s was not remembered." % key) currentContext = contextParent @@ -151,7 +151,7 @@ def locateSlotData(self, name): if data is not Unset: return data if currentContext.parent is None: - raise KeyError, "Slot named '%s' was not filled." % name + raise KeyError("Slot named '%s' was not filled." % name) currentContext = currentContext.parent def clone(self, deep=True, cloneTags=True): diff --git a/nevow/dirlist.py b/nevow/dirlist.py index 9fe64df7..27f657b4 100644 --- a/nevow/dirlist.py +++ b/nevow/dirlist.py @@ -5,7 +5,7 @@ # system imports import os -import urllib +import urllib.request, urllib.parse, urllib.error import stat # twisted imports @@ -49,7 +49,7 @@ def data_listing(self, context, data): files = []; dirs = [] for path in directory: - url = urllib.quote(path, '/') + url = urllib.parse.quote(path, '/') if os.path.isdir(os.path.join(self.path, path)): url = url + '/' dirs.append({ @@ -65,7 +65,7 @@ def data_listing(self, context, data): self.contentTypes, self.contentEncodings, self.defaultType) try: filesize = os.stat(os.path.join(self.path, path))[stat.ST_SIZE] - except OSError, x: + except OSError as x: if x.errno != 2 and x.errno != 13: raise x else: @@ -80,7 +80,7 @@ def data_listing(self, context, data): def data_header(self, context, data): request = context.locate(inevow.IRequest) - return "Directory listing for %s" % urllib.unquote(request.uri) + return "Directory listing for %s" % urllib.parse.unquote(request.uri) def render_tableLink(self, context, data): return tags.a(href=data['link'])[data['linktext']] diff --git a/nevow/entities.py b/nevow/entities.py index 5d0e3dbb..8c3bf422 100644 --- a/nevow/entities.py +++ b/nevow/entities.py @@ -5,15 +5,18 @@ trees. """ +import builtins import types __by_number = {} -def makeEntity((name, num, description)): +def makeEntity(entity_desc): + (name, num, description) = entity_desc from nevow.stan import Entity e = Entity(name, num, description) - __by_number[types.IntType(num)] = e + # int is overwritten as an entity, so we take it from a safe place. + __by_number[builtins.int(num)] = e globals()[name] = e diff --git a/nevow/events.py b/nevow/events.py index f43d6680..433dbcc3 100644 --- a/nevow/events.py +++ b/nevow/events.py @@ -16,7 +16,7 @@ def subscribe(self, identifier, subscriber): Returns a token which should be passed to unsubscribe when done. """ if DEBUG: - print "SUBSCRIBE", self, identifier, subscriber + print("SUBSCRIBE", self, identifier, subscriber) self._subscribers.setdefault(identifier, []).append(subscriber) return identifier, subscriber @@ -24,7 +24,7 @@ def unsubscribe(self, token): """Unsubscribe the given token from events. """ if DEBUG: - print "UNSUBSCRIBE", token + print("UNSUBSCRIBE", token) identifier, reference = token self._subscribers[identifier].remove(reference) @@ -32,14 +32,14 @@ def publish(self, identifier, *args): """Notify the listeners on a given identifier that an event has occurred. """ if DEBUG: - print "PUBLISH", self, identifier, + print("PUBLISH", self, identifier, end=' ') subscribers = self._subscribers.get(identifier, []) for sub in subscribers: sub(*args) if DEBUG: - print "NOTIFY SUBSCRIBER", sub + print("NOTIFY SUBSCRIBER", sub) if DEBUG: - print "done" + print("done") def nextId(self): self._currentId += 1 diff --git a/nevow/failure.py b/nevow/failure.py index c805f1dc..ac7acee0 100644 --- a/nevow/failure.py +++ b/nevow/failure.py @@ -189,13 +189,13 @@ def htmlString(s): def htmlFunc(f): return t.div(_class="function")[ - "Function %s in file %s at line %s" % (f.__name__, f.func_code.co_filename, f.func_code.co_firstlineno) + "Function %s in file %s at line %s" % (f.__name__, f.__code__.co_filename, f.__code__.co_firstlineno) ] def htmlMeth(m): return t.div(_class="method")[ - "Method %s in file %s at line %s" % (m.im_func.__name__, m.im_func.func_code.co_filename, m.im_func.func_code.co_firstlineno) + "Method %s in file %s at line %s" % (m.__func__.__name__, m.__func__.__code__.co_filename, m.__func__.__code__.co_firstlineno) ] def htmlUnknown(u): @@ -205,10 +205,9 @@ def htmlUnknown(u): htmlReprTypes = { - types.DictType: htmlDict, - types.ListType: htmlList, - types.InstanceType: htmlInst, - types.StringType: htmlString, + dict: htmlDict, + list: htmlList, + bytes: htmlString, types.FunctionType: htmlFunc, types.MethodType: htmlMeth, } diff --git a/nevow/flat/flatmdom.py b/nevow/flat/flatmdom.py index 09572b57..261917d0 100644 --- a/nevow/flat/flatmdom.py +++ b/nevow/flat/flatmdom.py @@ -1,7 +1,7 @@ # Copyright (c) 2004 Divmod. # See LICENSE for details. -from __future__ import generators + from nevow.flat import serialize, precompile from nevow.stan import Tag, xml, directive, slot, cdata @@ -50,7 +50,7 @@ def MicroDomElementSerializer(element, context): specials = {} attributes = attributeList directives = directiveMapping - for k, v in attrs.items(): + for k, v in list(attrs.items()): # I know, this is totally not the way to do xml namespaces but who cares right now ## I'll fix it later -dp ### no you won't *I'll* fix it later -glyph diff --git a/nevow/flat/flatsax.py b/nevow/flat/flatsax.py index 30202d92..a398135b 100644 --- a/nevow/flat/flatsax.py +++ b/nevow/flat/flatsax.py @@ -4,6 +4,8 @@ from xml.sax import make_parser, handler import xml as pyxml +from twisted.python import compat + from nevow.stan import xml, Tag, directive, slot import nevow @@ -132,7 +134,7 @@ def startElementNS(self, ns_and_name, qname, attrs): specials = {} attributes = self.attributeList directives = self.directiveMapping - for k, v in attrs.items(): + for k, v in list(attrs.items()): att_ns, nons = k if att_ns != nevow.namespace: continue @@ -145,7 +147,7 @@ def startElementNS(self, ns_and_name, qname, attrs): del attrs[k] no_ns_attrs = {} - for (attrNs, attrName), v in attrs.items(): + for (attrNs, attrName), v in list(attrs.items()): nsPrefix = self.prefixMap.get(attrNs) if nsPrefix is None: no_ns_attrs[attrName] = v @@ -248,5 +250,16 @@ def parse(fl, ignoreDocType=False, ignoreComment=False): return s.document def parseString(t, ignoreDocType=False, ignoreComment=False): - from cStringIO import StringIO - return parse(StringIO(t), ignoreDocType, ignoreComment) + """returns stan from an XML literal in a string. + + t should be a byte string with the correct charset declaration. + To make things easy, we accept unicode strings, too, and encode them + as utf-8; you should therefore not declare any charsets in such + literals. + """ + from io import BytesIO + + if isinstance(t, compat.unicode): + t = t.encode("utf-8") + + return parse(BytesIO(t), ignoreDocType, ignoreComment) diff --git a/nevow/flat/flatstan.py b/nevow/flat/flatstan.py index ac952c55..a1f22913 100644 --- a/nevow/flat/flatstan.py +++ b/nevow/flat/flatstan.py @@ -1,9 +1,9 @@ # Copyright (c) 2004 Divmod. # See LICENSE for details. -from __future__ import generators -import urllib, warnings + +import urllib.request, urllib.parse, urllib.error, warnings from twisted.python import log, failure @@ -38,7 +38,7 @@ def TagSerializer(original, context, contextIsMine=False): visible = bool(original.tagName) if visible and context.isAttrib: - raise RuntimeError, "Tried to render tag '%s' in an tag attribute context." % (original.tagName) + raise RuntimeError("Tried to render tag '%s' in an tag attribute context." % (original.tagName)) if context.precompile and original.macro: toBeRenderedBy = original.macro @@ -111,7 +111,7 @@ def TagSerializer(original, context, contextIsMine=False): yield '<%s' % original.tagName if original.attributes: attribContext = WovenContext(parent=context, precompile=context.precompile, isAttrib=True) - for (k, v) in sorted(original.attributes.iteritems()): + for (k, v) in sorted(original.attributes.items()): if v is None: continue yield ' %s="' % k @@ -155,7 +155,7 @@ def StringSerializer(original, context): if context.inURL: # The magic string "-_.!*'()" also appears in url.py. Thinking about # changing this? Change that, too. - return urllib.quote(original, safe="-_.!*'()") + return urllib.parse.quote(original, safe="-_.!*'()") ## quote it if context.inJS: original = _jsSingleQuoteQuote(original) @@ -169,6 +169,16 @@ def StringSerializer(original, context): return original.replace("&", "&").replace("<", "<").replace(">", ">") + +def BytesSerializer(original, context): + # utf-8-decode and quote the string as necessary. It's not entirely + # clear if this is a good idea, but byte strings can originate from + # various sources (e.g., URLs). Whether these can always be expected + # to be in utf-8 is another matter, of course... + return StringSerializer(original.decode("utf-8"), context) + + + def NoneWarningSerializer(original, context): if context.isAttrib: ## We don't want the big red None warning inside a html attribute. Just leave it blank. @@ -208,7 +218,7 @@ def XmlSerializer(original, context): def FunctionSerializer_nocontext(original): - code = getattr(original, 'func_code', None) + code = getattr(original, '__code__', None) if code is None: return True argcount = code.co_argcount @@ -235,22 +245,22 @@ def FunctionSerializer(original, context, nocontextfun=FunctionSerializer_nocont else: result = original(context, data) except StopIteration: - raise RuntimeError, "User function %r raised StopIteration." % original + raise RuntimeError("User function %r raised StopIteration." % original) return serialize(result, context) def MethodSerializer(original, context): def nocontext(original): - func = getattr(original, 'im_func', None) - code = getattr(func, 'func_code', None) + func = getattr(original, '__func__', None) + code = getattr(func, '__code__', None) return code is None or code.co_argcount == 2 return FunctionSerializer(original, context, nocontext) def RendererSerializer(original, context): def nocontext(original): - func = getattr(original, 'im_func', None) - code = getattr(func, 'func_code', None) + func = getattr(original, '__func__', None) + code = getattr(func, '__code__', None) return code is None or code.co_argcount == 2 return FunctionSerializer(original.rend, context, nocontext) diff --git a/nevow/flat/ten.py b/nevow/flat/ten.py index 9db7f3ab..a19f5785 100644 --- a/nevow/flat/ten.py +++ b/nevow/flat/ten.py @@ -1,7 +1,7 @@ # Copyright (c) 2004 Divmod. # See LICENSE for details. -from __future__ import generators + import types import warnings @@ -83,8 +83,6 @@ def iterflatten(stan, ctx, writer, shouldYieldItem=None): for item in gen: if isinstance(item, str): straccum.append(item) - elif isinstance(item, unicode): - straccum.append(item.encode('utf8')) elif isinstance(item, (list, types.GeneratorType)): # stop iterating this generator and put it back on the stack # and start iterating the new item instead. diff --git a/nevow/flat/twist.py b/nevow/flat/twist.py index d1afba2b..8e1ae96a 100644 --- a/nevow/flat/twist.py +++ b/nevow/flat/twist.py @@ -21,13 +21,13 @@ def _drive(iterable, finished): it after those Deferreds fire. """ try: - next = iterable.next() + next_item = next(iterable) except StopIteration: finished.callback('') except: finished.errback() else: - deferred, returner = next + deferred, returner = next_item def cb(result): """ Pass the result of a Deferred on to the callable which is diff --git a/nevow/guard.py b/nevow/guard.py index c8f9e6ed..5bf98dbe 100644 --- a/nevow/guard.py +++ b/nevow/guard.py @@ -16,9 +16,9 @@ from hashlib import md5 except ImportError: from md5 import md5 -import StringIO +import io -from zope.interface import implements +from zope.interface import implementer # Twisted Imports @@ -33,20 +33,23 @@ from twisted.protocols import http # Nevow imports -from nevow import inevow, url, stan +from nevow import inevow, url, stan, util def _sessionCookie(): - return md5("%s_%s" % (str(random.random()) , str(time.time()))).hexdigest() + return md5((b"%b_%b" % ( + str(random.random()).encode("ascii"), + str(time.time()).encode("ascii"))) + ).hexdigest() +@implementer(inevow.ISession, inevow.IGuardSession) class GuardSession(components.Componentized): """A user's session with a system. This utility class contains no functionality, but is used to represent a session. """ - implements(inevow.ISession, inevow.IGuardSession) def __init__(self, guard, uid): """Initialize a session with a unique ID for that session. @@ -68,7 +71,7 @@ def getLoggedInRoot(self): # XXX TODO: need to actually sort avatars by login order! if len(self.portals) != 1: raise RuntimeError("Ambiguous request for current avatar.") - return self.portals.values()[0][0] + return list(self.portals.values())[0][0] def resourceForPortal(self, port): return self.portals.get(port) @@ -86,7 +89,7 @@ def setDefaultResource(self, rsrc, logout): raise RuntimeError("Ambiguous request for current avatar.") self.setResourceForPortal( rsrc, - self.portals.keys()[0], + list(self.portals.keys())[0], logout) def setResourceForPortal(self, rsrc, port, logout): @@ -148,7 +151,7 @@ def expire(self): del self.guard.sessions[self.uid] # Logout of all portals - for portal in self.portals.keys(): + for portal in list(self.portals.keys()): self.portalLogout(portal) for c in self.expireCallbacks: @@ -170,7 +173,7 @@ def checkExpired(self): self.checkExpiredID = None # If I haven't been touched in 15 minutes: if time.time() - self.lastModified > self.lifetime / 2: - if self.guard.sessions.has_key(self.uid): + if self.uid in self.guard.sessions: self.expire() else: log.msg("no session to expire: %s" % str(self.uid)) @@ -180,7 +183,7 @@ def checkExpired(self): self.checkExpired) def __getstate__(self): d = self.__dict__.copy() - if d.has_key('checkExpiredID'): + if 'checkExpiredID' in d: del d['checkExpiredID'] return d @@ -196,7 +199,7 @@ def urlToChild(ctx, *ar, **kw): u = u.child(stan.xml(segment)) if inevow.IRequest(ctx).method == 'POST': u = u.clear() - for k,v in kw.items(): + for k,v in list(kw.items()): u = u.replace(k, v) return u @@ -209,8 +212,8 @@ def urlToChild(ctx, *ar, **kw): def nomind(*args): return None +@implementer(inevow.IResource) class Forbidden(object): - implements(inevow.IResource) def locateChild(self, ctx, segments): return self @@ -221,6 +224,7 @@ def renderHTTP(self, ctx): return ("Forbidden" "

Forbidden

Request was forbidden.") +@implementer(inevow.IResource) class SessionWrapper: """ SessionWrapper @@ -241,7 +245,6 @@ class SessionWrapper: the browser is closed before the session timeout, both the session and the cookie go away. """ - implements(inevow.IResource) sessionLifetime = 3600 sessionFactory = GuardSession @@ -272,7 +275,8 @@ def __init__(self, portal, cookieKey=None, mindFactory=None, credInterface=None, def renderHTTP(self, ctx): request = inevow.IRequest(ctx) d = defer.maybeDeferred(self._delegate, ctx, []) - def _cb((resource, segments), ctx): + def _cb(res_and_segments, ctx): + (resource, segments) = res_and_segments assert not segments res = inevow.IResource(resource) return res.renderHTTP(ctx) @@ -341,7 +345,11 @@ def _delegate(self, ctx, segments): sz = self.sessions[httpAuthSessionKey] = self.sessionFactory(self, httpAuthSessionKey) # kick off the expiry timer. sz.checkExpired() - return self.checkLogin(ctx, sz, segments, None, UsernamePassword(*userpass)) + return self.checkLogin(ctx, sz, segments, None, + # XXX insanity: see at getCredentials + UsernamePassword( + util.toBytes(userpass[0]), + util.toString(userpass[1]))) # no, really, without a session ## Redirect to the URL with the session key in it, plus the segments of the url @@ -367,7 +375,7 @@ def createSession(self, ctx, segments): else: expires = None request.addCookie(self.cookieKey, newCookie, - path="/%s" % '/'.join(request.prepath), + path=b"/%s" % b'/'.join(request.prepath), secure=secure, expires=expires, domain=self.cookieDomainForRequest(request)) sz = self.sessions[newCookie] = self.sessionFactory(self, newCookie) @@ -425,14 +433,13 @@ def checkLogin(self, ctx, session, segments, sessionURL=None, httpAuthCredential if spoof and hasattr(session, 'args'): request.args = session.args request.fields = session.fields - request.content = StringIO.StringIO() + request.content = io.StringIO() request.content.close() request.method = session.method request.requestHeaders = session._requestHeaders del session.args, session.fields, session.method, session._requestHeaders - if segments and segments[0] in (LOGIN_AVATAR, LOGOUT_AVATAR): authCommand = segments[0] else: @@ -447,12 +454,13 @@ def checkLogin(self, ctx, session, segments, sessionURL=None, httpAuthCredential return self.login(request, session, httpAuthCredentials, segments).addErrback( self.authRequiredError, session ) - + if authCommand == LOGIN_AVATAR: subSegments = segments[1:] - def unmangleURL((res,segs)): + def unmangleURL(res_and_segments): # Tell the session that we just logged in so that it will # remember form values for us. + (res,segs) = res_and_segments session.justLoggedIn = True # Then, generate a redirect back to where we're supposed to be # by looking at the root of the site and calculating the path @@ -506,8 +514,12 @@ def explicitLogout(self, session): session.portalLogout(self.portal) def getCredentials(self, request): - username = request.args.get('username', [''])[0] - password = request.args.get('password', [''])[0] + # XXX insanity: cred.checkers.InMemoryUsernamePasswordDatabaseDontUse + # has bytes-valued usernames. No idea why; anyway, I'd really + # like these to be actual strings. + # We're doing the same madness below (look for XXX insanity) + username = util.toBytes(request.args.get(b'username', [''])[0]) + password = util.toString(request.args.get(b'password', [''])[0]) return UsernamePassword(username, password) def login(self, request, session, credentials, segments): @@ -533,7 +545,8 @@ def login(self, request, session, credentials, segments): self._cbLoginSuccess, session, segments ) - def _cbLoginSuccess(self, (iface, res, logout), session, segments): + def _cbLoginSuccess(self, descriptor, session, segments): + (iface, res, logout) = descriptor session.setResourceForPortal(res, self.portal, logout) return res, segments diff --git a/nevow/i18n.py b/nevow/i18n.py index 68b876cd..8158b72b 100644 --- a/nevow/i18n.py +++ b/nevow/i18n.py @@ -1,8 +1,21 @@ -from zope.interface import implements +from zope.interface import implementer from nevow import inevow +def _robustFloat(literal): + """returns a float for literal. + + Non-int literals are mapped to -1; nevow 0.14 and earlier accepts + this kind of thing (but we now sort such items to the end of the + preference list). + """ + try: + return float(literal) + except ValueError: + return -1 + + def languagesFactory(ctx): header = inevow.IRequest(ctx).getHeader('accept-language') if header is None: @@ -20,12 +33,12 @@ def languagesFactory(ctx): langs.append((quality, lang)) if '-' in lang: langs.append((quality, lang.split('-')[0])) - langs.sort(lambda a,b: cmp(b[0], a[0])) + langs.sort(key=lambda ob: _robustFloat(ob[0]), reverse=True) return [lang for quality, lang in langs] +@implementer(inevow.II18NConfig) class I18NConfig(object): - implements(inevow.II18NConfig) def __init__(self, domain=None, @@ -111,13 +124,13 @@ class Translator(object): @ivar kwargs: keyword arguments to pass to translator. @ivar gettextFunction: If using the default translator function, - name of GNU gettext function to wrap. Useful for 'ungettext'. + name of GNU gettext function to wrap. Useful for 'ngettext'. """ translator = None args = None kwargs = None - gettextFunction = 'ugettext' + gettextFunction = 'gettext' def _gettextTranslation(self, *args, **kwargs): domain = kwargs.pop('domain', None) @@ -162,7 +175,7 @@ def __call__(self, *args, **kwargs): Translate a string. @param args: arguments to pass to translator, usually the - string to translate, or for things like ungettext two strings + string to translate, or for things like ngettext two strings and a number. @param kwargs: keyword arguments for the translator. @@ -181,7 +194,7 @@ def __call__(self, *args, **kwargs): _ = Translator() -ungettext = Translator(gettextFunction='ungettext') +ngettext = Translator(gettextFunction='ngettext') def render(translator=None): """ @@ -209,7 +222,7 @@ def _render(page, ctx, data): children = ctx.tag.children ctx.tag.clear() for child in children: - if isinstance(child, basestring): + if isinstance(child, str): child = translator(child) ctx.tag[child] return ctx.tag diff --git a/nevow/json.py b/nevow/json.py index 887fc0c3..ec0ca871 100644 --- a/nevow/json.py +++ b/nevow/json.py @@ -1,333 +1,88 @@ -# -*- test-case-name: nevow.test.test_json -*- -# Copyright (c) 2004-2007 Divmod. +# Copyright (c) 2018, Divmod # See LICENSE for details. -""" -JavaScript Object Notation. +# Original nevow had a custom json module; there's probably no point +# keeping that now that built-in json in python is ok. +# +# This is just a thin wrapper to make sure athena objects are serialisable. -This is not (nor does it intend to be) a faithful JSON implementation, but it -is kind of close. -""" - -import re, types +import json from nevow.inevow import IAthenaTransportable from nevow import rend, page, _flat, tags -class ParseError(ValueError): - pass - -whitespace = re.compile( - r'(' - r'[\r\n\t\ ]+' - r'|/\*.*?\*/' - r'|//[^\n]*[\n]' - r')' - , re.VERBOSE + re.DOTALL) -openBrace = re.compile(r'{') -closeBrace = re.compile(r'}') -openSquare = re.compile(r'\[') -closeSquare = re.compile(r'\]') -class StringTokenizer(object): +class NevowJSONEncoder(json.JSONEncoder): + """a json.JSONEncoder with extra logic for encoding some custom nevow + types. """ - because r'(?[a-fA-F0-9]{2})) # Match hex-escaped unicode' u'\n' - ur'|' u'\n' - ur'(?:\\u(?P[a-fA-F0-9]{4})) # Match hex-escaped high unicode' u'\n' - ur'|' u'\n' - ur'(?P\\[fbntr\\"]) # Match escaped control characters' u'\n', - re.VERBOSE) - -_controlMap = { - u'\\f': u'\f', - u'\\b': u'\b', - u'\\n': u'\n', - u'\\t': u'\t', - u'\\r': u'\r', - u'\\"': u'"', - u'\\\\': u'\\', - } - -def _stringSub(m): - u = m.group('unicode') - if u is None: - u = m.group('unicode2') - if u is not None: - return unichr(int(u, 16)) - c = m.group('control') - return _controlMap[c] - - -def parseString(tokens): - if type(tokens[0]) is not StringToken: - raise ParseError, "Unexpected %r" % tokens[0] - s = _stringExpr.sub(_stringSub, tokens.pop(0)[1:-1].decode('utf-8')) - return s, tokens - - -def parseIdentifier(tokens): - if type(tokens[0]) is not IdentifierToken: - raise ParseError("Unexpected %r" % (tokens[0],)) - return tokens.pop(0), tokens - - -def parseList(tokens): - l = [] - tokens.pop(0) - first = True - while tokens[0] != ']': - if not first: - accept(',', tokens) - first = False - - value, tokens = parseValue(tokens) - l.append(value) - - accept(']', tokens) - return l, tokens - + res = [] + def _w(s): + res.append(s) + + transportable = IAthenaTransportable(obj, None) + if transportable is None: + if isinstance(obj, type(None)): + return 'null' + else: + return json.dumps(obj) + else: + _w('(new ' + transportable.jsClass + '(') + arguments = transportable.getInitialArguments() + for n, e in enumerate(arguments): + _w(self.default(e)) + if n != len(arguments) - 1: + _w(',') + _w('))') + return "".join(res) + + +class NevowJSONDecoder(json.JSONDecoder): + """a json.JSONDecoder with logic for decoding the extra types + serialized by NevowJSONEncoder. + """ -def parseObject(tokens): - o = {} - tokens.pop(0) - first = True - while tokens[0] != '}': - if not first: - accept(',', tokens) - first = False - name, tokens = parseString(tokens) - accept(':', tokens) - value, tokens = parseValue(tokens) - o[name] = value +def dumps(obj, **kwargs): + """ + JSON-encode an object to a str. - accept('}', tokens) - return o, tokens + @param obj: None, True, False, an int, long, float, unicode string, + list, tuple, or dictionary the JSON-encoded form of which will be + returned. + """ + return NevowJSONEncoder(**kwargs).encode(obj) -def parse(s): +def loads(string, **kwargs): """ Return the object represented by the JSON-encoded string C{s}. - """ - tokens = tokenise(s) - value, tokens = parseValue(tokens) - if tokens: - raise ParseError, "Unexpected %r" % tokens[0] - return value - -class CycleError(Exception): - pass -_translation = dict([(o, u'\\x%02x' % (o,)) for o in range(0x20)]) - -# Characters which cannot appear as literals in the output -_translation.update({ - ord(u'\\'): u'\\\\', - ord(u'"'): ur'\"', - ord(u'\f'): ur'\f', - ord(u'\b'): ur'\b', - ord(u'\n'): ur'\n', - ord(u'\t'): ur'\t', - ord(u'\r'): ur'\r', - # The next two are sneaky, see - # http://timelessrepo.com/json-isnt-a-javascript-subset - ord(u'\u2028'): u'\\u2028', - ord(u'\u2029'): u'\\u2029', - }) - -def stringEncode(s): - return s.translate(_translation).encode('utf-8') - - -def _serialize(obj, w, seen): - from nevow import athena - - if isinstance(obj, types.BooleanType): - if obj: - w('true') - else: - w('false') - elif isinstance(obj, (int, long, float)): - w(str(obj)) - elif isinstance(obj, unicode): - w('"') - w(stringEncode(obj)) - w('"') - elif isinstance(obj, types.NoneType): - w('null') - elif id(obj) in seen: - raise CycleError(type(obj)) - elif isinstance(obj, (tuple, list)): - w('[') - for n, e in enumerate(obj): - _serialize(e, w, seen) - if n != len(obj) - 1: - w(',') - w(']') - elif isinstance(obj, dict): - w('{') - for n, (k, v) in enumerate(obj.iteritems()): - _serialize(k, w, seen) - w(':') - _serialize(v, w, seen) - if n != len(obj) - 1: - w(',') - w('}') - elif isinstance(obj, (athena.LiveFragment, athena.LiveElement)): - _serialize(obj._structured(), w, seen) - elif isinstance(obj, (rend.Fragment, page.Element)): - def _w(s): - w(stringEncode(s.decode('utf-8'))) - wrapper = tags.div(xmlns="http://www.w3.org/1999/xhtml") - w('"') - for _ in _flat.flatten(None, _w, wrapper[obj], False, False): - pass - w('"') - else: - transportable = IAthenaTransportable(obj, None) - if transportable is not None: - w('(new ' + transportable.jsClass.encode('ascii') + '(') - arguments = transportable.getInitialArguments() - for n, e in enumerate(arguments): - _serialize(e, w, seen) - if n != len(arguments) - 1: - w(',') - w('))') - else: - raise TypeError("Unsupported type %r: %r" % (type(obj), obj)) - - - -_undefined = object() -def serialize(obj=_undefined, **kw): + For backward compatibility, C{s} can also be a byte string (it will + be interpreted as utf-8). """ - JSON-encode an object. + if isinstance(string, bytes): + string = string.decode("utf-8") + if string == 'undefined': + return None + return NevowJSONDecoder(**kwargs).decode(string) - @param obj: None, True, False, an int, long, float, unicode string, - list, tuple, or dictionary the JSON-encoded form of which will be - returned. - """ - if obj is _undefined: - obj = kw - L = [] - _serialize(obj, L.append, {}) - return ''.join(L) -__all__ = ['parse', 'serialize'] +__all__ = ['loads', 'dumps'] diff --git a/nevow/jsutil.py b/nevow/jsutil.py index e9f715a8..3c8f01c1 100644 --- a/nevow/jsutil.py +++ b/nevow/jsutil.py @@ -111,6 +111,7 @@ def generateTestScript(fname, after={}, dependencies=None): if m.name in after: js.extend(after[m.name]) - js.append(file(fname).read()) + with open(fname) as f: + js.append(f.read()) return '\n'.join(js) diff --git a/nevow/livetrial/runner.py b/nevow/livetrial/runner.py index f0c94f57..7053ae46 100644 --- a/nevow/livetrial/runner.py +++ b/nevow/livetrial/runner.py @@ -5,7 +5,7 @@ staticData = filepath.FilePath(__file__).parent().child('static') class TestSuiteFragment(athena.LiveFragment): - jsClass = u'Nevow.Athena.Test.TestSuite' + jsClass = 'Nevow.Athena.Test.TestSuite' docFactory = loaders.stan(tags.invisible(render=tags.directive('tests'))) def __init__(self, suite): @@ -34,7 +34,7 @@ def gather(testInstances): else: head.append(test.head()) gather(self.testInstances) - return filter(None, head) + return [item for item in head if item] def render_tests(self, ctx, data): @@ -43,7 +43,7 @@ def render_tests(self, ctx, data): class TestRunner(TestSuiteFragment): - jsClass = u'Nevow.Athena.Test.TestRunner' + jsClass = 'Nevow.Athena.Test.TestRunner' docFactory = loaders.stan( tags.div(_class='test-runner', render=tags.directive('liveFragment'))[ tags.form(action='#')[ diff --git a/nevow/livetrial/testcase.py b/nevow/livetrial/testcase.py index 123dec66..11af487c 100644 --- a/nevow/livetrial/testcase.py +++ b/nevow/livetrial/testcase.py @@ -62,7 +62,7 @@ def getWidgetDocument(self): Subclasses may want to override this. """ - return u'' + return '' def head(self): @@ -145,16 +145,16 @@ def __init__(self): def loadByName(self, name, recurse=False): - thing = self.findByName(name) - return self.loadAnything(thing, recurse) + return self.findByName(name) + #return self.loadAnything(thing, recurse) #findByName calls loadAnything def loadMethod(self, method): - raise NotImplementedError, 'livetests must be classes' + raise NotImplementedError('livetests must be classes') def loadClass(self, klass): - if not (isinstance(klass, type) or isinstance(klass, types.ClassType)): + if not (isinstance(klass, type) or isinstance(klass, type)): raise TypeError("%r is not a class" % (klass,)) if not self.isTestCase(klass): raise ValueError("%r is not a test case" % (klass,)) @@ -171,7 +171,7 @@ def loadModule(self, module): def isTestCase(self, obj): - return isinstance(obj, (type, types.ClassType)) and issubclass(obj, TestCase) and obj is not TestCase + return isinstance(obj, type) and issubclass(obj, TestCase) and obj is not TestCase def _findTestClasses(self, module): diff --git a/nevow/loaders.py b/nevow/loaders.py index ada36f00..c4779673 100644 --- a/nevow/loaders.py +++ b/nevow/loaders.py @@ -8,24 +8,22 @@ - B{stan} - turn a stan tag tree into a DocFactory - B{xmlfile} - load a well formed XML document from file - - B{htmlfile} - load a HTML file from disk + - B{htmlfile} - legacy alias for xmlfile - B{xmlstr} - load a well formed XML document from a string - - B{htmlstr} - load a HTML document from a string + - B{htmlstr} - legacy alias for xmlstr -Unless absolutely necessary you should use either the stan loader or -one of the xml loaders. The html loaders should only be used for badly -formed HTML documents, i.e. if your HTML developer hasn't heard of -XHTML yet. Even then, you should probably try to educate the HTML -developer first ;-). +Until nevow 0.14, the html loaders would accept malformed XHTML. +Since twisted.web.microdom is no longer supported, maintaining +that feature became difficult. Just write well-formed XHTML. It's not +so hard. """ import warnings import os.path -from zope.interface import implements +from zope.interface import implementer from twisted.python.reflect import getClass -from twisted.web import microdom from nevow import inevow from nevow import flat @@ -33,10 +31,10 @@ from nevow.util import CachedFile +@implementer(inevow.IDocFactory) class stan(object): """A stan tags document factory""" - implements(inevow.IDocFactory) stan = None pattern = None @@ -62,78 +60,9 @@ def load(self, ctx=None, preprocessors=()): -class htmlstr(object): - """A document factory for HTML contained in a string""" - - implements(inevow.IDocFactory) - - template = None - pattern = None - beExtremelyLenient = True - _cache = None - - def __init__(self, template=None, pattern=None, beExtremelyLenient=None): - warnings.warn( - "[v0.8] htmlstr is deprecated because it's buggy. Please start using xmlfile and/or xmlstr.", - DeprecationWarning, - stacklevel=2) - if template is not None: - self.template = template - if pattern is not None: - self.pattern = pattern - if beExtremelyLenient is not None: - self.beExtremelyLenient = beExtremelyLenient - - def load(self, ctx=None, preprocessors=()): - assert not preprocessors, "preprocessors not supported by htmlstr" - if self._cache is None: - doc = microdom.parseString(self.template, beExtremelyLenient=self.beExtremelyLenient) - doc = flat.precompile(doc, ctx) - if self.pattern is not None: - doc = inevow.IQ(doc).onePattern(self.pattern) - self._cache = doc - return self._cache - -class htmlfile(object): - """A document factory for an HTML disk template""" - - implements(inevow.IDocFactory) - - template = None - pattern = None - templateDir = '' - beExtremelyLenient = True - - def __init__(self, template=None, pattern=None, templateDir=None, beExtremelyLenient=None): - warnings.warn( - "[v0.8] htmlfile is deprecated because it's buggy. Please start using xmlfile and/or xmlstr.", - DeprecationWarning, - stacklevel=2) - if template is not None: - self.template = template - if pattern is not None: - self.pattern = pattern - if templateDir is not None: - self.templateDir = templateDir - if beExtremelyLenient is not None: - self.beExtremelyLenient = beExtremelyLenient - _filename = os.path.join(self.templateDir, self.template) - self._cache = CachedFile(_filename, self._reallyLoad) - - def _reallyLoad(self, path, ctx): - doc = microdom.parse(path, beExtremelyLenient=self.beExtremelyLenient) - doc = flat.precompile(doc, ctx) - if self.pattern is not None: - doc = inevow.IQ(doc).onePattern(self.pattern) - return doc - - def load(self, ctx=None, preprocessors=()): - assert not preprocessors, "preprocessors not supported by htmlfile" - return self._cache.load(ctx) - +@implementer(inevow.IDocFactory) class xmlstr(object): - implements(inevow.IDocFactory) template = None pattern = None @@ -166,9 +95,9 @@ def load(self, ctx=None, preprocessors=()): return self._cache +@implementer(inevow.IDocFactory) class xmlfile(object): - implements(inevow.IDocFactory) template = None templateDir = None @@ -219,3 +148,7 @@ def _reallyLoad(self, path, ctx, preprocessors): doc = inevow.IQ(doc).onePattern(self.pattern) return doc + + +htmlfile = xmlfile +htmlstr = xmlstr diff --git a/nevow/page.py b/nevow/page.py index b7109714..45d11e34 100644 --- a/nevow/page.py +++ b/nevow/page.py @@ -6,7 +6,7 @@ API Stability: Completely unstable. """ -from zope.interface import implements +from zope.interface import implementer from nevow.inevow import IRequest, IRenderable, IRendererFactory from nevow.errors import MissingRenderMethod, MissingDocumentFactory @@ -42,6 +42,7 @@ +@implementer(IRenderable) class Element(object): """ Base for classes which can render part of a page. @@ -72,7 +73,6 @@ def items(self, request, tag): @ivar docFactory: The factory which will be used to load documents to return from C{render}. """ - implements(IRenderable) docFactory = None preprocessors = () @@ -97,7 +97,7 @@ def render(self, request): Load and return C{self.docFactory}. """ rend = self.rend - if rend.im_func is not Element.__dict__['rend']: + if rend.__func__ is not Element.__dict__['rend']: context = _ctxForRequest(request, [], self, False) return rend(context, None) diff --git a/nevow/query.py b/nevow/query.py index a1eb97f3..e5fa1b9d 100644 --- a/nevow/query.py +++ b/nevow/query.py @@ -6,10 +6,10 @@ import twisted.python.components as tpc from nevow import inevow, stan -from zope.interface import implements +from zope.interface import implementer +@implementer(inevow.IQ) class QueryContext(tpc.Adapter): - implements(inevow.IQ) def _locatePatterns(self, pattern, default, loop=True): if self.original.tag.pattern == pattern: @@ -47,7 +47,7 @@ def _locatePatterns(self, pattern, default, loop=True): yield x.clone(deep=False, clearPattern=True) if default is None: - raise stan.NodeNotFound, ("pattern", pattern) + raise stan.NodeNotFound("pattern", pattern) if hasattr(default, 'clone'): while True: yield default.clone(deep=False) else: @@ -86,13 +86,13 @@ def __init__(self, original): class QueryNeverFind(tpc.Adapter): def patternGenerator(self, pattern, default=None): - raise stan.NodeNotFound, ('pattern', pattern) + raise stan.NodeNotFound('pattern', pattern) def allPatterns(self, pattern): return [] def onePattern(self, pattern): - raise stan.NodeNotFound, ('pattern', pattern) + raise stan.NodeNotFound('pattern', pattern) def _locatePatterns(self, pattern, default, loop=True): return [] diff --git a/nevow/rend.py b/nevow/rend.py index 9060dc97..87d52234 100644 --- a/nevow/rend.py +++ b/nevow/rend.py @@ -18,11 +18,11 @@ """ from time import time as now -from cStringIO import StringIO +from io import StringIO import random import warnings -from zope.interface import implements, providedBy +from zope.interface import implementer, providedBy import twisted.python.components as tpc from twisted.python.reflect import qual, accumulateClassList @@ -53,8 +53,8 @@ def _getPreprocessors(inst): +@implementer(inevow.IRendererFactory) class RenderFactory(object): - implements(inevow.IRendererFactory) def renderer(self, context, name): """Return a renderer with the given name. @@ -88,8 +88,8 @@ def renderer(self, context, name): render_data = lambda self, context, data_: data(context, data_) +@implementer(inevow.IMacroFactory) class MacroFactory(object): - implements(inevow.IMacroFactory) def macro(self, ctx, name): """Return a macro with the given name. @@ -118,8 +118,8 @@ class DataNotFoundError(Exception): """ +@implementer(inevow.IContainer) class DataFactory(object): - implements(inevow.IContainer) def child(self, context, n): args = [] @@ -157,8 +157,8 @@ def locateChild(self, ctx, segments): if name.startswith('freeform_post!'): configurableName, bindingName = name.split('!')[1:3] elif name.startswith('freeform-action-post!'): - configurableName, request.args['freeform-actee'] = name.split('!')[1:3] - bindingName = request.args['freeform-action'][0] + configurableName, request.args[b'freeform-actee'] = name.split('!')[1:3] + bindingName = request.args[b'freeform-action'][0] if bindingName: ctx.remember(self, inevow.IResource) ctx.remember(request, inevow.IRequest) @@ -177,6 +177,7 @@ def child_freeform_hand(self, ctx): return inevow.IHand(inevow.ISession(ctx), None) +@implementer(iformless.IConfigurable) class ConfigurableMixin(object): """ A sane L{IConfigurable} implementation for L{Fragment} and L{Page}. @@ -193,7 +194,6 @@ def foo(self, argName, anotherArg): assert isinstance(argName, str) assert isinstance(anotherArg, int) """ - implements(iformless.IConfigurable) def getBindingNames(self, ctx): """Expose bind_* methods and attributes on this class. @@ -258,12 +258,12 @@ def _callback(binding): bindingName).addCallback(_callback) +@implementer(iformless.IConfigurableFactory) class ConfigurableFactory: """Locates configurables by looking for methods that start with configurable_ and end with the name of the configurable. The method should take a single arg (other than self) - the current context. """ - implements(iformless.IConfigurableFactory) def locateConfigurable(self, context, name): """formless.webform.renderForms calls locateConfigurable on the IConfigurableFactory @@ -288,7 +288,7 @@ def configurable_(self, context): ... bar = autocallable(bar) ... >>> class Foo(Page): - ... implements(IFoo) + ... @implementer(IFoo) ... ... def bar(): ... print "bar called through the web!" @@ -298,7 +298,7 @@ def configurable_(self, context): ... ... docFactory = stan(render_forms). """ - if filter(lambda x: issubclass(x, annotate.TypedInterface), providedBy(self)): + if [x for x in providedBy(self) if issubclass(x, annotate.TypedInterface)]: warnings.warn("[0.5] Subclassing TypedInterface to declare annotations is deprecated. Please provide bind_* methods on your Page or Fragment subclass instead.", DeprecationWarning) from formless import configurable return configurable.TypedInterfaceConfigurable(self) @@ -363,6 +363,7 @@ def originalFactory(ctx): return ctx.tag +@implementer(inevow.IRenderer, inevow.IGettable) class Fragment(DataFactory, RenderFactory, MacroFactory, ConfigurableMixin): """ This class is deprecated because it relies on context objects @@ -370,7 +371,6 @@ class Fragment(DataFactory, RenderFactory, MacroFactory, ConfigurableMixin): @see: L{Element} """ - implements(inevow.IRenderer, inevow.IGettable) docFactory = None original = None @@ -408,7 +408,7 @@ def rend(self, context, data): finally: self.docFactory.pattern = old self.docFactory.precompiledDoc = None - except TypeError, e: + except TypeError as e: # Avert your eyes now! I don't want to catch anything but IQ # adaption exceptions here but all I get is TypeError. This whole # section of code is a complete hack anyway so one more won't @@ -512,12 +512,12 @@ def putChild(self, name, child): self.children[name] = child +@implementer(inevow.IResource) class Page(Fragment, ConfigurableFactory, ChildLookupMixin): """A page is the main Nevow resource and renders a document loaded via the document factory (docFactory). """ - implements(inevow.IResource) buffered = False @@ -546,7 +546,7 @@ def _renderHTTP(self, ctx): def finishRequest(): carryover = request.args.get('_nevow_carryover_', [None])[0] - if carryover is not None and _CARRYOVER.has_key(carryover): + if carryover is not None and carryover in _CARRYOVER: del _CARRYOVER[carryover] if self.afterRender is not None: return util.maybeDeferred(self.afterRender,ctx) @@ -668,7 +668,7 @@ def redirectAfterPost(aspects): magicCookie = '%s%s%s' % (now(),request.getClientIP(),random.random()) refpath = refpath.replace('_nevow_carryover_', magicCookie) _CARRYOVER[magicCookie] = C = tpc.Componentized() - for k, v in aspects.iteritems(): + for k, v in aspects.items(): C.setComponent(k, v) destination = flat.flatten(refpath, ctx) @@ -783,10 +783,10 @@ def data(context, data): return context.tag.clear()[data] +@implementer(inevow.IResource) class FourOhFour: """A simple 404 (not found) page. """ - implements(inevow.IResource) notFound = "Page Not FoundSorry, but I couldn't find the object you requested." original = None @@ -799,7 +799,7 @@ def renderHTTP(self, ctx): # Look for an application-remembered handler try: notFoundHandler = ctx.locate(inevow.ICanHandleNotFound) - except KeyError, e: + except KeyError as e: return self.notFound # Call the application-remembered handler but if there are any errors # then log it and fallback to the standard message. @@ -809,7 +809,7 @@ def renderHTTP(self, ctx): log.err() return self.notFound - def __nonzero__(self): + def __bool__(self): return False diff --git a/nevow/scripts/nit.py b/nevow/scripts/nit.py index b9ab4c2c..f4e93ee8 100644 --- a/nevow/scripts/nit.py +++ b/nevow/scripts/nit.py @@ -50,7 +50,7 @@ def run(): config = NitOptions() try: config.parseOptions() - except UsageError, ue: + except UsageError as ue: raise SystemExit("%s: %s" % (sys.argv[0], ue)) else: if not config['testmodules']: diff --git a/nevow/scripts/xmlgettext.py b/nevow/scripts/xmlgettext.py index a286edd0..bafea730 100644 --- a/nevow/scripts/xmlgettext.py +++ b/nevow/scripts/xmlgettext.py @@ -1,5 +1,5 @@ from xml.dom import pulldom -from cStringIO import StringIO +from io import StringIO from twisted.python import usage import nevow @@ -38,14 +38,14 @@ def read(self, bufsize): def getMsgID(node): out = StringIO() - print >>out, 'msgid ""' + print('msgid ""', file=out) for child in node.childNodes: s = child.toxml('utf-8') s = s.replace('\\', '\\\\') s = s.replace('"', '\\"') s = s.replace('\n', '\\n') - print >>out, '"%s"' % s - print >>out, 'msgstr ""' + print('"%s"' % s, file=out) + print('msgstr ""', file=out) return out.getvalue() def process(filename, messages): @@ -69,12 +69,12 @@ def process(filename, messages): def report(messages): for msgid, locations in messages.items(): for line in locations: - print line - print msgid + print(line) + print(msgid) class GettextOptions(usage.Options): def opt_version(self): - print 'Nevow version:', nevow.__version__ + print('Nevow version:', nevow.__version__) usage.Options.opt_version(self) def parseArgs(self, *files): diff --git a/nevow/stan.py b/nevow/stan.py index fc6f689b..36b3d714 100644 --- a/nevow/stan.py +++ b/nevow/stan.py @@ -21,8 +21,8 @@ prototypes for all of the XHTML element types. """ -from __future__ import generators -from zope.interface import implements + +from zope.interface import implementer from nevow import inevow @@ -96,9 +96,9 @@ def __hash__(self): return hash((directive, self.name)) - def __cmp__(self, other): + def __eq__(self, other): if isinstance(other, directive): - return cmp(self.name, other.name) + return self.name == other.name return NotImplemented @@ -147,7 +147,7 @@ def __iter__(self): """Prevent an infinite loop if someone tries to do for x in slot('foo'): """ - raise NotImplementedError, "Stan slot instances are not iterable." + raise NotImplementedError("Stan slot instances are not iterable.") @@ -201,6 +201,7 @@ def __repr__(self): +@implementer(inevow.IQ) class Tag(object): """ Tag instances represent XML tags with a tag name, attributes, and @@ -224,7 +225,6 @@ class Tag(object): the XML file from which it was parsed. If it was not parsed from an XML file, C{None}. """ - implements(inevow.IQ) specials = ['data', 'render', 'remember', 'pattern', 'key', 'macro'] @@ -362,11 +362,11 @@ def __call__(self, **kw): return self for name in self.specials: - if kw.has_key(name): + if name in kw: setattr(self, name, kw[name]) del kw[name] - for k, v in kw.iteritems(): + for k, v in kw.items(): if k[-1] == '_': k = k[:-1] elif k[0] == '_': @@ -403,7 +403,7 @@ def __iter__(self): """Prevent an infinite loop if someone tries to do for x in stantaginstance: """ - raise NotImplementedError, "Stan tag instances are not iterable." + raise NotImplementedError("Stan tag instances are not iterable.") def _clearSpecials(self): """Clears all the specials in this tag. For use by flatstan. @@ -496,7 +496,7 @@ def forever(): class UnsetClass: - def __nonzero__(self): + def __bool__(self): return False def __repr__(self): return "Unset" @@ -546,18 +546,18 @@ class PatternTag(object): through a sequence of matching patterns.''' def __init__(self, patterner): - self.pat = patterner.next() + self.pat = next(patterner) self.patterner = patterner - def next(self): + def __next__(self): if self.pat: p, self.pat = self.pat, None return p - return self.patterner.next() + return next(self.patterner) def makeForwarder(name): - return lambda self, *args, **kw: getattr(self.next(), name)(*args, **kw) + return lambda self, *args, **kw: getattr(next(self), name)(*args, **kw) for forward in ['__call__', '__getitem__', 'fillSlots']: setattr(PatternTag, forward, makeForwarder(forward)) @@ -591,7 +591,7 @@ def _locatePatterns(tag, pattern, default, loop=True): yield cloned if default is None: - raise NodeNotFound, ("pattern", pattern) + raise NodeNotFound("pattern", pattern) if hasattr(default, 'clone'): while True: yield default.clone(deep=False) else: diff --git a/nevow/static.py b/nevow/static.py index cfb783cc..6fbbc4a4 100644 --- a/nevow/static.py +++ b/nevow/static.py @@ -7,12 +7,10 @@ # System Imports import os, string, time -import cStringIO +import io import traceback import warnings -StringIO = cStringIO -del cStringIO -from zope.interface import implements +from zope.interface import implementer try: from twisted.web.resource import NoResource, ForbiddenResource @@ -38,11 +36,11 @@ def isDangerous(path): return path == '..' or '/' in path or os.sep in path +@implementer(inevow.IResource) class Data: """ This is a static, in-memory resource. """ - implements(inevow.IResource) def __init__(self, data, type, expires=None): self.data = data @@ -83,7 +81,7 @@ def addSlash(request): return "http%s://%s%s/" % ( request.isSecure() and 's' or '', request.getHeader("host"), - (string.split(request.uri,'?')[0])) + (request.uri.split('?')[0])) class Registry(components.Componentized): """ @@ -145,7 +143,7 @@ def loadMimeTypes(mimetype_locations=['/etc/mime.types']): def getTypeAndEncoding(filename, types, encodings, defaultType): p, ext = os.path.splitext(filename) ext = ext.lower() - if encodings.has_key(ext): + if ext in encodings: enc = encodings[ext] ext = os.path.splitext(p)[1].lower() else: @@ -153,6 +151,7 @@ def getTypeAndEncoding(filename, types, encodings, defaultType): type = types.get(ext, defaultType) return type, enc +@implementer(inevow.IResource) class File: """ File is a resource that represents a plain non-interpreted file @@ -171,7 +170,6 @@ class File: return the contents of /tmp/foo/bar.html . """ - implements(inevow.IResource) contentTypes = loadMimeTypes() @@ -301,7 +299,7 @@ def renderHTTP(self, ctx): try: f = self.openForReading() - except IOError, e: + except IOError as e: import errno if e[0] == errno.EACCES: return ForbiddenResource().render(request) @@ -316,10 +314,10 @@ def renderHTTP(self, ctx): if range is not None: # This is a request for partial data... - bytesrange = string.split(range, '=') + bytesrange = range.split('=') assert bytesrange[0] == 'bytes',\ "Syntactically invalid http range header!" - start, end = string.split(bytesrange[1],'-') + start, end = bytesrange[1].split('-') if start: f.seek(int(start)) if end: @@ -413,8 +411,8 @@ def view_stopProducing(self, issuer): Inspired by Apache's mod_asis """ +@implementer(inevow.IResource) class ASISProcessor: - implements(inevow.IResource) def __init__(self, path, registry=None): self.path = path diff --git a/nevow/taglibrary/tabbedPane.py b/nevow/taglibrary/tabbedPane.py index 059e0f45..8f96abb4 100644 --- a/nevow/taglibrary/tabbedPane.py +++ b/nevow/taglibrary/tabbedPane.py @@ -19,13 +19,14 @@ class tabbedPaneGlue: fileCSS = static.File(stylesheetPath, 'text/css') - inlineCSS = t.style(type_='text/css')[ t.xml(file(stylesheetPath).read()) ] + with open(stylesheetPath) as f: + inlineCSS = t.style(type_='text/css')[ t.xml(f.read()) ] class TabbedPaneFragment(athena.LiveFragment): - jsClass = u'Nevow.TagLibrary.TabbedPane.TabbedPane' - cssModule = u'Nevow.TagLibrary.TabbedPane' + jsClass = 'Nevow.TagLibrary.TabbedPane.TabbedPane' + cssModule = 'Nevow.TagLibrary.TabbedPane' docFactory = loaders.xmlstr("""
} node containing the tab's number. """ return TabbedPaneFragment( - [('Page ' + str(i), tags.h1[str(i)]) for i in xrange(4)]) + [('Page ' + str(i), tags.h1[str(i)]) for i in range(4)]) class TabbedPaneFetcher(athena.LiveElement): - jsClass = u'Nevow.Test.TestTabbedPane.TabbedPaneFetcher' + jsClass = 'Nevow.Test.TestTabbedPane.TabbedPaneFetcher' docFactory = loaders.xmlstr("""
') @@ -569,7 +571,7 @@ def test_handlerMacroAgainstList(self): macro is. """ tag = ["hello", " ", "world"] - self.assertEquals( + self.assertEqual( athena._rewriteEventHandlerToAttribute(tag), tag) @@ -590,15 +592,24 @@ def test_athenaIdRewriting(self): element.setFragmentParent(page) def _verifyRendering(result): - self.assertIn(' + setContent(temp, """ This is some template data! @@ -100,8 +101,8 @@ def render_replaceNode(self, context, data): tr = TemplateRenderer(docFactory=loaders.htmlfile(temp)) return deferredRender(tr).addCallback( - lambda result: self.assertEquals( - result, + lambda result: self.assertEqual( + re.sub("\n *", "", result.decode("ascii")), 'THE TITLE

THE HEADER

SOME DUMMY TEXT' )) @@ -109,7 +110,7 @@ def test_sequence(self): """Test case provided by mg """ temp = self.mktemp() - setContent(temp, """
""") + setContent(temp, """
""") class TemplateRenderer(rend.Page): def data_aList(self,context,data): @@ -119,8 +120,8 @@ def data_aList(self,context,data): return deferredRender(tr).addCallback( lambda result: - self.assertEquals( - result, '
  1. one
  2. two
  3. three
', + self.assertEqual( + result, b'
  1. one
  2. two
  3. three
', "Whoops. We didn't get what we expected!" )) @@ -128,7 +129,7 @@ def test_sequence2(self): """Test case provided by radix """ temp = self.mktemp() - setContent(temp, """
""") + setContent(temp, """
""") class TemplateRenderer(rend.Page): def data_aList(self,context,data): @@ -138,8 +139,8 @@ def data_aList(self,context,data): return deferredRender(tr).addCallback( lambda result: - self.assertEquals( - result, '
  1. one
  2. two
  3. three
', + self.assertEqual( + result, b'
  1. one
  2. two
  3. three
', "Whoops. We didn't get what we expected!" )) @@ -149,29 +150,26 @@ def test_slots(self): """ temp = self.mktemp() setContent(temp, """ - - - -
""") +
""") class Renderer(rend.Page): def data_aDict(self,context,data): return {'1':'one','2':'two','3':'three','4':'four'} def render_slots(self,context,data): - for name,value in data.items(): + for name,value in list(data.items()): context.fillSlots(name, value) return context.tag return deferredRender(Renderer(docFactory=loaders.htmlfile(temp))).addCallback( lambda result: - self.assertEquals( + self.assertEqual( result, - "
onetwo
threefour
", + b"
onetwo
threefour
", "Whoops. We didn't get what we expected!")) def test_patterns(self): temp = self.mktemp() - setContent(temp, """ + setContent(temp, """ ONE TWO THREE @@ -183,11 +181,11 @@ def render_foo(self, context, data): return defer.DeferredList([ deferredRender(Mine("one", docFactory=loaders.htmlfile(temp))).addCallback( - lambda result: self.assertEquals(result, 'ONE')), + lambda result: self.assertEqual(result, b'ONE')), deferredRender(Mine("two", docFactory=loaders.htmlfile(temp))).addCallback( - lambda result: self.assertEquals(result, 'TWO')), + lambda result: self.assertEqual(result, b'TWO')), deferredRender(Mine("three", docFactory=loaders.htmlfile(temp))).addCallback( - lambda result: self.assertEquals(result, 'THREE')) + lambda result: self.assertEqual(result, b'THREE')) ], fireOnOneErrback=True) @@ -212,10 +210,10 @@ def render_world(self, context, data): sr = Subclass() D = deferredRender(sr) def after(result): - self.assertSubstring('hello', result) - self.assertSubstring('world', result) - self.assertEquals(result, - "
hello
world") + self.assertSubstring(b'hello', result) + self.assertSubstring(b'world', result) + self.assertEqual(result, + b"
hello
world") return D.addCallback(after) @@ -246,10 +244,10 @@ def testXML(self): def testHTML(self): - t = 'hreflabel' + t = 'hreflabel' doc = flat.flatten(loaders.htmlstr(t).load()) self.assertEqual(doc, 'label') - t = 'label' + t = 'label' precompiled = loaders.htmlstr(t).load() ctx = context.WovenContext(tag=tags.invisible[precompiled]) ctx.fillSlots('href', 'href') diff --git a/nevow/test/test_element.py b/nevow/test/test_element.py index 1b862321..1bb8ba40 100644 --- a/nevow/test/test_element.py +++ b/nevow/test/test_element.py @@ -182,7 +182,7 @@ def test_simpleStanRendering(self): """ f = Element(docFactory=stan(p["Hello, world."])) return self._render(f).addCallback( - self.assertEquals, "

Hello, world.

") + self.assertEqual, "

Hello, world.

") def test_docFactoryClassAttribute(self): @@ -194,7 +194,7 @@ def test_docFactoryClassAttribute(self): class SubElement(Element): docFactory = stan(p["Hello, world."]) return self._render(SubElement()).addCallback( - self.assertEquals, "

Hello, world.

") + self.assertEqual, "

Hello, world.

") def test_simpleXHTMLRendering(self): @@ -204,7 +204,7 @@ def test_simpleXHTMLRendering(self): """ f = Element(docFactory=xmlstr("

Hello, world.

")) return self._render(f).addCallback( - self.assertEquals, "

Hello, world.

") + self.assertEqual, "

Hello, world.

") def test_stanDirectiveRendering(self): @@ -242,7 +242,7 @@ def renderMethod(self, request, tag): docFactory=stan(p(render=directive('renderMethod'))[ "Goodbye, world."])) return self._render(f).addCallback( - self.assertEquals, "Hello, world.") + self.assertEqual, "Hello, world.") def test_elementContainingStaticElement(self): @@ -257,7 +257,7 @@ def renderMethod(self, request, tag): f = RenderfulElement( docFactory=stan(p(render=directive('renderMethod')))) return self._render(f).addCallback( - self.assertEquals, "

Hello, world.

") + self.assertEqual, "

Hello, world.

") def test_elementContainingDynamicElement(self): @@ -277,7 +277,7 @@ def innerMethod(self, request, tag): f = OuterElement( docFactory=stan(p(render=directive('outerMethod')))) return self._render(f).addCallback( - self.assertEquals, "

Hello, world.

") + self.assertEqual, "

Hello, world.

") def test_synchronousFlatten(self): diff --git a/nevow/test/test_errorhandler.py b/nevow/test/test_errorhandler.py index 6a4b2e1b..53625121 100644 --- a/nevow/test/test_errorhandler.py +++ b/nevow/test/test_errorhandler.py @@ -1,5 +1,5 @@ -from zope.interface import implements +from zope.interface import implementer from twisted.python import log from twisted.internet import defer from nevow import appserver, context, inevow, loaders, rend, tags as T, testutil @@ -10,8 +10,8 @@ class Root(rend.Page): +@implementer(inevow.ICanHandleNotFound) class NotFoundHandler(object): - implements(inevow.ICanHandleNotFound) html = 'NotFoundHandler' def renderHTTP_notFound(self, ctx): return self.html @@ -19,8 +19,8 @@ def renderHTTP_notFound(self, ctx): class BrokenException(Exception): pass +@implementer(inevow.ICanHandleNotFound) class BadNotFoundHandler(object): - implements(inevow.ICanHandleNotFound) html = 'NotFoundHandler' exceptionType = BrokenException exceptionMessage ='Error from BadNotFoundHandler' @@ -61,25 +61,28 @@ def test_standard404(self): """ root = Root() def later(resource): - self.failUnless(isinstance(resource, rend.FourOhFour)) - def morelater((code, html)): - self.assertEquals(rend.FourOhFour.notFound, html) - self.assertEquals(code, 404) + self.assertTrue(isinstance(resource, rend.FourOhFour)) + def morelater(xxx_todo_changeme): + (code, html) = xxx_todo_changeme + self.assertEqual(rend.FourOhFour.notFound, html) + self.assertEqual(code, 404) return renderResource('/foo').addCallback(morelater) return getResource(root, '/foo').addCallback(later) def test_remembered404Handler(self): - def later((code, html)): - self.assertEquals(html, NotFoundHandler.html) - self.assertEquals(code, 404) + def later(xxx_todo_changeme1): + (code, html) = xxx_todo_changeme1 + self.assertEqual(html, NotFoundHandler.html) + self.assertEqual(code, 404) return renderResource('/foo', notFoundHandler=NotFoundHandler()).addCallback(later) def test_keyErroringNotFoundHandler(self): - def later((code, html)): - self.assertEquals(rend.FourOhFour.notFound, html) - self.assertEquals(code, 404) + def later(xxx_todo_changeme2): + (code, html) = xxx_todo_changeme2 + self.assertEqual(rend.FourOhFour.notFound, html) + self.assertEqual(code, 404) fe = self.flushLoggedErrors(BrokenException) - self.assertEquals(len(fe), 1) + self.assertEqual(len(fe), 1) return renderResource('/foo', notFoundHandler=BadNotFoundHandler()).addCallback(later) diff --git a/nevow/test/test_flatsax.py b/nevow/test/test_flatsax.py index 9c3e19c4..28ce5976 100644 --- a/nevow/test/test_flatsax.py +++ b/nevow/test/test_flatsax.py @@ -31,20 +31,20 @@ def test_tagLocation(self): number at which the tag was seen in that file. """ fName = self.mktemp() - fObj = file(fName, 'w') - fObj.write( - '\n' - ' \n' - ' \n' - ' Hello, world.\n' - ' \n' - ' \n' - ' \n' - ' Hi.\n' - ' \n' - '\n') - fObj.close() - [html] = parse(file(fName)) + with open(fName, 'w') as fObj: + fObj.write( + '\n' + ' \n' + ' \n' + ' Hello, world.\n' + ' \n' + ' \n' + ' \n' + ' Hi.\n' + ' \n' + '\n') + with open(fName) as f: + [html] = parse(f) [head, body] = self._tagChildren(html) [title] = self._tagChildren(head) self.assertEqual(html.filename, fName) @@ -70,13 +70,13 @@ def test_attrLocation(self): number at which the tag was seen in that file. """ fName = self.mktemp() - fObj = file(fName, 'w') - fObj.write( - '\n' - ' \n' - '\n') - fObj.close() - [html] = parse(file(fName)) + with open(fName, 'w') as fObj: + fObj.write( + '\n' + ' \n' + '\n') + with open(fName) as f: + [html] = parse(f) attr = html.attributes['foo'] self.assertEqual(attr.filename, fName) self.assertEqual(attr.lineNumber, 2) @@ -89,13 +89,13 @@ def test_slotLocation(self): C{lineNumber}, and C{columnNumber} attributes as L{Tag} instances do. """ fName = self.mktemp() - fObj = file(fName, 'w') - fObj.write( - '\n' - ' \n' - '') - fObj.close() - [html] = parse(file(fName)) + with open(fName, 'w') as fObj: + fObj.write( + '\n' + ' \n' + '') + with open(fName) as f: + [html] = parse(f) [foo] = [x for x in html.children if isinstance(x, slot)] self.assertEqual(foo.filename, fName) self.assertEqual(foo.lineNumber, 2) @@ -104,38 +104,38 @@ def test_slotLocation(self): def test_parseString(self): xml = '''''' - self.failUnlessEqual(xml, flatten(parseString(xml))) + self.assertEqual(xml, flatten(parseString(xml))) def test_attrs(self): xml = '''

''' - self.failUnlessEqual(xml, flatten(parseString(xml))) + self.assertEqual(xml, flatten(parseString(xml))) def test_xmlns(self): xml = '''''' - self.failUnlessEqual(xml, flatten(parseString(xml))) + self.assertEqual(xml, flatten(parseString(xml))) def test_processingInstruction(self): xml = '''''' - self.failUnlessEqual(xml, flatten(parseString(xml))) + self.assertEqual(xml, flatten(parseString(xml))) def test_doctype(self): xml = ( '\n' '') - self.failUnlessEqual(norm(xml), norm(flatten(parseString(xml)))) + self.assertEqual(norm(xml), norm(flatten(parseString(xml)))) def test_entities(self): xml = """

&

""" - self.failUnlessEqual(xml, flatten(parseString(xml))) + self.assertEqual(xml, flatten(parseString(xml))) def test_cdata(self): xml = '' - self.failUnlessEqual(xml, flatten(parseString(xml))) + self.assertEqual(xml, flatten(parseString(xml))) def test_comment(self): xml = '' - self.failUnlessEqual(xml, flatten(parseString(xml))) + self.assertEqual(xml, flatten(parseString(xml))) def test_commentWhereSpacingMatters(self): """ @@ -150,19 +150,19 @@ def test_commentWhereSpacingMatters(self): """ - self.failUnlessEqual(xml, flatten(parseString(xml))) + self.assertEqual(xml, flatten(parseString(xml))) def test_unicodeComment(self): xml = '' - self.failUnlessEqual(xml, flatten(parseString(xml))) + self.assertEqual(xml, flatten(parseString(xml))) def test_xmlAttr(self): xml = '' - self.failUnlessEqual(xml, flatten(parseString(xml))) + self.assertEqual(xml, flatten(parseString(xml))) def test_badNamespace(self): xml = 'xyz' - self.failUnlessEqual(xml, flatten(parseString(xml))) + self.assertEqual(xml, flatten(parseString(xml))) test_badNamespace.skip = ( 'the standard 2.3 sax parser likes all namespaces to be defined ' 'so this test fails. it does pass with python-xml') @@ -173,7 +173,7 @@ def test_switchns(self): '

in default namespace

' '' 'in foo namespace') - self.failUnlessEqual(xml, flatten(parseString(xml))) + self.assertEqual(xml, flatten(parseString(xml))) def test_otherns(self): xml = ( @@ -181,7 +181,7 @@ def test_otherns(self): 'xmlns:xf="http://www.w3.org/2002/xforms">

' 'in default namespace

' 'in another namespace') - self.failUnlessEqual(xml, flatten(parseString(xml))) + self.assertEqual(xml, flatten(parseString(xml))) def test_invisiblens(self): """ @@ -190,4 +190,4 @@ def test_invisiblens(self): xml = ( '

' '123

') - self.failUnlessEqual('

123

', flatten(parseString(xml))) + self.assertEqual('

123

', flatten(parseString(xml))) diff --git a/nevow/test/test_flatstan.py b/nevow/test/test_flatstan.py index 026d108c..b09e0139 100644 --- a/nevow/test/test_flatstan.py +++ b/nevow/test/test_flatstan.py @@ -3,7 +3,7 @@ from twisted.internet import defer -from zope.interface import implements, Interface +from zope.interface import implementer, Interface from nevow import stan from nevow import context @@ -49,21 +49,21 @@ def render(self, tag, precompile=False, data=None, setupRequest=lambda r: r, set class TestSimpleSerialization(Base): def test_serializeProto(self): - self.assertEquals(self.render(proto), '') + self.assertEqual(self.render(proto), '') def test_serializeTag(self): tag = proto(someAttribute="someValue") - self.assertEquals(self.render(tag), '') + self.assertEqual(self.render(tag), '') def test_serializeChildren(self): tag = proto(someAttribute="someValue")[ proto ] - self.assertEquals(self.render(tag), '') + self.assertEqual(self.render(tag), '') def test_serializeWithData(self): tag = proto(data=5) - self.assertEquals(self.render(tag), '') + self.assertEqual(self.render(tag), '') def test_adaptRenderer(self): ## This is an implementation of the "adapt" renderer @@ -72,19 +72,19 @@ def _(context, data): data ] tag = proto(data=5, render=_) - self.assertEquals(self.render(tag), '5') + self.assertEqual(self.render(tag), '5') def test_serializeDataWithRenderer(self): tag = proto(data=5, render=str) - self.assertEquals(self.render(tag), '5') + self.assertEqual(self.render(tag), '5') def test_noContextRenderer(self): def _(data): return data tag = proto(data=5, render=_) - self.assertEquals(self.render(tag), '5') + self.assertEqual(self.render(tag), '5') tag = proto(data=5, render=lambda data: data) - self.assertEquals(self.render(tag), '5') + self.assertEqual(self.render(tag), '5') def test_aBunchOfChildren(self): tag = proto[ @@ -92,28 +92,28 @@ def test_aBunchOfChildren(self): 5, "A friend in need is a friend indeed" ] - self.assertEquals(self.render(tag), 'A Child5A friend in need is a friend indeed') + self.assertEqual(self.render(tag), 'A Child5A friend in need is a friend indeed') def test_basicPythonTypes(self): tag = proto(data=5)[ "A string; ", - u"A unicode string; ", + "A unicode string; ", 5, " (An integer) ", 1.0, " (A float) ", - 1L, " (A long) ", + 1, " (A long) ", True, " (A bool) ", ["A ", "List; "], stan.xml(" Some xml; "), lambda data: "A function" ] if self.hasBools: - self.assertEquals(self.render(tag), "A string; A unicode string; 5 (An integer) 1.0 (A float) 1 (A long) True (A bool) A List; Some xml; A function") + self.assertEqual(self.render(tag), "A string; A unicode string; 5 (An integer) 1.0 (A float) 1 (A long) True (A bool) A List; Some xml; A function") else: - self.assertEquals(self.render(tag), "A string; A unicode string; 5 (An integer) 1.0 (A float) 1 (A long) 1 (A bool) A List; Some xml; A function") + self.assertEqual(self.render(tag), "A string; A unicode string; 5 (An integer) 1.0 (A float) 1 (A long) 1 (A bool) A List; Some xml; A function") def test_escaping(self): tag = proto(foo="<>&\"'")["<>&\"'"] - self.assertEquals(self.render(tag), '<>&"\'') + self.assertEqual(self.render(tag), '<>&"\'') class TestComplexSerialization(Base): @@ -127,11 +127,11 @@ def test_precompileWithRenderer(self): ] ] prelude, context, postlude = self.render(tag, precompile=True) - self.assertEquals(prelude, "

Here's a string

") - self.assertEquals(context.tag.tagName, "p") - self.assertEquals(context.tag.data, 5) - self.assertEquals(context.tag.render, str) - self.assertEquals(postlude, '
') + self.assertEqual(prelude, "

Here's a string

") + self.assertEqual(context.tag.tagName, "p") + self.assertEqual(context.tag.data, 5) + self.assertEqual(context.tag.render, str) + self.assertEqual(postlude, '
') def test_precompileSlotData(self): """Test that tags with slotData are not precompiled out of the @@ -140,7 +140,7 @@ def test_precompileSlotData(self): tag = tags.p[tags.slot('foo')] tag.fillSlots('foo', 'bar') precompiled = self.render(tag, precompile=True) - self.assertEquals(self.render(precompiled), '

bar

') + self.assertEqual(self.render(precompiled), '

bar

') def test_precompiledSlotLocation(self): @@ -186,7 +186,7 @@ def render_same(context, data): result1 = self.render(doc, precompile=True) result2 = self.render(doc, precompile=True) rendered = self.render(result2) - self.assertEquals(rendered, "

Hello

5

") + self.assertEqual(rendered, "

Hello

5

") def test_precompilePrecompiled(self): def render_same(context, data): @@ -203,7 +203,7 @@ def render_same(context, data): result1 = self.render(doc, precompile=True) result2 = self.render(result1, precompile=True) rendered = self.render(result2) - self.assertEquals(rendered, "

Hello

5

") + self.assertEqual(rendered, "

Hello

5

") def test_precompileDoesntChangeOriginal(self): doc = tags.html(data="foo")[tags.p['foo'], tags.p['foo']] @@ -211,37 +211,37 @@ def test_precompileDoesntChangeOriginal(self): result = self.render(doc, precompile=True) rendered = self.render(result) - self.assertEquals(len(doc.children), 2) - self.assertEquals(rendered, "

foo

foo

") + self.assertEqual(len(doc.children), 2) + self.assertEqual(rendered, "

foo

foo

") def test_precompileNestedDynamics(self): tag = self.makeComplex() prelude, dynamic, postlude = self.render(tag, precompile=True) - self.assertEquals(prelude, '') + self.assertEqual(prelude, '') - self.assertEquals(dynamic.tag.tagName, 'table') - self.failUnless(dynamic.tag.children) - self.assertEquals(dynamic.tag.data, 5) + self.assertEqual(dynamic.tag.tagName, 'table') + self.assertTrue(dynamic.tag.children) + self.assertEqual(dynamic.tag.data, 5) childPrelude, childDynamic, childPostlude = dynamic.tag.children - self.assertEquals(childPrelude, '') - self.assertEquals(childDynamic.tag.tagName, 'span') - self.assertEquals(childDynamic.tag.render, str) - self.assertEquals(childPostlude, '') + self.assertEqual(childPrelude, '') + self.assertEqual(childDynamic.tag.tagName, 'span') + self.assertEqual(childDynamic.tag.render, str) + self.assertEqual(childPostlude, '') - self.assertEquals(postlude, '') + self.assertEqual(postlude, '') def test_precompileThenRender(self): tag = self.makeComplex() prerendered = self.render(tag, precompile=True) - self.assertEquals(self.render(prerendered), '
5
') + self.assertEqual(self.render(prerendered), '
5
') def test_precompileThenMultipleRenders(self): tag = self.makeComplex() prerendered = self.render(tag, precompile=True) - self.assertEquals(self.render(prerendered), '
5
') - self.assertEquals(self.render(prerendered), '
5
') + self.assertEqual(self.render(prerendered), '
5
') + self.assertEqual(self.render(prerendered), '
5
') def test_patterns(self): tag = tags.html[ @@ -253,12 +253,12 @@ def test_patterns(self): ] ] ] - self.assertEquals(self.render(tag), "
  1. one
  2. two
  3. three
") + self.assertEqual(self.render(tag), "
  1. one
  2. two
  3. three
") def test_precompilePatternWithNoChildren(self): tag = tags.img(pattern='item') pc = flat.precompile(tag) - self.assertEquals(pc[0].tag.children, []) + self.assertEqual(pc[0].tag.children, []) def test_slots(self): tag = tags.html[ @@ -272,7 +272,7 @@ def test_slots(self): ] ] ] - self.assertEquals(self.render(tag), "
Header one.Header two.
One: 1Two: 2
") + self.assertEqual(self.render(tag), "
Header one.Header two.
One: 1Two: 2
") def test_slotAttributeEscapingWhenPrecompiled(self): @@ -291,7 +291,7 @@ def render_searchResults(ctx, remoteCursor): # this test passes if the precompile test is skipped. precompiled = self.render(tag, precompile=True) - self.assertEquals(self.render(precompiled), '') + self.assertEqual(self.render(precompiled), '') def test_nestedpatterns(self): @@ -309,7 +309,7 @@ def data_header(context, data): return ['col1', 'col2', 'col3'] ] ] ] - self.assertEquals(self.render(tag), "
col1col2col3
123
456
") + self.assertEqual(self.render(tag), "
col1col2col3
123
456
") def test_cloning(self): def data_foo(context, data): return [{'foo':'one'}, {'foo':'two'}] @@ -334,37 +334,38 @@ def render_test(context, data): ] ] document=self.render(document, precompile=True) - self.assertEquals(self.render(document), '
  • fooone
  • footwo
') + self.assertEqual(self.render(document), '
  • fooone
  • footwo
') def test_singletons(self): for x in ('img', 'br', 'hr', 'base', 'meta', 'link', 'param', 'area', 'input', 'col', 'basefont', 'isindex', 'frame'): - self.assertEquals(self.render(tags.Proto(x)()), '<%s />' % x) + self.assertEqual(self.render(tags.Proto(x)()), '<%s />' % x) def test_nosingleton(self): for x in ('div', 'span', 'script', 'iframe'): - self.assertEquals(self.render(tags.Proto(x)()), '<%(tag)s>' % {'tag': x}) + self.assertEqual(self.render(tags.Proto(x)()), '<%(tag)s>' % {'tag': x}) def test_nested_data(self): def checkContext(ctx, data): - self.assertEquals(data, "inner") - self.assertEquals(ctx.locate(inevow.IData, depth=2), "outer") + self.assertEqual(data, "inner") + self.assertEqual(ctx.locate(inevow.IData, depth=2), "outer") return 'Hi' tag = tags.html(data="outer")[tags.span(render=lambda ctx,data: ctx.tag, data="inner")[checkContext]] - self.assertEquals(self.render(tag), "Hi") + self.assertEqual(self.render(tag), "Hi") def test_nested_remember(self): class IFoo(Interface): pass + @implementer(IFoo) class Foo(str): - implements(IFoo) + pass def checkContext(ctx, data): - self.assertEquals(ctx.locate(IFoo), Foo("inner")) - self.assertEquals(ctx.locate(IFoo, depth=2), Foo("outer")) + self.assertEqual(ctx.locate(IFoo), Foo("inner")) + self.assertEqual(ctx.locate(IFoo, depth=2), Foo("outer")) return 'Hi' tag = tags.html(remember=Foo("outer"))[tags.span(render=lambda ctx,data: ctx.tag, remember=Foo("inner"))[checkContext]] - self.assertEquals(self.render(tag), "Hi") + self.assertEqual(self.render(tag), "Hi") def test_deferredRememberInRenderer(self): class IFoo(Interface): @@ -376,7 +377,7 @@ def locateIt(ctx, data): return IFoo(ctx) tag = tags.invisible(render=rememberIt)[tags.invisible(render=locateIt)] self.render(tag, wantDeferred=True).addCallback( - lambda result: self.assertEquals(result, "bar")) + lambda result: self.assertEqual(result, "bar")) def test_deferredFromNestedFunc(self): def outer(ctx, data): @@ -384,14 +385,14 @@ def inner(ctx, data): return defer.succeed(tags.p['Hello']) return inner self.render(tags.invisible(render=outer), wantDeferred=True).addCallback( - lambda result: self.assertEquals(result, '

Hello

')) + lambda result: self.assertEqual(result, '

Hello

')) def test_dataContextCreation(self): data = {'foo':'oof', 'bar':'rab'} doc = tags.p(data=data)[tags.slot('foo'), tags.slot('bar')] doc.fillSlots('foo', tags.invisible(data=tags.directive('foo'), render=str)) doc.fillSlots('bar', lambda ctx,data: data['bar']) - self.assertEquals(flat.flatten(doc), '

oofrab

') + self.assertEqual(flat.flatten(doc), '

oofrab

') def test_leaky(self): def foo(ctx, data): @@ -403,7 +404,7 @@ def foo(ctx, data): tags.slot("bar"), tags.invisible(render=str)]) - self.assertEquals(result, '
one
') + self.assertEqual(result, '
one
') class TestMultipleRenderWithDirective(Base): @@ -433,37 +434,37 @@ def count(self, context, data): class TestEntity(Base): def test_it(self): val = self.render(entities.nbsp) - self.assertEquals(val, ' ') + self.assertEqual(val, ' ') def test_nested(self): val = self.render(tags.html(src=entities.quot)[entities.amp]) - self.assertEquals(val, '&') + self.assertEqual(val, '&') def test_xml(self): val = self.render([entities.lt, entities.amp, entities.gt]) - self.assertEquals(val, '<&>') + self.assertEqual(val, '<&>') class TestNoneAttribute(Base): def test_simple(self): val = self.render(tags.html(foo=None)["Bar"]) - self.assertEquals(val, "Bar") + self.assertEqual(val, "Bar") def test_slot(self): val = self.render(tags.html().fillSlots('bar', None)(foo=tags.slot('bar'))["Bar"]) - self.assertEquals(val, "Bar") + self.assertEqual(val, "Bar") test_slot.skip = "Attribute name flattening must happen later for this to work" def test_deepSlot(self): val = self.render(tags.html().fillSlots('bar', lambda c,d: None)(foo=tags.slot('bar'))["Bar"]) - self.assertEquals(val, "Bar") + self.assertEqual(val, "Bar") test_deepSlot.skip = "Attribute name flattening must happen later for this to work" def test_deferredSlot(self): self.render(tags.html().fillSlots('bar', defer.succeed(None))(foo=tags.slot('bar'))["Bar"], wantDeferred=True).addCallback( - lambda val: self.assertEquals(val, "Bar")) + lambda val: self.assertEqual(val, "Bar")) test_deferredSlot.skip = "Attribute name flattening must happen later for this to work" @@ -478,7 +479,7 @@ def appendKey(ctx, data): tags.div(key="two", render=appendKey)[ tags.div(render=appendKey)[ tags.div(key="four", render=appendKey)]]]) - self.assertEquals(val, ["one", "one.two", "one.two", "one.two.four"]) + self.assertEqual(val, ["one", "one.two", "one.two", "one.two.four"]) @@ -507,7 +508,7 @@ def gen(ctx, data): # The actual test notquiteglobals = {} def finished(spam): - print 'FINISHED' + print('FINISHED') def error(failure): notquiteglobals['exception'] = failure.value def checker(result): diff --git a/nevow/test/test_flatten.py b/nevow/test/test_flatten.py index 1d270fd9..2eac6f82 100644 --- a/nevow/test/test_flatten.py +++ b/nevow/test/test_flatten.py @@ -9,25 +9,25 @@ class TestSerialization(TestCase): def test_someTypes(self): - self.assertEquals(ten.flatten(1), '1') - self.assertEquals(ten.flatten([1,2,3]), '123') + self.assertEqual(ten.flatten(1), '1') + self.assertEqual(ten.flatten([1,2,3]), '123') def test_nestedTags(self): - self.assertEquals( + self.assertEqual( ten.flatten( tags.html(hi='there')[ tags.body[ 42 ]]), '42') def test_dynamic(self): - self.assertEquals( + self.assertEqual( ten.flatten( tags.html[ tags.body(render=lambda c, d: 'body!')]), 'body!') def test_reallyDynamic(self): - self.assertEquals( + self.assertEqual( ten.flatten( tags.html[ lambda c, d: tags.body[ @@ -35,24 +35,24 @@ def test_reallyDynamic(self): 'stuff') def test_serializeString(self): - self.assertEquals(ten.flatten('one'), 'one') - self.assertEquals(type(ten.flatten('<>')), tags.raw) - self.assertEquals(ten.flatten('123'), '<abc&&>123') - self.assertEquals(ten.flatten(tags.xml('<>&')), '<>&') - self.assertEquals(ten.flatten(tags.xml(u'\xc2\xa3')), '\xc3\x82\xc2\xa3') + self.assertEqual(ten.flatten('one'), 'one') + self.assertEqual(type(ten.flatten('<>')), tags.raw) + self.assertEqual(ten.flatten('123'), '<abc&&>123') + self.assertEqual(ten.flatten(tags.xml('<>&')), '<>&') + self.assertEqual(ten.flatten(tags.xml('\xc2\xa3')), '\xc2\xa3') def test_flattenTwice(self): """Test that flattening a string twice does not encode it twice. """ - self.assertEquals(ten.flatten(ten.flatten('&')), '&') + self.assertEqual(ten.flatten(ten.flatten('&')), '&') class TestPrecompile(TestCase): def test_simple(self): - self.assertEquals(ten.precompile(1), ['1']) + self.assertEqual(ten.precompile(1), ['1']) def test_complex(self): - self.assertEquals(ten.precompile( + self.assertEqual(ten.precompile( tags.html[ tags.head[ tags.title["Hi"]], @@ -66,10 +66,10 @@ def test_dynamic(self): tags.html[ render]) prelude, dynamic, postlude = result - self.assertEquals(prelude, '') - self.assertEquals(dynamic.tag.render, render) - self.assertEquals(postlude, '') - self.assertEquals(ten.flatten(result), 'one') + self.assertEqual(prelude, '') + self.assertEqual(dynamic.tag.render, render) + self.assertEqual(postlude, '') + self.assertEqual(ten.flatten(result), 'one') def test_tagWithRender(self): render = lambda c, d: 'body' @@ -77,10 +77,10 @@ def test_tagWithRender(self): tags.html[ tags.body(render=render)]) prelude, dynamic, postlude = result - self.assertEquals(prelude, '') - self.assertEquals(dynamic.tag.render, render) - self.assertEquals(postlude, '') - self.assertEquals(ten.flatten(result), 'body') + self.assertEqual(prelude, '') + self.assertEqual(dynamic.tag.render, render) + self.assertEqual(postlude, '') + self.assertEqual(ten.flatten(result), 'body') import unicodedata @@ -90,10 +90,10 @@ def test_tagWithRender(self): class TestUnicode(TestCase): def test_it(self): - self.assertEquals(ten.flatten(u), u.encode('utf8')) + self.assertEqual(ten.flatten(u).encode('utf-8'), u.encode('utf8')) def test_unescaped(self): - self.assertEquals(ten.flatten(tags.xml(u'<<<%s>>>' % u)), (u'<<<%s>>>' % u).encode('utf8')) + self.assertEqual(ten.flatten(tags.xml('<<<%s>>>' % u)).encode('utf-8'), ('<<<%s>>>' % u).encode('utf8')) class Registration(TestCase): def testBadRegister(self): diff --git a/nevow/test/test_guard.py b/nevow/test/test_guard.py index e5483410..6ff01a4a 100644 --- a/nevow/test/test_guard.py +++ b/nevow/test/test_guard.py @@ -7,7 +7,7 @@ import gc -from zope.interface import implements +from zope.interface import implementer from twisted.cred.checkers import InMemoryUsernamePasswordDatabaseDontUse, AllowAnonymousAccess, ANONYMOUS from twisted.cred.portal import Portal, IRealm @@ -21,6 +21,7 @@ from nevow import guard from nevow import context from nevow import appserver +from nevow import util class FakeHTTPChannel: @@ -78,7 +79,7 @@ def makeFakeRequest(self, path, username='',password='', req.user = username req.password = password req.received_cookies.update(self.received_cookies) - req.requestReceived("GET", path, "HTTP/1.0") + req.requestReceived(b"GET", util.toBytes(path), b"HTTP/1.0") return req @@ -87,10 +88,10 @@ def __init__(self, *args, **kw): appserver.NevowRequest.__init__(self, *args, **kw) self._pchn = self.channel self._cookieCache = {} - from cStringIO import StringIO - self.content = StringIO() + from io import BytesIO + self.content = BytesIO() self.requestHeaders.setRawHeaders(b'host', [b'fake.com']) - self.written = StringIO() + self.written = BytesIO() def followRedirect(self): [L] = self.responseHeaders.getRawHeaders('location') @@ -120,7 +121,7 @@ def write(self, data): def addCookie(self, k, v, *args,**kw): appserver.NevowRequest.addCookie(self,k,v,*args,**kw) - assert not self._cookieCache.has_key(k), "Should not be setting duplicate cookies!" + assert k not in self._cookieCache, "Should not be setting duplicate cookies!" self._cookieCache[k] = (v, args, kw) self.channel.received_cookies[k] = v @@ -186,8 +187,8 @@ def renderHTTP(self, ctx): return 'No' +@implementer(IRealm) class SillyRealm: - implements(IRealm) def __init__(self, anonymousAvatarFactory=SillyAnonymous, authenticatedAvatarFactory=SillyAvatar): @@ -214,7 +215,7 @@ class GuardTestSuper(TestCase): sessions = {} def tearDown(self): - for sz in self.sessions.values(): + for sz in list(self.sessions.values()): sz.expire() def createPortal(self, realmFactory=None): @@ -240,7 +241,7 @@ def getGuard(channel): resource = channel.site.resource while isinstance(resource, ParentPage): assert len(resource.children) == 1 - resource = resource.children.values()[0] + resource = list(resource.children.values())[0] return resource @@ -257,10 +258,10 @@ def renderHTTP(self, ctx): class GetLoggedInAnonymous(rend.Page): def child_(self, ctx): return self def renderHTTP(self, ctx): - raise RuntimeError, "We weren't supposed to get here." + raise RuntimeError("We weren't supposed to get here.") +@implementer(IRealm) class GetLoggedInRealm: - implements(IRealm) def requestAvatar(self, avatarId, mind, *interfaces): if avatarId == ANONYMOUS: @@ -291,9 +292,9 @@ def getGuardPath(self): otherwise guaranteed to start with a slash and end with a non-slash. """ if not self.guardPath: - return '' + return b'' else: - return '/' + '/'.join(self.guardPath) + return b'/' + b'/'.join([util.toBytes(s) for s in self.guardPath]) def test_httpAuthInit(self): """ @@ -309,9 +310,9 @@ def test_httpAuthInit(self): # Make the request three times. The same resource should come back # each time, and there should only ever be one session. for x in range(3): - req = chan.makeFakeRequest('%s/' % self.getGuardPath(), "test", "test") - self.assertEquals(req.written.getvalue(), "Yes") - self.assertEquals(len(self.sessions), 1) + req = chan.makeFakeRequest(b'%s/' % self.getGuardPath(), "test", "test") + self.assertEqual(req.written.getvalue(), b"Yes") + self.assertEqual(len(self.sessions), 1) def test_sessionInit(self): @@ -328,29 +329,31 @@ def test_sessionInit(self): # The first thing that happens when we attempt to browse with no session # is a cookie being set and a redirect being issued to the session url - req = chan.makeFakeRequest('%s/xxx/yyy/' % self.getGuardPath()) - self.assertEquals( len(req._cookieCache.values()), 1, "Bad number of cookies in response.") + req = chan.makeFakeRequest(b'%s/xxx/yyy/' % self.getGuardPath()) + self.assertEqual( len(list(req._cookieCache.values())), 1, "Bad number of cookies in response.") # The redirect is set immediately and should have a path segment at the beginning matching our cookie - self.failUnless(req.responseHeaders.hasHeader('location')) - cookie = req._cookieCache.values()[0][0] + self.assertTrue(req.responseHeaders.hasHeader('location')) + cookie = list(req._cookieCache.values())[0][0] # The URL should have the cookie segment in it and the correct path segments at the end - self.assertEquals(req.responseHeaders.getRawHeaders('location')[0], - 'http://fake.com%s/%s/xxx/yyy/' % (self.getGuardPath(), guard.SESSION_KEY+cookie, )) + self.assertEqual(req.responseHeaders.getRawHeaders('location')[0], + 'http://fake.com%s/%s/xxx/yyy/' % ( + util.toString(self.getGuardPath()), + guard.SESSION_KEY+cookie)) # Now, let's follow the redirect req = req.followRedirect() # Our session should now be set up and we will be redirected to our final destination - self.assertEquals( + self.assertEqual( req.responseHeaders.getRawHeaders('location')[0].split('?')[0], - 'http://fake.com%s/xxx/yyy/' % self.getGuardPath()) + 'http://fake.com%s/xxx/yyy/' % util.toString(self.getGuardPath())) # Let's follow the redirect to the final page req = req.followRedirect() - self.failIf(req.responseHeaders.hasHeader('location')) + self.assertFalse(req.responseHeaders.hasHeader('location')) # We should have the final resource, which is an anonymous resource - self.assertEquals(req.written.getvalue(), "No") + self.assertEqual(req.written.getvalue(), b"No") def test_sessionInit_noCookies(self): @@ -368,25 +371,27 @@ def test_sessionInit_noCookies(self): # The first thing that happens when we attempt to browse with no session # is a cookie being set and a redirect being issued to the session url - req = chan.makeFakeRequest('%s/xxx/yyy/' % self.getGuardPath(), requestClass=FakeHTTPRequest_noCookies) + req = chan.makeFakeRequest(b'%s/xxx/yyy/' % self.getGuardPath(), requestClass=FakeHTTPRequest_noCookies) # The redirect is set immediately and should have a path segment at the beginning matching our session id - self.failUnless(req.responseHeaders.hasHeader('location')) + self.assertTrue(req.responseHeaders.hasHeader('location')) # The URL should have the session id segment in it and the correct path segments at the end [location] = req.responseHeaders.getRawHeaders('location') - prefix = 'http://fake.com%s/%s' % (self.getGuardPath(), guard.SESSION_KEY) - suffix = '/xxx/yyy/' - self.failUnless(location.startswith(prefix)) - self.failUnless(location.endswith(suffix)) + location = location.encode("ascii") + prefix = b'http://fake.com%s/%s' % (self.getGuardPath(), util.toBytes(guard.SESSION_KEY)) + suffix = b'/xxx/yyy/' + self.assertTrue(location.startswith(prefix)) + self.assertTrue(location.endswith(suffix)) for c in location[len(prefix):-len(suffix)]: - self.failUnless(c in '0123456789abcdef') + self.assertTrue(c in b'0123456789abcdef', "Bad cookie char %s"%c) # Now, let's follow the redirect req = req.followRedirect() - self.failIf(req.responseHeaders.hasHeader('location')) + self.assertFalse(req.responseHeaders.hasHeader('location'), + "Too many redirects") # We should have the final resource, which is an anonymous resource - self.assertEquals(req.written.getvalue(), "No") + self.assertEqual(req.written.getvalue(), b"No") def testUsernamePassword(self): @@ -395,19 +400,19 @@ def testUsernamePassword(self): chan = self.createGuard(p) # Check the anonymous page - req = chan.makeFakeRequest('%s/' % self.getGuardPath()).followAllRedirects() - self.assertEquals(req.written.getvalue(), "No") + req = chan.makeFakeRequest(b'%s/' % self.getGuardPath()).followAllRedirects() + self.assertEqual(req.written.getvalue(), b"No") # Check the logged in page - req = chan.makeFakeRequest('%s/__login__/?username=test&password=test' % self.getGuardPath()).followAllRedirects() - self.assertEquals(req.written.getvalue(), "Yes") + req = chan.makeFakeRequest(b'%s/__login__/?username=test&password=test' % self.getGuardPath()).followAllRedirects() + self.assertEqual(req.written.getvalue(), b"Yes") # Log out - chan.makeFakeRequest("%s/__logout__" % self.getGuardPath()).followRedirect() + chan.makeFakeRequest(b"%s/__logout__" % self.getGuardPath()).followRedirect() # Get the anonymous page again - k = chan.makeFakeRequest("%s/" % self.getGuardPath()) - self.assertEquals(k.written.getvalue(), "No") + k = chan.makeFakeRequest(b"%s/" % self.getGuardPath()) + self.assertEqual(k.written.getvalue(), b"No") def testLoginWithNoSession(self): @@ -415,8 +420,8 @@ def testLoginWithNoSession(self): p.registerChecker(InMemoryUsernamePasswordDatabaseDontUse(test='test'), IUsernamePassword) chan = self.createGuard(p) - req = chan.makeFakeRequest('%s/__login__/?username=test&password=test' % self.getGuardPath()).followAllRedirects() - self.assertEquals(req.written.getvalue(), "Yes") + req = chan.makeFakeRequest(b'%s/__login__/?username=test&password=test' % self.getGuardPath()).followAllRedirects() + self.assertEqual(req.written.getvalue(), b"Yes") def test_sessionNegotiationSavesRequestParameters(self): @@ -433,14 +438,15 @@ def test_sessionNegotiationSavesRequestParameters(self): channel = self.createGuard(portal) request = channel.makeFakeRequest( - '%s/?foo=1&bar=2' % self.getGuardPath()).followAllRedirects() - self.assertEquals(request.written.getvalue(), '') + b'%s/?foo=1&bar=2' % self.getGuardPath()).followAllRedirects() + self.assertEqual(request.written.getvalue(), b'') self.assertEqual( - renders, [({'foo': ['1'], 'bar': ['2']}, - None, - None, - 'GET', - Headers({'host': ['fake.com']}))]) + renders, + [({b'bar': [b'2'], b'foo': [b'1']}, + None, + None, + b'GET', + Headers({b'host': [b'fake.com']}))]) def test_loginRestoresRequestParameters(self): @@ -473,10 +479,10 @@ def test_loginRestoresRequestParameters(self): # Perform the login. request = channel.makeFakeRequest( - self.getGuardPath() + '/__login__?username=test&password=test') + self.getGuardPath() + b'/__login__?username=test&password=test') request = request.followAllRedirects() - self.assertEquals(request.written.getvalue(), '') + self.assertEqual(request.written.getvalue(), b'') self.assertEqual( renders, [({'foo': ['1'], 'bar': ['2']}, None, @@ -501,21 +507,21 @@ def test_oldRequestParametersIgnored(self): # Negotiate a session using a request with some parameters. request = channel.makeFakeRequest( - self.getGuardPath() + "?foo=bar&bar=baz") + self.getGuardPath() + b"?foo=bar&bar=baz") request = request.followAllRedirects() # Perform the login. request = channel.makeFakeRequest( - self.getGuardPath() + '/__login__?username=test&password=test') + self.getGuardPath() + b'/__login__?username=test&password=test') request = request.followAllRedirects() - self.assertEquals(request.written.getvalue(), '') + self.assertEqual(request.written.getvalue(), b'') self.assertEqual( - renders, [({'username': ['test'], 'password': ['test']}, + renders, [({b'username': [b'test'], b'password': [b'test']}, None, - '', - 'GET', - Headers({'host': ['fake.com']}))]) + b'', + b'GET', + Headers({b'host': [b'fake.com']}))]) def testNoSlash(self): @@ -523,34 +529,36 @@ def testNoSlash(self): p = self.createPortal() chan = self.createGuard(p) - req = chan.makeFakeRequest('%s/' % self.getGuardPath(), requestClass=FakeHTTPRequest_noCookies).followAllRedirects() + req = chan.makeFakeRequest(b'%s/' % self.getGuardPath(), requestClass=FakeHTTPRequest_noCookies).followAllRedirects() # We should have the final resource, which is an anonymous resource - self.assertEquals(req.written.getvalue(), "No") + self.assertEqual(req.written.getvalue(), b"No") # now try requesting just the guard path - self.failUnless(req.path.startswith('%s/%s' % (self.getGuardPath(), guard.SESSION_KEY))) - self.failUnless(req.path.endswith('/')) + self.assertTrue(req.path.startswith(b'%s/%s' % (self.getGuardPath(), util.toBytes(guard.SESSION_KEY)))) + self.assertTrue(req.path.endswith(b'/')) req = chan.makeFakeRequest(req.path[:-1], requestClass=FakeHTTPRequest_noCookies).followAllRedirects() # it should work just as well as with the slash # (not actually the same page, but SillyPage always says the same thing here) - self.assertEquals(req.written.getvalue(), "No") + self.assertEqual(req.written.getvalue(), b"No") def testTrailingSlashMatters_noCookies(self): class TrailingSlashPage(rend.Page): def locateChild(self, context, segments): - return self.__class__('%s/%s' % (self.original, segments[0])), segments[1:] + return self.__class__('%s/%s' % ( + util.toString(self.original) + , segments[0])), segments[1:] class TrailingSlashAvatar(TrailingSlashPage): def renderHTTP(self, context): - return 'Authenticated %s' % self.original + return 'Authenticated %s' % util.toString(self.original) class TrailingSlashAnonymous(TrailingSlashPage): def renderHTTP(self, ctx): - return 'Anonymous %s' % self.original + return 'Anonymous %s' % util.toString(self.original) + @implementer(IRealm) class TrailingSlashRealm: - implements(IRealm) def __init__(self, path): self.path = path @@ -564,17 +572,17 @@ def requestAvatar(self, avatarId, mind, *interfaces): p = self.createPortal(realmFactory=lambda : TrailingSlashRealm(self.getGuardPath())) chan = self.createGuard(p) - req = chan.makeFakeRequest('%s/' % self.getGuardPath(), requestClass=FakeHTTPRequest_noCookies).followAllRedirects() + req = chan.makeFakeRequest(b'%s/' % self.getGuardPath(), requestClass=FakeHTTPRequest_noCookies).followAllRedirects() # We should have the final resource, which is an anonymous resource - self.assertEquals(req.written.getvalue(), "Anonymous %s/" % self.getGuardPath()) + self.assertEqual(req.written.getvalue(), b"Anonymous %b/" % self.getGuardPath()) # now try requesting just the guard path - self.failUnless(req.path.startswith('%s/%s' % (self.getGuardPath(), guard.SESSION_KEY))) - self.failUnless(req.path.endswith('/')) + self.assertTrue(req.path.startswith(b'%s/%s' % (self.getGuardPath(), util.toBytes(guard.SESSION_KEY)))) + self.assertTrue(req.path.endswith(b'/')) req = chan.makeFakeRequest(req.path[:-1], requestClass=FakeHTTPRequest_noCookies).followAllRedirects() # it should no longer have the trailing slash - self.assertEquals(req.written.getvalue(), "Anonymous %s" % self.getGuardPath()) + self.assertEqual(req.written.getvalue(), b"Anonymous %b" % self.getGuardPath()) def testTrailingSlashMatters_withCookies(self): # omitting the trailing slash when not using session keys can @@ -584,7 +592,8 @@ def testTrailingSlashMatters_withCookies(self): class TrailingSlashPage(rend.Page): def locateChild(self, context, segments): - return self.__class__('%s/%s' % (self.original, segments[0])), segments[1:] + return self.__class__('%s/%s' % ( + util.toString(self.original), segments[0])), segments[1:] class TrailingSlashAvatar(TrailingSlashPage): def renderHTTP(self, context): @@ -592,10 +601,10 @@ def renderHTTP(self, context): class TrailingSlashAnonymous(TrailingSlashPage): def renderHTTP(self, ctx): - return 'Anonymous %s' % self.original + return 'Anonymous %s' % util.toString(self.original) + @implementer(IRealm) class TrailingSlashRealm: - implements(IRealm) def __init__(self, path): self.path = path @@ -609,23 +618,23 @@ def requestAvatar(self, avatarId, mind, *interfaces): p = self.createPortal(realmFactory=lambda : TrailingSlashRealm(self.getGuardPath())) chan = self.createGuard(p) - req = chan.makeFakeRequest('%s/' % self.getGuardPath()).followAllRedirects() + req = chan.makeFakeRequest(b'%b/' % self.getGuardPath()).followAllRedirects() # We should have the final resource, which is an anonymous resource - self.assertEquals(req.written.getvalue(), "Anonymous %s/" % self.getGuardPath()) + self.assertEqual(req.written.getvalue(), b"Anonymous %b/" % self.getGuardPath()) - req = chan.makeFakeRequest('%s' % self.getGuardPath()).followAllRedirects() + req = chan.makeFakeRequest(b'%s' % self.getGuardPath()).followAllRedirects() # We should have the final resource, which is an anonymous resource - self.assertEquals(req.written.getvalue(), "Anonymous %s" % self.getGuardPath()) + self.assertEqual(req.written.getvalue(), b"Anonymous %b" % self.getGuardPath()) def testPlainTextCookie(self): """Cookies from non-SSL sites have no secure attribute.""" p = self.createPortal() chan = self.createGuard(p) - req = chan.makeFakeRequest('%s/xxx/yyy/' % self.getGuardPath()) - self.assertEquals( len(req._cookieCache.values()), 1, "Bad number of cookies in response.") - cookie, a, kw = req._cookieCache.values()[0] + req = chan.makeFakeRequest(b'%s/xxx/yyy/' % self.getGuardPath()) + self.assertEqual( len(list(req._cookieCache.values())), 1, "Bad number of cookies in response.") + cookie, a, kw = list(req._cookieCache.values())[0] secure = kw.get('secure', None) - self.failIf(secure) + self.assertFalse(secure) def testPlainTextCookie_evenWithSecureCookies(self): """Cookies from non-SSL sites have no secure attribute, even if secureCookie is true.""" @@ -633,22 +642,22 @@ def testPlainTextCookie_evenWithSecureCookies(self): chan = self.createGuard(p) gu = getGuard(chan) gu.secureCookies = False - req = chan.makeFakeRequest('%s/xxx/yyy/' % self.getGuardPath()) - self.assertEquals( len(req._cookieCache.values()), 1, "Bad number of cookies in response.") - cookie, a, kw = req._cookieCache.values()[0] + req = chan.makeFakeRequest(b'%s/xxx/yyy/' % self.getGuardPath()) + self.assertEqual( len(list(req._cookieCache.values())), 1, "Bad number of cookies in response.") + cookie, a, kw = list(req._cookieCache.values())[0] secure = kw.get('secure', None) - self.failIf(secure) + self.assertFalse(secure) def testSecureCookie_secureCookies(self): """Cookies from SSL sites have secure=True.""" p = self.createPortal() chan = self.createGuard(p) - req = chan.makeFakeRequest('%s/xxx/yyy/' % self.getGuardPath(), + req = chan.makeFakeRequest(b'%s/xxx/yyy/' % self.getGuardPath(), requestClass=FakeHTTPRequest_forceSSL) - self.assertEquals( len(req._cookieCache.values()), 1, "Bad number of cookies in response.") - cookie, a, kw = req._cookieCache.values()[0] + self.assertEqual( len(list(req._cookieCache.values())), 1, "Bad number of cookies in response.") + cookie, a, kw = list(req._cookieCache.values())[0] secure = kw.get('secure', None) - self.failUnless(secure) + self.assertTrue(secure) def testSecureCookie_noSecureCookies(self): """Cookies from SSL sites do not have secure=True if secureCookies is false.""" @@ -656,12 +665,12 @@ def testSecureCookie_noSecureCookies(self): chan = self.createGuard(p) gu = getGuard(chan) gu.secureCookies = False - req = chan.makeFakeRequest('%s/xxx/yyy/' % self.getGuardPath(), + req = chan.makeFakeRequest(b'%s/xxx/yyy/' % self.getGuardPath(), requestClass=FakeHTTPRequest_forceSSL) - self.assertEquals( len(req._cookieCache.values()), 1, "Bad number of cookies in response.") - cookie, a, kw = req._cookieCache.values()[0] + self.assertEqual( len(list(req._cookieCache.values())), 1, "Bad number of cookies in response.") + cookie, a, kw = list(req._cookieCache.values())[0] secure = kw.get('secure', None) - self.failIf(secure) + self.assertFalse(secure) def testPersistentCookie_persistentCookies(self): """Cookies from sites are saved to disk because SessionWrapper.persistentCookies=True.""" @@ -669,10 +678,10 @@ def testPersistentCookie_persistentCookies(self): chan = self.createGuard(p) gu = getGuard(chan) gu.persistentCookies = True - req = chan.makeFakeRequest('%s/xxx/yyy/' % self.getGuardPath(), + req = chan.makeFakeRequest(b'%s/xxx/yyy/' % self.getGuardPath(), requestClass=FakeHTTPRequest) - self.assertEquals( len(req._cookieCache.values()), 1, "Bad number of cookies in response.") - cookie, a, kw = req._cookieCache.values()[0] + self.assertEqual( len(list(req._cookieCache.values())), 1, "Bad number of cookies in response.") + cookie, a, kw = list(req._cookieCache.values())[0] expires = kw.get('expires', None) self.failIfIdentical(expires, None) @@ -680,10 +689,10 @@ def testPersistentCookie_noPersistentCookies(self): """Cookies from sites are not saved to disk because SessionWrapper.persistentCookies=False.""" p = self.createPortal() chan = self.createGuard(p) - req = chan.makeFakeRequest('%s/xxx/yyy/' % self.getGuardPath(), + req = chan.makeFakeRequest(b'%s/xxx/yyy/' % self.getGuardPath(), requestClass=FakeHTTPRequest) - self.assertEquals( len(req._cookieCache.values()), 1, "Bad number of cookies in response.") - cookie, a, kw = req._cookieCache.values()[0] + self.assertEqual( len(list(req._cookieCache.values())), 1, "Bad number of cookies in response.") + cookie, a, kw = list(req._cookieCache.values())[0] expires = kw.get('expires', None) self.failUnlessIdentical(expires, None) @@ -693,14 +702,14 @@ def testCookiePath(self): """Cookies get the correct path setting sites have no secure attribute.""" p = self.createPortal() chan = self.createGuard(p) - req = chan.makeFakeRequest('%s/xxx/yyy/' % self.getGuardPath()) - self.assertEquals( len(req._cookieCache.values()), 1, "Bad number of cookies in response.") - cookie, a, kw = req._cookieCache.values()[0] + req = chan.makeFakeRequest(b'%s/xxx/yyy/' % self.getGuardPath()) + self.assertEqual( len(list(req._cookieCache.values())), 1, "Bad number of cookies in response.") + cookie, a, kw = list(req._cookieCache.values())[0] path = kw.get('path', None) wanted = self.getGuardPath() - if wanted == '': - wanted = '/' - self.failUnlessEqual(path, wanted) + if wanted == b'': + wanted = b'/' + self.assertEqual(path, wanted) def test_defaultCookieDomain(self): @@ -709,8 +718,8 @@ def test_defaultCookieDomain(self): """ portal = self.createPortal() channel = self.createGuard(portal) - request = channel.makeFakeRequest('%s/abc' % (self.getGuardPath(),)) - cookie, args, kwargs = request._cookieCache.values()[0] + request = channel.makeFakeRequest(b'%s/abc' % (self.getGuardPath(),)) + cookie, args, kwargs = list(request._cookieCache.values())[0] self.assertEqual(kwargs['domain'], None) @@ -731,8 +740,8 @@ def cookieDomainForRequest(self, request): self.wrapperFactory = SpecialSessionWrapper channel = self.createGuard(portal) - request = channel.makeFakeRequest('%s/abc' % (self.getGuardPath(),)) - cookie, args, kwargs = request._cookieCache.values()[0] + request = channel.makeFakeRequest(b'%s/abc' % (self.getGuardPath(),)) + cookie, args, kwargs = list(request._cookieCache.values())[0] self.assertEqual(kwargs['domain'], 'example.com') self.assertEqual(requests, [request]) @@ -742,52 +751,52 @@ def testLoginExtraPath(self): p.registerChecker(InMemoryUsernamePasswordDatabaseDontUse(test='test'), IUsernamePassword) chan = self.createGuard(p) - req = chan.makeFakeRequest('%s/__login__/sub/path?username=test&password=test' % self.getGuardPath()).followAllRedirects() - self.assertEquals(req.written.getvalue(), "Yes") - self.assertEquals(req.path, '%s/sub/path' % self.getGuardPath()) + req = chan.makeFakeRequest(b'%s/__login__/sub/path?username=test&password=test' % self.getGuardPath()).followAllRedirects() + self.assertEqual(req.written.getvalue(), b"Yes") + self.assertEqual(req.path, b'%s/sub/path' % self.getGuardPath()) def testLoginExtraPath_withSlash(self): p = self.createPortal() p.registerChecker(InMemoryUsernamePasswordDatabaseDontUse(test='test'), IUsernamePassword) chan = self.createGuard(p) - req = chan.makeFakeRequest('%s/__login__/sub/path/?username=test&password=test' % self.getGuardPath()).followAllRedirects() - self.assertEquals(req.written.getvalue(), "Yes") - self.assertEquals(req.path, '%s/sub/path/' % self.getGuardPath()) + req = chan.makeFakeRequest(b'%s/__login__/sub/path/?username=test&password=test' % self.getGuardPath()).followAllRedirects() + self.assertEqual(req.written.getvalue(), b"Yes") + self.assertEqual(req.path, b'%s/sub/path/' % self.getGuardPath()) def testLogoutExtraPath(self): p = self.createPortal() p.registerChecker(InMemoryUsernamePasswordDatabaseDontUse(test='test'), IUsernamePassword) chan = self.createGuard(p) - req = chan.makeFakeRequest('%s/__login__?username=test&password=test' % self.getGuardPath()).followAllRedirects() - self.assertEquals(req.written.getvalue(), "Yes") + req = chan.makeFakeRequest(b'%s/__login__?username=test&password=test' % self.getGuardPath()).followAllRedirects() + self.assertEqual(req.written.getvalue(), b"Yes") # Log out - req2 = chan.makeFakeRequest("%s/__logout__/sub/path" % self.getGuardPath()).followRedirect() - self.assertEquals(req2.written.getvalue(), "No") - self.assertEquals(req2.path, '%s/sub/path' % self.getGuardPath()) + req2 = chan.makeFakeRequest(b"%s/__logout__/sub/path" % self.getGuardPath()).followRedirect() + self.assertEqual(req2.written.getvalue(), b"No") + self.assertEqual(req2.path, b'%s/sub/path' % self.getGuardPath()) def testLogoutExtraPath_withSlash(self): p = self.createPortal() p.registerChecker(InMemoryUsernamePasswordDatabaseDontUse(test='test'), IUsernamePassword) chan = self.createGuard(p) - req = chan.makeFakeRequest('%s/__login__?username=test&password=test' % self.getGuardPath()).followAllRedirects() - self.assertEquals(req.written.getvalue(), "Yes") + req = chan.makeFakeRequest(b'%s/__login__?username=test&password=test' % self.getGuardPath()).followAllRedirects() + self.assertEqual(req.written.getvalue(), b"Yes") # Log out - req2 = chan.makeFakeRequest("%s/__logout__/sub/path/" % self.getGuardPath()).followRedirect() - self.assertEquals(req2.written.getvalue(), "No") - self.assertEquals(req2.path, '%s/sub/path/' % self.getGuardPath()) + req2 = chan.makeFakeRequest(b"%s/__logout__/sub/path/" % self.getGuardPath()).followRedirect() + self.assertEqual(req2.written.getvalue(), b"No") + self.assertEqual(req2.path, b'%s/sub/path/' % self.getGuardPath()) def testGetLoggedInRoot_getLogin(self): p = self.createPortal(realmFactory=GetLoggedInRealm) p.registerChecker(InMemoryUsernamePasswordDatabaseDontUse(test='test'), IUsernamePassword) chan = self.createGuard(p) - req = chan.makeFakeRequest('%s/__login__?username=test&password=test' % self.getGuardPath()).followAllRedirects() - self.assertEquals(req.written.getvalue(), "GetLoggedInAvatar") + req = chan.makeFakeRequest('%s/__login__?username=test&password=test' % util.toString(self.getGuardPath())).followAllRedirects() + self.assertEqual(req.written.getvalue(), b"GetLoggedInAvatar") def testGetLoggedInRoot_httpAuthLogin(self): @@ -795,9 +804,9 @@ def testGetLoggedInRoot_httpAuthLogin(self): p.registerChecker(InMemoryUsernamePasswordDatabaseDontUse(test='test'), IUsernamePassword) chan = self.createGuard(p) for x in range(4): - req = chan.makeFakeRequest('%s/' % self.getGuardPath(), "test", "test") - self.assertEquals(req.written.getvalue(), "GetLoggedInAvatar") - self.assertEquals(len(self.sessions),1) + req = chan.makeFakeRequest(b'%s/' % self.getGuardPath(), "test", "test") + self.assertEqual(req.written.getvalue(), b"GetLoggedInAvatar") + self.assertEqual(len(self.sessions),1) def testErrorPage_httpAuth(self): """Failed HTTP Auth results in a 403 error.""" @@ -806,15 +815,15 @@ def testErrorPage_httpAuth(self): IUsernamePassword) chan = self.createGuard(p) - req = chan.makeFakeRequest('%s' % self.getGuardPath(), + req = chan.makeFakeRequest(b'%s' % self.getGuardPath(), "test", "invalid-password") self.assertFalse(req.responseHeaders.hasHeader('location')) - self.assertEquals(req.code, 403) - self.assertEquals(req.written.getvalue(), - 'Forbidden' - +'

Forbidden

Request was forbidden.' - +'') - self.assertEquals(req.path, self.getGuardPath()) + self.assertEqual(req.code, 403) + self.assertEqual(req.written.getvalue(), + b'Forbidden' + +b'

Forbidden

Request was forbidden.' + +b'') + self.assertEqual(req.path, self.getGuardPath()) def testErrorPage_httpAuth_deep(self): """Failed HTTP Auth results in a 403 error.""" @@ -823,15 +832,16 @@ def testErrorPage_httpAuth_deep(self): IUsernamePassword) chan = self.createGuard(p) - req = chan.makeFakeRequest('%s/quux/thud' % self.getGuardPath(), + req = chan.makeFakeRequest(b'%s/quux/thud' % self.getGuardPath(), "test", "invalid-password") self.assertFalse(req.responseHeaders.hasHeader('location')) - self.assertEquals(req.code, 403) - self.assertEquals(req.written.getvalue(), - 'Forbidden' - +'

Forbidden

Request was forbidden.' - +'') - self.assertEquals(req.path, '%s/quux/thud' % self.getGuardPath()) + self.assertEqual(req.code, 403) + self.assertEqual(req.written.getvalue(), + util.toBytes( + 'Forbidden' + +'

Forbidden

Request was forbidden.' + +'')) + self.assertEqual(req.path, b'%s/quux/thud' % self.getGuardPath()) def testErrorPage_getLogin(self): """Failed normal login results in anonymous view of the same page.""" @@ -841,13 +851,13 @@ def testErrorPage_getLogin(self): chan = self.createGuard(p) req = chan.makeFakeRequest( - '%s/__login__?username=test&password=invalid-password' + b'%s/__login__?username=test&password=invalid-password' % self.getGuardPath()).followAllRedirects() - self.assertEquals(req.written.getvalue(), 'No') + self.assertEqual(req.written.getvalue(), b'No') wanted = self.getGuardPath() - if wanted == '': - wanted = '/' - self.assertEquals(req.path, wanted) + if wanted == b'': + wanted = b'/' + self.assertEqual(req.path, wanted) def testErrorPage_getLogin_deep(self): """Failed normal login results in anonymous view of the same page.""" @@ -857,10 +867,10 @@ def testErrorPage_getLogin_deep(self): chan = self.createGuard(p) req = chan.makeFakeRequest( - '%s/__login__/quux/thud?username=test&password=invalid-password' + b'%s/__login__/quux/thud?username=test&password=invalid-password' % self.getGuardPath()).followAllRedirects() - self.assertEquals(req.written.getvalue(), 'No') - self.assertEquals(req.path, '%s/quux/thud' % self.getGuardPath()) + self.assertEqual(req.written.getvalue(), b'No') + self.assertEqual(req.path, b'%s/quux/thud' % self.getGuardPath()) class ParentPage(rend.Page): diff --git a/nevow/test/test_howtolistings.py b/nevow/test/test_howtolistings.py index 965f01e3..23650d87 100644 --- a/nevow/test/test_howtolistings.py +++ b/nevow/test/test_howtolistings.py @@ -3,6 +3,7 @@ This module tests the code listings used in the documentation. """ +import imp import sys from twisted.python.filepath import FilePath @@ -12,7 +13,7 @@ from nevow.testutil import renderLivePage, JavaScriptTestCase from nevow.athena import jsDeps, expose -from nevow import plugins +from nevow import plugins, util class ExampleTestBase(object): @@ -53,7 +54,7 @@ def setUp(self): jsDeps._loadPlugins = True # Even more horrible! nevow.plugins.__path__ needs to be recomputed # each time for the new value of sys.path. - reload(plugins) + imp.reload(plugins) def tearDown(self): @@ -64,7 +65,7 @@ def tearDown(self): sys.modules.clear() sys.modules.update(self.originalModules) sys.path[:] = self.originalPath - reload(plugins) + imp.reload(plugins) @@ -83,7 +84,7 @@ def run(self, result): base.examplePath = self.examplePath try: base.setUp() - except SkipTest, e: + except SkipTest as e: result.startTest(self) result.addSkip(self, str(e)) result.stopTest(self) @@ -137,9 +138,11 @@ def test_renderEcho(self): def checkContent(result): # The "liveElement" renderer inserts this, let's look for it to # make sure it rendered live: - self.assertIn('id="athena:'+str(eb._athenaID)+'"', result) - self.assertIn('athena:class="EchoThing.EchoWidget"', result) - self.assertIn(TEXT, result) + self.assertIn( + util.toBytes('id="athena:'+str(eb._athenaID)+'"'), result) + self.assertIn( + util.toBytes('athena:class="EchoThing.EchoWidget"'), result) + self.assertIn(util.toBytes(TEXT), result) return renderLivePage(erlp).addCallback(checkContent) @@ -152,8 +155,8 @@ def test_echoTellsClient(self): eb = EchoElement() echoed = [] eb.callRemote = lambda method, message: echoed.append((method, message)) - eb.say(u'HELLO... Hello... hello...') - self.assertEquals(echoed, [('addText', u'HELLO... Hello... hello...')]) + eb.say('HELLO... Hello... hello...') + self.assertEqual(echoed, [('addText', 'HELLO... Hello... hello...')]) @@ -191,9 +194,11 @@ def test_basicRendering(self): def checkContent(result): # The "liveElement" renderer inserts this, let's look for it to # make sure it rendered live: - self.assertIn('id="athena:'+str(cb._athenaID)+'"', result) - self.assertIn('athena:class="ChatThing.ChatterWidget"', result) - self.assertIn(PROMPT, result) + self.assertIn(util.toBytes('id="athena:'+str(cb._athenaID)+'"'), + result) + self.assertIn( + util.toBytes('athena:class="ChatThing.ChatterWidget"'), result) + self.assertIn(util.toBytes(PROMPT), result) return renderLivePage(erlp).addCallback(checkContent) @@ -205,8 +210,8 @@ def test_username(self): from chatthing.chatterbox import ChatterElement, ChatRoom cb = ChatterElement(ChatRoom()) setUsername = expose.get(cb, 'setUsername') - setUsername(u'jethro') - self.assertIdentical(u'jethro', cb.username) + setUsername('jethro') + self.assertIdentical('jethro', cb.username) def test_loginThenWall(self): @@ -220,14 +225,14 @@ def test_loginThenWall(self): cr = ChatRoom() user1 = cr.makeChatter() user1.wall = lambda msg: jethroHeard.append(msg) - user1.setUsername(u'jethro') + user1.setUsername('jethro') user2 = cr.makeChatter() user2.wall = lambda msg: cletusHeard.append(msg) - user2.setUsername(u'cletus') - self.assertEquals(jethroHeard, - [u' * user jethro has joined the room', - u' * user cletus has joined the room']) - self.assertEquals(cletusHeard, [u' * user cletus has joined the room']) + user2.setUsername('cletus') + self.assertEqual(jethroHeard, + [' * user jethro has joined the room', + ' * user cletus has joined the room']) + self.assertEqual(cletusHeard, [' * user cletus has joined the room']) def test_sayThenHear(self): @@ -239,18 +244,18 @@ def test_sayThenHear(self): cr = ChatRoom() user1 = cr.makeChatter() user1.wall = lambda msg: msg - user1.setUsername(u'jethro') + user1.setUsername('jethro') user2 = cr.makeChatter() user2.wall = lambda msg: msg - user2.setUsername(u'cletus') + user2.setUsername('cletus') jethroHeard = [] cletusHeard = [] user1.hear = lambda who, what: jethroHeard.append((who,what)) user2.hear = lambda who, what: cletusHeard.append((who,what)) say = expose.get(user1, 'say') - say(u'Hey, Cletus!') - self.assertEquals(jethroHeard, cletusHeard) - self.assertEquals(cletusHeard, [(u'jethro', u'Hey, Cletus!')]) + say('Hey, Cletus!') + self.assertEqual(jethroHeard, cletusHeard) + self.assertEqual(cletusHeard, [('jethro', 'Hey, Cletus!')]) def test_wallTellsClient(self): @@ -262,8 +267,8 @@ def test_wallTellsClient(self): cb = ChatRoom().makeChatter() heard = [] cb.callRemote = lambda method, msg: heard.append((method, msg)) - cb.wall(u'Message for everyone...') - self.assertEquals(heard, [('displayMessage', u'Message for everyone...')]) + cb.wall('Message for everyone...') + self.assertEqual(heard, [('displayMessage', 'Message for everyone...')]) def test_hearTellsClient(self): """ @@ -274,6 +279,6 @@ def test_hearTellsClient(self): cb = ChatRoom().makeChatter() heard = [] cb.callRemote = lambda method, who, what: heard.append((method, who, what)) - cb.hear(u'Hello', u'Chat') - self.assertEquals(heard, [('displayUserMessage', u'Hello', u'Chat')]) + cb.hear('Hello', 'Chat') + self.assertEqual(heard, [('displayUserMessage', 'Hello', 'Chat')]) diff --git a/nevow/test/test_i18n.py b/nevow/test/test_i18n.py index 768583b1..00e76760 100644 --- a/nevow/test/test_i18n.py +++ b/nevow/test/test_i18n.py @@ -1,7 +1,7 @@ -from zope.interface import implements +from zope.interface import implementer from twisted.trial import unittest -from cStringIO import StringIO +from io import StringIO from nevow import inevow, flat, context, tags, loaders, rend from nevow import i18n from nevow.testutil import FakeRequest @@ -11,7 +11,7 @@ def mockTranslator(s, languages=None, domain=None): if domain is not None: args['domain'] = domain return 'MOCK(%s)[%s]' % (', '.join(['%s=%r' % (k,v) - for k,v in args.items()]), + for k,v in list(args.items())]), s) class Misc(unittest.TestCase): @@ -21,13 +21,13 @@ def test_simple(self): def test_simple_flat(self): s = i18n._('foo') r = flat.ten.flatten(s, None) - self.assertEquals(r, 'foo') + self.assertEqual(r, 'foo') def test_translator(self): _ = i18n.Translator(translator=mockTranslator) s = _('foo') r = flat.ten.flatten(s, None) - self.assertEquals(r, 'MOCK()[foo]') + self.assertEqual(r, 'MOCK()[foo]') class Config(unittest.TestCase): def test_remember(self): @@ -41,13 +41,13 @@ def test_classInit(self): domain='bar') s = _('foo') r = flat.ten.flatten(s, None) - self.assertEquals(r, "MOCK(domain='bar')[foo]") + self.assertEqual(r, "MOCK(domain='bar')[foo]") def test_runTime(self): _ = i18n.Translator(translator=mockTranslator) s = _('foo', domain='baz') r = flat.ten.flatten(s, None) - self.assertEquals(r, "MOCK(domain='baz')[foo]") + self.assertEqual(r, "MOCK(domain='baz')[foo]") def test_context(self): _ = i18n.Translator(translator=mockTranslator) @@ -56,7 +56,7 @@ def test_context(self): ctx.remember(cfg) s = _('foo') r = flat.ten.flatten(s, ctx) - self.assertEquals(r, "MOCK(domain='thud')[foo]") + self.assertEqual(r, "MOCK(domain='thud')[foo]") def test_runTime_beats_all(self): _ = i18n.Translator(translator=mockTranslator, @@ -66,7 +66,7 @@ def test_runTime_beats_all(self): ctx.remember(cfg) s = _('foo', domain='baz') r = flat.ten.flatten(s, None) - self.assertEquals(r, "MOCK(domain='baz')[foo]") + self.assertEqual(r, "MOCK(domain='baz')[foo]") def test_classInit_beats_context(self): @@ -77,14 +77,14 @@ def test_classInit_beats_context(self): ctx.remember(cfg) s = _('foo') r = flat.ten.flatten(s, None) - self.assertEquals(r, "MOCK(domain='baz')[foo]") + self.assertEqual(r, "MOCK(domain='baz')[foo]") class Format(unittest.TestCase): def test_simple(self): _ = i18n.Translator(translator=mockTranslator) s = _('foo %s') % 'bar' r = flat.ten.flatten(s, None) - self.assertEquals(r, "MOCK()[foo bar]") + self.assertEqual(r, "MOCK()[foo bar]") def test_multiple(self): _ = i18n.Translator(translator=mockTranslator) @@ -92,7 +92,7 @@ def test_multiple(self): s = s % 'bar %s' s = s % 'baz' r = flat.ten.flatten(s, None) - self.assertEquals(r, "MOCK()[foo bar baz]") + self.assertEqual(r, "MOCK()[foo bar baz]") @@ -101,7 +101,7 @@ def test_noLanguages(self): request = FakeRequest(headers={}) ctx = context.RequestContext(tag=request) r = inevow.ILanguages(ctx) - self.assertEquals(r, []) + self.assertEqual(r, []) def test_oneLanguage(self): request = FakeRequest(headers={ @@ -109,7 +109,7 @@ def test_oneLanguage(self): }) ctx = context.RequestContext(tag=request) r = inevow.ILanguages(ctx) - self.assertEquals(r, ['fo']) + self.assertEqual(r, ['fo']) def test_multipleLanguages(self): request = FakeRequest(headers={ @@ -117,7 +117,7 @@ def test_multipleLanguages(self): }) ctx = context.RequestContext(tag=request) r = inevow.ILanguages(ctx) - self.assertEquals(r, ['fo', 'ba', 'th']) + self.assertEqual(r, ['fo', 'ba', 'th']) def test_quality_simple(self): request = FakeRequest(headers={ @@ -125,7 +125,7 @@ def test_quality_simple(self): }) ctx = context.RequestContext(tag=request) r = inevow.ILanguages(ctx) - self.assertEquals(r, ['fo']) + self.assertEqual(r, ['fo']) def test_quality_sort(self): request = FakeRequest(headers={ @@ -133,7 +133,7 @@ def test_quality_sort(self): }) ctx = context.RequestContext(tag=request) r = inevow.ILanguages(ctx) - self.assertEquals(r, ['xy', 'fo', 'ba']) + self.assertEqual(r, ['xy', 'fo', 'ba']) def test_quality_invalid_notQ(self): request = FakeRequest(headers={ @@ -141,7 +141,7 @@ def test_quality_invalid_notQ(self): }) ctx = context.RequestContext(tag=request) r = inevow.ILanguages(ctx) - self.assertEquals(r, ['ba', 'fo']) + self.assertEqual(r, ['fo', 'ba']) def test_quality_invalid_notFloat(self): request = FakeRequest(headers={ @@ -149,7 +149,7 @@ def test_quality_invalid_notFloat(self): }) ctx = context.RequestContext(tag=request) r = inevow.ILanguages(ctx) - self.assertEquals(r, ['ba', 'fo']) + self.assertEqual(r, ['fo', 'ba']) class Render(unittest.TestCase): def makePage(self, content): @@ -172,15 +172,15 @@ def finisher(result): def test_empty(self): return self.makePage(['']).addCallback( - lambda r: self.assertEquals(r, 'MOCK()[]')) + lambda r: self.assertEqual(r, 'MOCK()[]')) def test_simple(self): return self.makePage(['foo']).addCallback( - lambda r: self.assertEquals(r, 'MOCK()[foo]')) + lambda r: self.assertEqual(r, 'MOCK()[foo]')) def test_stan(self): return self.makePage([tags.p['You should really avoid tags in i18n input.']]).addCallback( - lambda r: self.assertEquals(r, 'MOCK()[

You should really avoid tags in i18n input.

]')) + lambda r: self.assertEqual(r, 'MOCK()[

You should really avoid tags in i18n input.

]')) class InterpolateTests: def test_mod_string(self): @@ -188,7 +188,7 @@ def test_mod_string(self): 'foo bar') def test_mod_unicode(self): - self.check('foo %s', u'bar', + self.check('foo %s', 'bar', 'foo bar') def test_mod_int(self): @@ -255,7 +255,7 @@ def setUp(self): self._ = i18n.Translator(translator=mockTranslator) def mangle(self, s): - raise NotImplementedError, 'override mangle somewhere' + raise NotImplementedError('override mangle somewhere') def check(self, fmt, args, *wants): got = self.mangle(self._(fmt) % args) @@ -288,32 +288,32 @@ def check(self, fmt, args, *wants): InterpolateMixin.check(self, fmt, args, *['MOCK()[%s]' % x for x in wants]) -class UNGettext(unittest.TestCase): +class NGettext(unittest.TestCase): def test_simple(self): - s1 = i18n.ungettext('%d foo', '%d foos', 1) - s2 = i18n.ungettext('%d foo', '%d foos', 42) + s1 = i18n.ngettext('%d foo', '%d foos', 1) + s2 = i18n.ngettext('%d foo', '%d foos', 42) def test_simple_flat_one(self): - s = i18n.ungettext('%d foo', '%d foos', 1) + s = i18n.ngettext('%d foo', '%d foos', 1) r = flat.ten.flatten(s, None) - self.assertEquals(r, '%d foo') + self.assertEqual(r, '%d foo') def test_simple_flat_many(self): - s = i18n.ungettext('%d foo', '%d foos', 42) + s = i18n.ngettext('%d foo', '%d foos', 42) r = flat.ten.flatten(s, None) - self.assertEquals(r, '%d foos') + self.assertEqual(r, '%d foos') def test_simple_flat_many(self): - s = i18n.ungettext('%d foo', '%d foos', 42) + s = i18n.ngettext('%d foo', '%d foos', 42) r = flat.ten.flatten(s, None) - self.assertEquals(r, '%d foos') + self.assertEqual(r, '%d foos') def test_format_one(self): - s = i18n.ungettext('%d foo', '%d foos', 1) % 1 + s = i18n.ngettext('%d foo', '%d foos', 1) % 1 r = flat.ten.flatten(s, None) - self.assertEquals(r, "1 foo") + self.assertEqual(r, "1 foo") def test_format_many(self): - s = i18n.ungettext('%d foo', '%d foos', 42) % 42 + s = i18n.ngettext('%d foo', '%d foos', 42) % 42 r = flat.ten.flatten(s, None) - self.assertEquals(r, "42 foos") + self.assertEqual(r, "42 foos") diff --git a/nevow/test/test_json.py b/nevow/test/test_json.py index e41b87cf..24c2d36f 100644 --- a/nevow/test/test_json.py +++ b/nevow/test/test_json.py @@ -5,7 +5,7 @@ Tests for L{nevow.json}. """ -from zope.interface import implements +from zope.interface import implementer from nevow.inevow import IAthenaTransportable from nevow import json, rend, page, loaders, tags, athena, testutil @@ -21,31 +21,31 @@ [0], [0, 1, 2], [None, 1, 2], - [None, u'one', 2], - [True, False, u'string', 10], + [None, 'one', 2], + [True, False, 'string', 10], [[1, 2], [3, 4]], [[1.5, 2.5], [3.5, 4.5]], - [0, [1, 2], [u'hello'], [u'world'], [True, None, False]], + [0, [1, 2], ['hello'], ['world'], [True, None, False]], {}, - {u'foo': u'bar'}, - {u'foo': None}, - {u'bar': True}, - {u'baz': [1, 2, 3]}, - {u'quux': {u'bar': u'foo'}}, + {'foo': 'bar'}, + {'foo': None}, + {'bar': True}, + {'baz': [1, 2, 3]}, + {'quux': {'bar': 'foo'}}, ] TEST_STRINGLIKE_OBJECTS = [ - u'', - u'string', - u'string with "embedded" quotes', - u"string with 'embedded' single-quotes", - u'string with \\"escaped embedded\\" quotes', - u"string with \\'escaped embedded\\' single-quotes", - u"string with backslashes\\\\", - u"string with trailing accented vowels: \xe1\xe9\xed\xf3\xfa\xfd\xff", - u"string with trailing control characters: \f\b\n\t\r", - u'string with high codepoint characters: \u0111\u2222\u3333\u4444\uffff', - u'string with very high codepoint characters: \U00011111\U00022222\U00033333\U00044444\U000fffff', + '', + 'string', + 'string with "embedded" quotes', + "string with 'embedded' single-quotes", + 'string with \\"escaped embedded\\" quotes', + "string with \\'escaped embedded\\' single-quotes", + "string with backslashes\\\\", + "string with trailing accented vowels: \xe1\xe9\xed\xf3\xfa\xfd\xff", + "string with trailing control characters: \f\b\n\t\r", + 'string with high codepoint characters: \u0111\u2222\u3333\u4444\uffff', + 'string with very high codepoint characters: \U00011111\U00022222\U00033333\U00044444\U000fffff', ] @@ -87,13 +87,13 @@ class JavascriptObjectNotationTestCase(unittest.TestCase): def testSerialize(self): for struct in TEST_OBJECTS: - json.serialize(struct) + json.dumps(struct) def testRoundtrip(self): for struct in TEST_OBJECTS: - bytes = json.serialize(struct) - unstruct = json.parse(bytes) - self.assertEquals( + bytes = json.dumps(struct) + unstruct = json.loads(bytes) + self.assertEqual( unstruct, struct, "Failed to roundtrip %r: %r (through %r)" % ( struct, unstruct, bytes)) @@ -103,23 +103,23 @@ def test_undefined(self): """ C{undefined} is parsed as Python C{None}. """ - self.assertEquals(None, json.parse(b'undefined')) + self.assertEqual(None, json.loads(b'undefined')) - def testStringlikeRountrip(self): + def testStringlikeRoundtrip(self): for struct in TEST_STRINGLIKE_OBJECTS: - bytes = json.serialize(struct) - unstruct = json.parse(bytes) + bytes = json.dumps(struct) + unstruct = json.loads(bytes) failMsg = "Failed to roundtrip %r: %r (through %r)" % ( struct, unstruct, bytes) - self.assertEquals(unstruct, struct, failMsg) - self.assert_(isinstance(unstruct, unicode), failMsg) + self.assertEqual(unstruct, struct, failMsg) + self.assertTrue(isinstance(unstruct, str), failMsg) def test_lineTerminators(self): """ When passed a unicode string containing a line terminator, - L{json.serialize} emits an escape sequence representing that character + L{json.dumps} emits an escape sequence representing that character (not a UTF-8 sequence directly representing that the line terminator code point). @@ -127,31 +127,31 @@ def test_lineTerminators(self): handle them properly. """ # These are the four line terminators currently in Unicode. - self.assertEqual('"\\r"', json.serialize(u"\r")) - self.assertEqual('"\\n"', json.serialize(u"\n")) - self.assertEqual('"\\u2028"', json.serialize(u"\u2028")) - self.assertEqual('"\\u2029"', json.serialize(u"\u2029")) + self.assertEqual('"\\r"', json.dumps("\r")) + self.assertEqual('"\\n"', json.dumps("\n")) + self.assertEqual('"\\u2028"', json.dumps("\u2028")) + self.assertEqual('"\\u2029"', json.dumps("\u2029")) def testScientificNotation(self): - self.assertEquals(json.parse('1e10'), 10**10) - self.assertEquals(json.parse('1e0'), 1) + self.assertEqual(json.loads('1e10'), 10**10) + self.assertEqual(json.loads('1e0'), 1) def testHexEscapedCodepoints(self): - self.assertEquals( - json.parse('"\\xe1\\xe9\\xed\\xf3\\xfa\\xfd"'), - u"\xe1\xe9\xed\xf3\xfa\xfd") + self.assertEqual( + json.loads('"\\u00e1\\u00e9\\u00ed\\u00f3\\u00fa\\u00fd"'), + "\xe1\xe9\xed\xf3\xfa\xfd") def testEscapedControls(self): - self.assertEquals( - json.parse('"\\f\\b\\n\\t\\r"'), - u"\f\b\n\t\r") + self.assertEqual( + json.loads('"\\f\\b\\n\\t\\r"'), + "\f\b\n\t\r") def _rendererTest(self, cls): - self.assertEquals( - json.serialize( + self.assertEqual( + json.dumps( cls( docFactory=loaders.stan(tags.p['Hello, world.']))), '"

Hello, world.

"') @@ -176,13 +176,13 @@ def test_elementSerialization(self): def _doubleSerialization(self, cls): fragment = cls(docFactory=loaders.stan(tags.div['Hello'])) self.assertEqual( - json.serialize(fragment), - json.serialize(fragment)) + json.dumps(fragment), + json.dumps(fragment)) def test_doubleFragmentSerialization(self): """ - Test that repeatedly calling L{json.serialize} with an instance of + Test that repeatedly calling L{json.dumps} with an instance of L{rend.Fragment} results in the same result each time. """ return self._doubleSerialization(rend.Fragment) @@ -204,8 +204,8 @@ def _doubleLiveSerialization(self, cls, renderer): tags.div(render=tags.directive('foo'))])) liveFragment.setFragmentParent(livePage) self.assertEqual( - json.serialize(liveFragment), - json.serialize(liveFragment)) + json.dumps(liveFragment), + json.dumps(liveFragment)) def test_doubleLiveFragmentSerialization(self): @@ -244,50 +244,49 @@ def foo(self, request, tag): def test_unsupportedSerialization(self): """ - L{json.serialize} should raise a L{TypeError} if it is passed an object + L{json.dumps} should raise a L{TypeError} if it is passed an object which it does not know how to serialize. """ class Unsupported(object): def __repr__(self): return 'an unsupported object' - exception = self.assertRaises(TypeError, json.serialize, Unsupported()) + exception = self.assertRaises(TypeError, json.dumps, Unsupported()) self.assertEqual( str(exception), - "Unsupported type : " - "an unsupported object") + "Object of type Unsupported is not JSON serializable") def test_customSerialization(self): """ - L{json.serialize} should emit JavaScript calls to the JavaScript object + L{json.dumps} should emit JavaScript calls to the JavaScript object named by L{IAthenaTransportable.jsClass} with the arguments returned by L{IAthenaTransportable.getInitialArguments} when passed an object which can be adapted to L{IAthenaTransportable}. """ + @implementer(IAthenaTransportable) class Transportable(object): """ Completely parameterized L{IAthenaTransportable} implementation so different data can be easily tested. """ - implements(IAthenaTransportable) def __init__(self, jsClass, initialArgs): self.jsClass = jsClass self.getInitialArguments = lambda: initialArgs self.assertEqual( - json.serialize(Transportable(u"Foo", ())), - "(new Foo())") + json.dumps(Transportable("Foo", ())), + '"(new Foo())"') self.assertEqual( - json.serialize(Transportable(u"Bar", (None,))), - "(new Bar(null))") + json.dumps(Transportable("Bar", (None,))), + '"(new Bar(null))"') self.assertEqual( - json.serialize(Transportable(u"Baz.Quux", (1, 2))), - "(new Baz.Quux(1,2))") + json.dumps(Transportable("Baz.Quux", (1, 2))), + '"(new Baz.Quux(1,2))"') # The style of the quotes in this assertion is basically irrelevant. # If, for some reason, the serializer changes to use ' instead of ", # there's no reason not to change this test to reflect that. -exarkun self.assertEqual( - json.serialize(Transportable(u"Quux", (u"Foo",))), - '(new Quux("Foo"))') + json.dumps(Transportable("Quux", ("Foo",))), + '"(new Quux(\\"Foo\\"))"') diff --git a/nevow/test/test_later.py b/nevow/test/test_later.py index 59ca9b71..2ffdbc35 100644 --- a/nevow/test/test_later.py +++ b/nevow/test/test_later.py @@ -43,29 +43,29 @@ def setUp(self): def test_deferredSupport(self): req = self.renderIt() - self.assertEquals(req.v, 'Hello ') + self.assertEqual(req.v, b'Hello ') self.d.callback("world") - self.assertEquals(req.v, 'Hello world') + self.assertEqual(req.v, b'Hello world') self.d2.callback(".") - self.assertEquals(req.v, 'Hello world.') + self.assertEqual(req.v, b'Hello world.') def test_deferredSupport2(self): req = self.renderIt() - self.assertEquals(req.v, 'Hello ') + self.assertEqual(req.v, b'Hello ') self.d2.callback(".") - self.assertEquals(req.v, 'Hello ') + self.assertEqual(req.v, b'Hello ') self.d.callback("world") - self.assertEquals(req.v, 'Hello world.') + self.assertEqual(req.v, b'Hello world.') def test_deferredSupport3(self): self.r.buffered = True req = self.renderIt() - self.assertEquals(req.v, '') + self.assertEqual(req.v, b'') self.d.callback("world") - self.assertEquals(req.v, '') + self.assertEqual(req.v, b'') self.d2.callback(".") - self.assertEquals(req.v, 'Hello world.') + self.assertEqual(req.v, b'Hello world.') def test_renderNestedDeferredCallables(self): """ @@ -84,7 +84,7 @@ def render_outer(ctx, data): out = [] d = twist.deferflatten(render_outer, ctx, out.append) def flattened(ign): - self.assertEquals(out, ['']) + self.assertEqual(out, ['']) d.addCallback(flattened) return d @@ -130,11 +130,11 @@ def setUp(self): def test_deferredSupport(self): req = self.renderIt() - self.assertEquals(req.v, '') + self.assertEqual(req.v, b'') self.d.callback("world") - self.assertEquals(req.v, 'Hello world and goodbye world') + self.assertEqual(req.v, b'Hello world and goodbye world') self.d2.callback(".") - self.assertEquals(req.v, 'Hello world and goodbye world.') + self.assertEqual(req.v, b'Hello world and goodbye world.') class SuperLaterDataTest(RenderHelper): @@ -148,7 +148,7 @@ def test_reusedDeferredSupport(self): doc.fillSlots('foo', defer.succeed(tags.span['Foo!!!'])) self.r = rend.Page(docFactory=loaders.stan(doc)) req = self.renderIt() - self.assertEquals(req.v, 'Foo!!!Foo!!!') + self.assertEqual(req.v, b'Foo!!!Foo!!!') def test_rendererCalledOnce(self): @@ -167,4 +167,4 @@ def render_renderer(self, ctx, data): return defer.succeed(recorder) self.r = RendererPage() req = self.renderIt() - self.assertEquals(req.v, '1') + self.assertEqual(req.v, b'1') diff --git a/nevow/test/test_loaders.py b/nevow/test/test_loaders.py index d604f845..b280170c 100644 --- a/nevow/test/test_loaders.py +++ b/nevow/test/test_loaders.py @@ -15,17 +15,17 @@ class TestDocFactories(unittest.TestCase): def _preprocessorTest(self, docFactory): def preprocessor(uncompiled): - self.assertEquals(len(uncompiled), 1) + self.assertEqual(len(uncompiled), 1) uncompiled = uncompiled[0] - self.assertEquals(uncompiled.tagName, 'div') - self.assertEquals(len(uncompiled.children), 2) - self.assertEquals(uncompiled.children[0].tagName, 'span') - self.assertEquals(uncompiled.children[0].children, ['Hello']) - self.assertEquals(uncompiled.children[1].tagName, 'span') - self.assertEquals(uncompiled.children[1].children, ['world']) + self.assertEqual(uncompiled.tagName, 'div') + self.assertEqual(len(uncompiled.children), 2) + self.assertEqual(uncompiled.children[0].tagName, 'span') + self.assertEqual(uncompiled.children[0].children, ['Hello']) + self.assertEqual(uncompiled.children[1].tagName, 'span') + self.assertEqual(uncompiled.children[1].children, ['world']) return t.div['goodbye.'] doc = docFactory.load(preprocessors=[preprocessor]) - self.assertEquals(doc, ['
goodbye.
']) + self.assertEqual(doc, ['
goodbye.
']) def test_stanPreprocessors(self): @@ -41,7 +41,7 @@ def test_stanPreprocessors(self): def test_stan(self): doc = t.ul(id='nav')[t.li['one'], t.li['two'], t.li['three']] df = loaders.stan(doc) - self.assertEquals(df.load()[0], '') + self.assertEqual(df.load()[0], '') def test_stanPrecompiled(self): @@ -55,7 +55,7 @@ def test_stanPrecompiled(self): df = loaders.stan(doc) loaded = df.load() self.assertEqual(loaded[0], '') @@ -63,7 +63,7 @@ def test_stanPrecompiled(self): def test_htmlstr(self): doc = '' df = loaders.htmlstr(doc) - self.assertEquals(df.load()[0], doc) + self.assertEqual(df.load()[0], doc) test_htmlstr.suppress = [ util.suppress(message= r"\[v0.8\] htmlstr is deprecated because it's buggy. " @@ -73,11 +73,10 @@ def test_htmlstr(self): def test_htmlfile(self): doc = '' temp = self.mktemp() - f = file(temp, 'w') - f.write(doc) - f.close() + with open(temp, 'w') as f: + f.write(doc) df = loaders.htmlfile(temp) - self.assertEquals(df.load()[0], doc) + self.assertEqual(df.load()[0], doc) test_htmlfile.suppress = [ util.suppress(message= r"\[v0.8\] htmlfile is deprecated because it's buggy. " @@ -85,13 +84,12 @@ def test_htmlfile(self): def test_htmlfile_slots(self): - doc = 'Hi there' + doc = 'Hi there' temp = self.mktemp() - f = file(temp, 'w') - f.write(doc) - f.close() + with open(temp, 'w') as f: + f.write(doc) df = loaders.htmlfile(temp) - self.assertEquals(df.load()[0].children, ['Hi there']) + self.assertEqual(df.load()[0].children, ['Hi there']) test_htmlfile_slots.suppress = [ util.suppress(message= r"\[v0.8\] htmlfile is deprecated because it's buggy. " @@ -101,7 +99,7 @@ def test_htmlfile_slots(self): def test_xmlstr(self): doc = '' df = loaders.xmlstr(doc) - self.assertEquals(df.load()[0], doc) + self.assertEqual(df.load()[0], doc) def test_xmlstrPreprocessors(self): @@ -117,11 +115,10 @@ def test_xmlstrPreprocessors(self): def test_xmlfile(self): doc = '' temp = self.mktemp() - f = file(temp, 'w') - f.write(doc) - f.close() + with open(temp, 'w') as f: + f.write(doc) df = loaders.xmlfile(temp) - self.assertEquals(df.load()[0], doc) + self.assertEqual(df.load()[0], doc) def test_xmlfilePreprocessors(self): @@ -130,9 +127,8 @@ def test_xmlfilePreprocessors(self): preprocessors it is given. """ xmlFile = self.mktemp() - f = file(xmlFile, 'w') - f.write('
Helloworld
') - f.close() + with open(xmlFile, 'w') as f: + f.write('
Helloworld
') factory = loaders.xmlfile(xmlFile) return self._preprocessorTest(factory) @@ -142,25 +138,25 @@ def test_patterned(self): """ doc = t.div[t.p[t.span(pattern='inner')['something']]] df = loaders.stan(doc, pattern='inner') - self.assertEquals(df.load()[0].tagName, 'span') - self.assertEquals(df.load()[0].children[0], 'something') + self.assertEqual(df.load()[0].tagName, 'span') + self.assertEqual(df.load()[0].children[0], 'something') def test_ignoreDocType(self): doc = '''\n

Hello.

''' df = loaders.xmlstr(doc, ignoreDocType=True) - self.assertEquals(flat.flatten(df), '

Hello.

') + self.assertEqual(flat.flatten(df), '

Hello.

') def test_ignoreComment(self): doc = '

Hello.

' df = loaders.xmlstr(doc, ignoreComment=True) - self.assertEquals(flat.flatten(df), '

Hello.

') + self.assertEqual(flat.flatten(df), '

Hello.

') class TestDocFactoriesCache(unittest.TestCase): doc = ''' -
+

one

two

@@ -178,10 +174,10 @@ class TestDocFactoriesCache(unittest.TestCase): def test_stan(self): loader = loaders.stan(self.stan) - self.assertEquals( id(loader.load()), id(loader.load()) ) + self.assertEqual( id(loader.load()), id(loader.load()) ) loader = loaders.stan(self.stan, pattern='1') - self.assertEquals( id(loader.load()), id(loader.load()) ) + self.assertEqual( id(loader.load()), id(loader.load()) ) l1 = loaders.stan(self.stan, pattern='1') l2 = loaders.stan(self.stan, pattern='1') @@ -194,10 +190,10 @@ def test_stan(self): def test_htmlstr(self): loader = loaders.htmlstr(self.doc) - self.assertEquals( id(loader.load()), id(loader.load()) ) + self.assertEqual( id(loader.load()), id(loader.load()) ) loader = loaders.htmlstr(self.doc, pattern='1') - self.assertEquals( id(loader.load()), id(loader.load()) ) + self.assertEqual( id(loader.load()), id(loader.load()) ) l1 = loaders.htmlstr(self.doc, pattern='1') l2 = loaders.htmlstr(self.doc, pattern='1') @@ -214,12 +210,11 @@ def test_htmlstr(self): def test_htmlfile(self): temp = self.mktemp() - f = file(temp, 'w') - f.write(self.doc) - f.close() + with open(temp, 'w') as f: + f.write(self.doc) loader = loaders.htmlfile(temp) - self.assertEquals( id(loader.load()), id(loader.load()) ) + self.assertEqual( id(loader.load()), id(loader.load()) ) l1 = loaders.htmlfile(temp, pattern='1') l2 = loaders.htmlfile(temp, pattern='1') @@ -236,13 +231,12 @@ def test_htmlfile(self): def test_htmlfileReload(self): temp = self.mktemp() - f = file(temp, 'w') - f.write(self.doc) - f.close() + with open(temp, 'w') as f: + f.write(self.doc) loader = loaders.htmlfile(temp) r = loader.load() - self.assertEquals(id(r), id(loader.load())) + self.assertEqual(id(r), id(loader.load())) os.utime(temp, (os.path.getatime(temp), os.path.getmtime(temp)+5)) self.assertNotEqual(id(r), id(loader.load())) test_htmlfileReload.suppress = [ @@ -255,10 +249,10 @@ def test_htmlfileReload(self): def test_xmlstr(self): loader = loaders.xmlstr(self.nsdoc) - self.assertEquals( id(loader.load()), id(loader.load()) ) + self.assertEqual( id(loader.load()), id(loader.load()) ) loader = loaders.xmlstr(self.nsdoc, pattern='1') - self.assertEquals( id(loader.load()), id(loader.load()) ) + self.assertEqual( id(loader.load()), id(loader.load()) ) l1 = loaders.xmlstr(self.nsdoc, pattern='1') l2 = loaders.xmlstr(self.nsdoc, pattern='1') @@ -283,22 +277,21 @@ def test_xmlSlotDefault(self): ''' loader = loaders.xmlstr(slotsdoc) loaded = loader.load() - self.assertEquals(loaded[1].default, None) - self.assertEquals(loaded[3].default, "3") + self.assertEqual(loaded[1].default, None) + self.assertEqual(loaded[3].default, "3") def test_xmlfile(self): temp = self.mktemp() - f = file(temp, 'w') - f.write(self.nsdoc) - f.close() + with open(temp, 'w') as f: + f.write(self.nsdoc) loader = loaders.xmlfile(temp) - self.assertEquals( id(loader.load()), id(loader.load()) ) + self.assertEqual( id(loader.load()), id(loader.load()) ) loader = loaders.xmlfile(temp, pattern='1') - self.assertEquals( id(loader.load()), id(loader.load()) ) + self.assertEqual( id(loader.load()), id(loader.load()) ) l1 = loaders.xmlfile(temp, pattern='1') l2 = loaders.xmlfile(temp, pattern='1') @@ -311,13 +304,12 @@ def test_xmlfile(self): def test_xmlfileReload(self): temp = self.mktemp() - f = file(temp, 'w') - f.write(self.nsdoc) - f.close() + with open(temp, 'w') as f: + f.write(self.nsdoc) loader = loaders.xmlfile(temp) r = loader.load() - self.assertEquals(id(r), id(loader.load())) + self.assertEqual(id(r), id(loader.load())) os.utime(temp, (os.path.getatime(temp), os.path.getmtime(temp)+5)) self.assertNotEqual(id(r), id(loader.load())) @@ -328,9 +320,8 @@ def test_reloadAfterPrecompile(self): temp = self.mktemp() # Write some content - f = file(temp, 'w') - f.write('

foo

') - f.close() + with open(temp, 'w') as f: + f.write('

foo

') # Precompile the doc ctx = context.WovenContext() @@ -339,22 +330,21 @@ def test_reloadAfterPrecompile(self): before = ''.join(flat.serialize(pc, ctx)) - # Write the file with different content and make sure the # timestamp changes - f = file(temp, 'w') - f.write('

bar

') - f.close() + with open(temp, 'w') as f: + f.write('

bar

') + os.utime(temp, (os.path.getatime(temp), os.path.getmtime(temp)+5)) after = ''.join(flat.serialize(pc, ctx)) self.assertIn('foo', before) self.assertIn('bar', after) - self.failIfEqual(before, after) - test_reloadAfterPrecompile.todo = \ - 'Fix so that disk templates are reloaded even after a precompile. ' \ - 'Probably just a matter of making the DocSerializer really lazy' + self.assertNotEqual(before, after) + test_reloadAfterPrecompile.todo = \ + 'Fix so that disk templates are reloaded even after a precompile. ' \ + 'Probably just a matter of making the DocSerializer really lazy' class TestContext(unittest.TestCase): @@ -372,9 +362,8 @@ def test_xmlstr(self): def test_xmlfile(self): temp = self.mktemp() - f = file(temp, 'w') - f.write('

hello

') - f.close() + with open(temp, 'w') as f: + f.write('

hello

') self._withAndWithout(loaders.xmlfile(temp)) def test_htmlstr(self): @@ -387,9 +376,8 @@ def test_htmlstr(self): def test_htmlfile(self): temp = self.mktemp() - f = file(temp, 'w') - f.write('

hello

') - f.close() + with open(temp, 'w') as f: + f.write('

hello

') self._withAndWithout(loaders.htmlfile(temp)) test_htmlfile.suppress = [ util.suppress(message= @@ -398,8 +386,8 @@ def test_htmlfile(self): def _withAndWithout(self, loader): ctx = context.WovenContext() - self.assertEquals(loader.load(), ['

hello

']) - self.assertEquals(loader.load(ctx), ['

hello

']) + self.assertEqual(loader.load(), ['

hello

']) + self.assertEqual(loader.load(ctx), ['

hello

']) class TestParsing(unittest.TestCase): @@ -411,4 +399,4 @@ def test_missingSpace(self): ## hard to fix. If you need this, switch to xmlstr. result = loaders.xmlstr(doc).load() # There should be a space between the two slots - self.assertEquals(result[2], ' ') + self.assertEqual(result[2], ' ') diff --git a/nevow/test/test_newflat.py b/nevow/test/test_newflat.py index e567bf08..b9ee4ffb 100644 --- a/nevow/test/test_newflat.py +++ b/nevow/test/test_newflat.py @@ -5,9 +5,9 @@ Tests for L{nevow._flat}. """ -import sys, traceback, StringIO +import sys, traceback, io -from zope.interface import implements +from zope.interface import implementer from twisted.trial.unittest import TestCase from twisted.internet.defer import Deferred, succeed @@ -34,9 +34,10 @@ # lambda to avoid adding anything else to this namespace. The result will # be a string which agrees with the one the traceback module will put into a # traceback for frames associated with functions defined in this file. -HERE = (lambda: None).func_code.co_filename +HERE = (lambda: None).__code__.co_filename +@implementer(IRenderable) class TrivialRenderable(object): """ An object which renders to a parameterized value. @@ -44,7 +45,6 @@ class TrivialRenderable(object): @ivar result: The object which will be returned by the render method. @ivar requests: A list of all the objects passed to the render method. """ - implements(IRenderable) def __init__(self, result): self.result = result @@ -60,6 +60,7 @@ def render(self, request): +@implementer(IRenderable) class RenderRenderable(object): """ An object which renders to a parameterized value and has a render method @@ -71,7 +72,6 @@ class RenderRenderable(object): @ivar tag: The value which will be returned from C{render}. @ivar result: The value which will be returned from the render method. """ - implements(IRenderable) def __init__(self, renders, name, tag, result): self.renders = renders @@ -118,7 +118,7 @@ def flatten(self, root, request=None, inAttribute=False, inXML=False): """ Helper to get a string from L{flatten}. """ - s = StringIO.StringIO() + s = io.StringIO() for _ in flatten(request, s.write, root, inAttribute, inXML): pass return s.getvalue() @@ -193,9 +193,11 @@ def test_unicode(self): An instance of L{unicode} is flattened to the UTF-8 representation of itself. """ - self.assertStringEqual(self.flatten(u'bytes<>&"\0'), 'bytes<>&"\0') - unich = u"\N{LATIN CAPITAL LETTER E WITH GRAVE}" - self.assertStringEqual(self.flatten(unich), unich.encode('utf-8')) + self.assertStringEqual(self.flatten('bytes<>&"\0'), 'bytes<>&"\0') + unich = "\N{LATIN CAPITAL LETTER E WITH GRAVE}" + self.assertEqual( + self.flatten(unich).encode('utf-8'), + unich.encode('utf-8')) def test_xml(self): @@ -203,8 +205,10 @@ def test_xml(self): An L{xml} instance is flattened to the UTF-8 representation of itself. """ self.assertStringEqual(self.flatten(xml("foo")), "foo") - unich = u"\N{LATIN CAPITAL LETTER E WITH GRAVE}" - self.assertStringEqual(self.flatten(xml(unich)), unich.encode('utf-8')) + unich = "\N{LATIN CAPITAL LETTER E WITH GRAVE}" + self.assertEqual( + self.flatten(xml(unich)).encode('utf-8'), + unich.encode('utf-8')) def test_entity(self): @@ -303,8 +307,8 @@ def test_unicodeTagName(self): A L{Tag} with a C{tagName} attribute which is C{unicode} instead of C{str} is flattened to an XML representation. """ - self.assertStringEqual(self.flatten(Tag(u'div')), "
") - self.assertStringEqual(self.flatten(Tag(u'div')['']), "
") + self.assertStringEqual(self.flatten(Tag('div')), "
") + self.assertStringEqual(self.flatten(Tag('div')['']), "
") def test_unicodeAttributeName(self): @@ -313,7 +317,7 @@ def test_unicodeAttributeName(self): is flattened to an XML representation. """ self.assertStringEqual( - self.flatten(Tag(u'div', {u'foo': 'bar'})), '
') + self.flatten(Tag('div', {'foo': 'bar'})), '
') def test_stringTagAttributes(self): @@ -529,8 +533,8 @@ def test_renderAttributedNestedInRenderResult(self): replaced with the return value of the named renderer on the L{IRenderable} which had the render method which returned the L{Tag}. """ + @implementer(IRenderable) class TwoRenderers(object): - implements(IRenderable) def renderer(self, name): return getattr(self, name) @@ -573,8 +577,8 @@ def test_renderMethodReturnsInputTag(self): If a render method returns the tag it was passed, the tag is flattened as though it did not have a render directive. """ + @implementer(IRenderable) class IdempotentRenderable(object): - implements(IRenderable) def renderer(self, name): return getattr(self, name) @@ -820,7 +824,7 @@ def test_deeplyNestedList(self): significantly greater than the Python maximum recursion limit. """ obj = ["foo"] - for i in xrange(1000): + for i in range(1000): obj = [obj] self._nestingTest(obj, "foo") @@ -831,7 +835,7 @@ def test_deeplyNestedSlot(self): significantly greater than the Python maximum recursion limit. """ tag = div()[slot("foo-0")] - for i in xrange(1000): + for i in range(1000): tag.fillSlots("foo-" + str(i), slot("foo-" + str(i + 1))) tag.fillSlots("foo-1000", "bar") self._nestingTest(tag, "
bar
") @@ -844,7 +848,7 @@ def test_deeplyNestedTag(self): """ n = 1000 tag = div["foo"] - for i in xrange(n - 1): + for i in range(n - 1): tag = div[tag] self._nestingTest(tag, "
" * n + "foo" + "
" * n) @@ -855,7 +859,7 @@ def test_deeplyNestedRenderables(self): nesting significantly greater than the Python maximum recursion limit. """ obj = TrivialRenderable("foo") - for i in xrange(1000): + for i in range(1000): obj = TrivialRenderable(obj) self._nestingTest(obj, "foo") @@ -919,8 +923,8 @@ def test_flattenExceptionStack(self): def broken(): raise RuntimeError("foo") + @implementer(IRenderable) class BrokenRenderable(object): - implements(IRenderable) def render(self, request): # insert another stack frame before the exception @@ -935,8 +939,8 @@ def render(self, request): # There are probably some frames above this, but I don't care what # they are. exc._traceback[-2:], - [(HERE, 927, 'render', 'broken()'), - (HERE, 920, 'broken', 'raise RuntimeError("foo")')]) + [(HERE, 931, 'render', 'broken()'), + (HERE, 924, 'broken', 'raise RuntimeError("foo")')]) @@ -971,17 +975,17 @@ def test_unicode(self): """ self.assertEqual( str(FlattenerError( - RuntimeError("reason"), [u'abc\N{SNOWMAN}xyz'], [])), + RuntimeError("reason"), ['abc\N{SNOWMAN}xyz'], [])), "Exception while flattening:\n" - " u'abc\\u2603xyz'\n" # Codepoint for SNOWMAN + " 'abc\u2603xyz'\n" # Codepoint for SNOWMAN "RuntimeError: reason\n") self.assertEqual( str(FlattenerError( - RuntimeError("reason"), [u'01234567\N{SNOWMAN}9' * 10], + RuntimeError("reason"), ['01234567\N{SNOWMAN}9' * 10], [])), "Exception while flattening:\n" - " u'01234567\\u2603901234567\\u26039<...>01234567\\u2603901234567" - "\\u26039'\n" + " '01234567\u2603901234567\u26039<...>01234567\u2603901234567" + "\u26039'\n" "RuntimeError: reason\n") @@ -991,8 +995,8 @@ def test_renderable(self): the repr of that object is included in the string representation of the exception. """ + @implementer(IRenderable) class Renderable(object): - implements(IRenderable) def __repr__(self): return "renderable repr" @@ -1048,22 +1052,23 @@ def g(): try: f() - except RuntimeError, exc: + except RuntimeError as exc: # Get the traceback, minus the info for *this* frame tbinfo = traceback.extract_tb(sys.exc_info()[2])[1:] + excStr = str(FlattenerError(exc, [], tbinfo)) else: self.fail("f() must raise RuntimeError") self.assertEqual( - str(FlattenerError(exc, [], tbinfo)), + excStr, "Exception while flattening:\n" " File \"%s\", line %d, in f\n" " g()\n" " File \"%s\", line %d, in g\n" " raise RuntimeError(\"reason\")\n" "RuntimeError: reason\n" % ( - HERE, f.func_code.co_firstlineno + 1, - HERE, g.func_code.co_firstlineno + 1)) + HERE, f.__code__.co_firstlineno + 1, + HERE, g.__code__.co_firstlineno + 1)) @@ -1150,8 +1155,8 @@ def test_renderableException(self): """ class TestException(Exception): pass + @implementer(IRenderable) class BrokenRenderable(object): - implements(IRenderable) def render(self, request): raise TestException() @@ -1234,8 +1239,8 @@ def test_manySynchronousDeferreds(self): frames allowed by the Python recursion limit succeeds if all the L{Deferred}s have results already. """ - results = [str(i) for i in xrange(1000)] - deferreds = map(succeed, results) + results = [str(i) for i in range(1000)] + deferreds = list(map(succeed, results)) limit = sys.getrecursionlimit() sys.setrecursionlimit(100) try: diff --git a/nevow/test/test_nit.py b/nevow/test/test_nit.py index 799c99de..8724be1b 100644 --- a/nevow/test/test_nit.py +++ b/nevow/test/test_nit.py @@ -15,7 +15,7 @@ from nevow.livetrial.runner import TestFrameworkRoot from nevow.scripts import nit -MESSAGE = u'I am an error' +MESSAGE = b'I am an error' diff --git a/nevow/test/test_passobj.py b/nevow/test/test_passobj.py index a7a8e956..6dd967e9 100644 --- a/nevow/test/test_passobj.py +++ b/nevow/test/test_passobj.py @@ -2,14 +2,14 @@ # See LICENSE for details. import formless -from zope.interface import implements +from zope.interface import implementer class IBar(formless.TypedInterface): bar = formless.String() +@implementer(IBar) class Bar: - implements(IBar) def __init__(self, bar): self.bar = bar @@ -22,8 +22,8 @@ class IFrob(formless.TypedInterface): integer = formless.Integer() +@implementer(IFrob) class Frob: - implements(IFrob) def __init__(self, integer): self.integer = integer @@ -55,8 +55,8 @@ def frobber(frobber=formless.Object(interface=IFrob), frobee=formless.Object(IFr someList = formless.List() +@implementer(IObjectTest) class ObjectTester: - implements(IObjectTest) def __init__(self): self.someList = [ @@ -65,7 +65,7 @@ def __init__(self): ] def someMethod(self, one, two): - print "ONE TWO", `one`, `two` + print("ONE TWO", repr(one), repr(two)) def frobber(self, frobber, frobee): return frobber.frobazz(frobee) @@ -145,8 +145,8 @@ def compoundChecker( compoundChecker = formless.autocallable(compoundChecker) +@implementer(IAnotherTest) class AnotherTest: - implements(IAnotherTest) def aBarMethod(self, abar): return "You passed me %s" % abar @@ -184,8 +184,8 @@ def remove(self, removal): del debugInstance.breaks[removal.fn] list.remove(self, removal) class Dummy(formless.TypedInterface): pass + @implementer(Dummy) class BP: - implements(Dummy) def __init__(self, fn, ln): self.fn=fn self.ln=ln @@ -193,7 +193,7 @@ def __str__(self): return "Breakpoint in file %s at line %s" % (self.fn, self.ln) breakpoints = BreakpointRemover() - for fn in debugInstance.breaks.keys(): + for fn in list(debugInstance.breaks.keys()): for lineno in debugInstance.breaks[fn]: breakpoints.append(BP(fn, lineno)) return breakpoints diff --git a/nevow/test/test_query.py b/nevow/test/test_query.py index 0b39c367..26aaca4a 100644 --- a/nevow/test/test_query.py +++ b/nevow/test/test_query.py @@ -172,7 +172,7 @@ def test_contextTagQuery(self): T.pattern = "outer" C = context.WovenContext(tag=T) new = IQ(C).onePattern('outer') - self.assertEquals(new.tagName, 'html') + self.assertEqual(new.tagName, 'html') def test_listNotEnough(self): P = flat.precompile(notEnough) @@ -189,11 +189,11 @@ def test_loaderNotEnough(self): class TestAll(testutil.TestCase): def verify(self, them): them = list(them) - self.assertEquals(len(them), 2) - self.assertEquals(them[0].tagName, 'div') - self.assertEquals(them[1].tagName, 'span') - self.assertEquals(them[0].attributes['bar'], 'one') - self.assertEquals(them[1].attributes['bar'], 'two') + self.assertEqual(len(them), 2) + self.assertEqual(them[0].tagName, 'div') + self.assertEqual(them[1].tagName, 'span') + self.assertEqual(them[0].attributes['bar'], 'one') + self.assertEqual(them[1].attributes['bar'], 'two') def testTagPatterns(self): self.verify( @@ -218,14 +218,14 @@ def verify(self, it): two = it(color="blue") three = it(color="green") four = it(color="orange") - self.assertEquals(one.attributes['color'], 'red') - self.assertEquals(one.attributes['bar'], 'one') - self.assertEquals(two.attributes['color'], 'blue') - self.assertEquals(two.attributes['bar'], 'two') - self.assertEquals(three.attributes['color'], 'green') - self.assertEquals(three.attributes['bar'], 'one') - self.assertEquals(four.attributes['color'], 'orange') - self.assertEquals(four.attributes['bar'], 'two') + self.assertEqual(one.attributes['color'], 'red') + self.assertEqual(one.attributes['bar'], 'one') + self.assertEqual(two.attributes['color'], 'blue') + self.assertEqual(two.attributes['bar'], 'two') + self.assertEqual(three.attributes['color'], 'green') + self.assertEqual(three.attributes['bar'], 'one') + self.assertEqual(four.attributes['color'], 'orange') + self.assertEqual(four.attributes['bar'], 'two') def testTagGenerators(self): self.verify( @@ -258,14 +258,14 @@ def testTagMissing(self): def testClonableDefault(self): orig = tags.p["Hello"] gen = IQ(flat.precompile(notEnough)).patternGenerator('foo', orig) - new = gen.next() - self.assertEquals(new.tagName, 'p') + new = next(gen) + self.assertEqual(new.tagName, 'p') self.assertNotIdentical(orig, new) def testNonClonableDefault(self): gen = IQ(flat.precompile(notEnough)).patternGenerator('foo', 'bar') - new = gen.next() - self.assertEquals(new, 'bar') + new = next(gen) + self.assertEqual(new, 'bar') def testXmlMissing(self): self.assertRaises(stan.NodeNotFound, IQ(stan.xml('hello')).patternGenerator, 'foo') @@ -277,5 +277,5 @@ def test_listOfTagPatternGenerator(self): the tag has a matching pattern special. """ patterns = IQ([tags.div(pattern="foo", bar="baz")]).patternGenerator("foo") - for i in xrange(3): - self.assertEqual(patterns.next().attributes['bar'], "baz") + for i in range(3): + self.assertEqual(patterns.__next__().attributes['bar'], "baz") diff --git a/nevow/test/test_rend.py b/nevow/test/test_rend.py index 63ca74be..49e2eb23 100644 --- a/nevow/test/test_rend.py +++ b/nevow/test/test_rend.py @@ -1,7 +1,7 @@ # Copyright (c) 2004 Divmod. # See LICENSE for details. -from zope.interface import implements, Interface +from zope.interface import implementer, Interface from twisted.internet import defer from twisted.trial import unittest @@ -38,6 +38,7 @@ def deferredRender(res, request=None): tag=request))) def done(result): + assert not isinstance(result, bytes) if isinstance(result, str): request.write(result) request.d.callback(request.accumulator) @@ -52,12 +53,7 @@ def test_simple(self): xhtml = '' r = rend.Page(docFactory=loaders.htmlstr(xhtml)) return deferredRender(r).addCallback( - lambda result: self.assertEquals(result, xhtml)) - test_simple.suppress = [ - SUPPRESS(message= - r"\[v0.8\] htmlstr is deprecated because it's buggy. " - "Please start using xmlfile and/or xmlstr.")] - + lambda result: self.assertEqual(result, util.toBytes(xhtml))) def test_extend(self): @@ -66,7 +62,7 @@ class R(rend.Page): docFactory = loaders.htmlstr(xhtml) r = R() return deferredRender(r).addCallback( - lambda result: self.assertEquals(result, xhtml)) + lambda result: self.assertEqual(result, util.toBytes(xhtml))) test_extend.suppress = [ SUPPRESS(message= r"\[v0.8\] htmlstr is deprecated because it's buggy. " @@ -75,7 +71,7 @@ class R(rend.Page): def test_data(self): xhtml = ( - '