Ticket #6833: amp-python3-6822-3.1.patch

File amp-python3-6822-3.1.patch, 88.5 KB (added by Gavin Panella, 4 years ago)
  • twisted/protocols/amp.py

    diff --git a/twisted/protocols/amp.py b/twisted/protocols/amp.py
    index a744882..35a81b6 100644
    a b has several features: 
    171171      which always issue NUL as the first byte.
    172172"""
    173173
     174from __future__ import unicode_literals
     175
    174176__metaclass__ = type
    175177
    176178import types, warnings
    177179
    178 from cStringIO import StringIO
     180from io import BytesIO
    179181from struct import pack
    180182import decimal, datetime
     183from functools import partial
    181184from itertools import count
    182185
    183 from zope.interface import Interface, implements
     186from zope.interface import Interface, implementer
    184187
    185188from twisted.python.reflect import accumulateClassDict
    186189from twisted.python.failure import Failure
    from twisted.internet.error import PeerVerifyError, ConnectionLost 
    196199from twisted.internet.error import ConnectionClosed
    197200from twisted.internet.defer import Deferred, maybeDeferred, fail
    198201from twisted.protocols.basic import Int16StringReceiver, StatefulStringProtocol
     202from twisted.python.compat import (
     203    iteritems, unicode, nativeString, intToBytes, _PY3, long,
     204)
    199205
    200206try:
    201207    from twisted.internet import ssl
    __all__ = [ 
    269275
    270276
    271277
    272 ASK = '_ask'
    273 ANSWER = '_answer'
    274 COMMAND = '_command'
    275 ERROR = '_error'
    276 ERROR_CODE = '_error_code'
    277 ERROR_DESCRIPTION = '_error_description'
    278 UNKNOWN_ERROR_CODE = 'UNKNOWN'
    279 UNHANDLED_ERROR_CODE = 'UNHANDLED'
     278ASK = b'_ask'
     279ANSWER = b'_answer'
     280COMMAND = b'_command'
     281ERROR = b'_error'
     282ERROR_CODE = b'_error_code'
     283ERROR_DESCRIPTION = b'_error_description'
     284UNKNOWN_ERROR_CODE = b'UNKNOWN'
     285UNHANDLED_ERROR_CODE = b'UNHANDLED'
    280286
    281287MAX_KEY_LENGTH = 0xff
    282288MAX_VALUE_LENGTH = 0xffff
    283289
    284290
     291
    285292class IArgumentType(Interface):
    286293    """
    287294    An L{IArgumentType} can serialize a Python object into an AMP box and
    class IArgumentType(Interface): 
    295302        extract one or more Python objects and add them to the C{objects}
    296303        dictionary.
    297304
    298         @param name: The name associated with this argument.  Most commonly,
     305        @param name: The name associated with this argument. Most commonly
    299306            this is the key which can be used to find a serialized value in
    300             C{strings} and which should be used as the key in C{objects} to
    301             associate with a structured Python object.
    302         @type name: C{str}
     307            C{strings}.
     308        @type name: C{bytes}
    303309
    304310        @param strings: The AMP box from which to extract one or more
    305311            values.
    306312        @type strings: C{dict}
    307313
    308314        @param objects: The output dictionary to populate with the value for
    309             this argument.
     315            this argument. The key used will be derived from C{name}. It may
     316            differ; in Python 3, for example, the key will be a Unicode/native
     317            string. See L{_wireNameToPythonIdentifier}.
    310318        @type objects: C{dict}
    311319
    312320        @param proto: The protocol instance which received the AMP box being
    class IArgumentType(Interface): 
    323331        objects, serialize values into one or more strings and add them to
    324332        the C{strings} dictionary.
    325333
    326         @param name: The name associated with this argument.  Most commonly,
    327             this is the key which can be used to find an object in
    328             C{objects} and which should be used as the key in C{strings} to
    329             associate with a C{str} giving the serialized form of that
    330             object.
    331         @type name: C{str}
     334        @param name: The name associated with this argument. Most commonly
     335            this is the key in C{strings} to associate with a C{bytes} giving
     336            the serialized form of that object.
     337        @type name: C{bytes}
    332338
    333         @param strings: The AMP box into which to insert one or more
    334             strings.
     339        @param strings: The AMP box into which to insert one or more strings.
    335340        @type strings: C{dict}
    336341
    337342        @param objects: The input dictionary from which to extract Python
    338             objects to serialize.
     343            objects to serialize. The key used will be derived from C{name}.
     344            It may differ; in Python 3, for example, the key will be a
     345            Unicode/native string. See L{_wireNameToPythonIdentifier}.
    339346        @type objects: C{dict}
    340347
    341348        @param proto: The protocol instance which will send the AMP box once
    class IResponderLocator(Interface): 
    415422
    416423        @param name: the wire-level name (commandName) of the AMP command to be
    417424        responded to.
     425        @type name: C{bytes}
    418426
    419427        @return: a 1-argument callable that takes an L{AmpBox} with argument
    420428        values for the given command, and returns an L{AmpBox} containing
    class RemoteAmpError(AmpError): 
    522530        """Create a remote error with an error code and description.
    523531
    524532        @param errorCode: the AMP error code of this error.
     533        @type errorCode: C{bytes}
    525534
    526535        @param description: some text to show to the user.
     536        @type description: C{str}
    527537
    528538        @param fatal: a boolean, true if this error should terminate the
    529539        connection.
    class RemoteAmpError(AmpError): 
    536546        else:
    537547            localwhat = ''
    538548            othertb = ''
    539         Exception.__init__(self, "Code<%s>%s: %s%s" % (
    540                 errorCode, localwhat,
    541                 description, othertb))
     549
     550        # Backslash-escape errorCode. Python 3.5 can do this natively
     551        # ("backslashescape") but Python 2.7 and Python 3.4 can't.
     552        if _PY3:
     553            errorCodeForMessage = "".join(
     554                "\\x%2x" % c if c >= 0x80 else chr(c)
     555                for c in errorCode)
     556        else:
     557            errorCodeForMessage = "".join(
     558                "\\x%2x" % ord(c) if ord(c) >= 0x80 else c
     559                for c in errorCode)
     560
     561        if othertb:
     562            message = "Code<%s>%s: %s\n%s" % (
     563                errorCodeForMessage, localwhat, description, othertb)
     564        else:
     565            message = "Code<%s>%s: %s" % (
     566                errorCodeForMessage, localwhat, description)
     567
     568        super(RemoteAmpError, self).__init__(message)
    542569        self.local = local
    543570        self.errorCode = errorCode
    544571        self.description = description
    PROTOCOL_ERRORS = {UNHANDLED_ERROR_CODE: UnhandledCommand} 
    582609
    583610class AmpBox(dict):
    584611    """
    585     I am a packet in the AMP protocol, much like a regular str:str dictionary.
     612    I am a packet in the AMP protocol, much like a regular bytes:bytes dictionary.
    586613    """
    587614    __slots__ = []              # be like a regular dictionary, don't magically
    588615                                # acquire a __dict__...
    589616
    590617
     618    def __init__(self, *args, **kw):
     619        """
     620        Initialize a new L{AmpBox}.
     621
     622        In Python 3, keyword arguments MUST be Unicode/native strings whereas
     623        in Python 2 they could be either byte strings or Unicode strings.
     624
     625        However, all keys of an L{AmpBox} MUST be byte strings, or possible to
     626        transparently coerce into byte strings (i.e. Python 2).
     627
     628        In Python 3, therefore, native string keys are coerced to byte strings
     629        by encoding as ASCII. This can result in C{UnicodeEncodeError} being
     630        raised.
     631
     632        @param args: See C{dict}, but all keys and values should be C{bytes}.
     633            On Python 3, native strings may be used as keys provided they
     634            contain only ASCII characters.
     635
     636        @param kw: See C{dict}, but all keys and values should be C{bytes}.
     637            On Python 3, native strings may be used as keys provided they
     638            contain only ASCII characters.
     639
     640        @raise UnicodeEncodeError: When a native string key cannot be coerced
     641            to an ASCII byte string (Python 3 only).
     642        """
     643        super(AmpBox, self).__init__(*args, **kw)
     644        if _PY3:
     645            nonByteNames = [n for n in self if not isinstance(n, bytes)]
     646            for nonByteName in nonByteNames:
     647                byteName = nonByteName.encode("ascii")
     648                self[byteName] = self.pop(nonByteName)
     649
     650
    591651    def copy(self):
    592652        """
    593653        Return another AmpBox just like me.
    class AmpBox(dict): 
    601661        """
    602662        Convert me into a wire-encoded string.
    603663
    604         @return: a str encoded according to the rules described in the module
    605         docstring.
     664        @return: a C{bytes} encoded according to the rules described in the
     665            module docstring.
    606666        """
    607         i = self.items()
    608         i.sort()
     667        i = sorted(iteritems(self))
    609668        L = []
    610669        w = L.append
    611670        for k, v in i:
    class AmpBox(dict): 
    622681                w(pack("!H", len(kv)))
    623682                w(kv)
    624683        w(pack("!H", 0))
    625         return ''.join(L)
     684        return b''.join(L)
    626685
    627686
    628687    def _sendTo(self, proto):
    class _SwitchBox(AmpBox): 
    703762
    704763
    705764
     765@implementer(IBoxReceiver)
    706766class BoxDispatcher:
    707767    """
    708768    A L{BoxDispatcher} dispatches '_ask', '_answer', and '_error' L{AmpBox}es,
    class BoxDispatcher: 
    728788    @type boxSender: L{IBoxSender}
    729789    """
    730790
    731     implements(IBoxReceiver)
    732 
    733791    _failAllReason = None
    734792    _outstandingRequests = None
    735     _counter = 0L
     793    _counter = long(0)
    736794    boxSender = None
    737795
    738796    def __init__(self, locator):
    class BoxDispatcher: 
    778836        @return: a string that has not yet been used on this connection.
    779837        """
    780838        self._counter += 1
    781         return '%x' % (self._counter,)
     839        if _PY3:
     840            # Python 3.4 cannot do % interpolation on byte strings so we must
     841            # work with a Unicode string and then encode.
     842            return (u'%x' % (self._counter,)).encode("ascii")
     843        else:
     844            return (b'%x' % (self._counter,))
    782845
    783846
    784847    def _sendBoxCommand(self, command, box, requiresAnswer=True):
    class BoxDispatcher: 
    795858        If the Deferred fails and the error is not handled by the caller of
    796859        this method, the failure will be logged and the connection dropped.
    797860
    798         @param command: a str, the name of the command to issue.
     861        @param command: a C{bytes}, the name of the command to issue.
    799862
    800863        @param box: an AmpBox with the arguments for the command.
    801864
    class BoxDispatcher: 
    827890        This is a low-level API, designed only for optimizing simple messages
    828891        for which the overhead of parsing is too great.
    829892
    830         @param command: a str naming the command.
     893        @param command: a C{bytes} naming the command.
    831894
    832895        @param kw: arguments to the amp box.
    833896
    class BoxDispatcher: 
    918981        question.addErrback(self.unhandledError)
    919982        errorCode = box[ERROR_CODE]
    920983        description = box[ERROR_DESCRIPTION]
     984        if isinstance(description, bytes):
     985            description = description.decode("utf-8", "replace")
    921986        if errorCode in PROTOCOL_ERRORS:
    922987            exc = PROTOCOL_ERRORS[errorCode](errorCode, description)
    923988        else:
    class BoxDispatcher: 
    9371002            if error.check(RemoteAmpError):
    9381003                code = error.value.errorCode
    9391004                desc = error.value.description
     1005                if isinstance(desc, unicode):
     1006                    desc = desc.encode("utf-8", "replace")
    9401007                if error.value.fatal:
    9411008                    errorBox = QuitBox()
    9421009                else:
    class BoxDispatcher: 
    9461013                log.err(error) # here is where server-side logging happens
    9471014                               # if the error isn't handled
    9481015                code = UNKNOWN_ERROR_CODE
    949                 desc = "Unknown Error"
     1016                desc = b"Unknown Error"
    9501017            errorBox[ERROR] = box[ASK]
    9511018            errorBox[ERROR_DESCRIPTION] = desc
    9521019            errorBox[ERROR_CODE] = code
    class BoxDispatcher: 
    10031070        cmd = box[COMMAND]
    10041071        responder = self.locator.locateResponder(cmd)
    10051072        if responder is None:
     1073            description = "Unhandled Command: %r" % (cmd,)
    10061074            return fail(RemoteAmpError(
    10071075                    UNHANDLED_ERROR_CODE,
    1008                     "Unhandled Command: %r" % (cmd,),
     1076                    description,
    10091077                    False,
    10101078                    local=Failure(UnhandledCommand())))
    10111079        return maybeDeferred(responder, box)
    10121080
    10131081
    10141082
     1083@implementer(IResponderLocator)
    10151084class CommandLocator:
    10161085    """
    10171086    A L{CommandLocator} is a collection of responders to AMP L{Command}s, with
    class CommandLocator: 
    10591128            return subcls
    10601129
    10611130
    1062     implements(IResponderLocator)
    1063 
    1064 
    10651131    def _wrapWithSerialization(self, aCallable, command):
    10661132        """
    10671133        Wrap aCallable with its command's argument de-serialization
    class CommandLocator: 
    11211187        Locate a callable to invoke when executing the named command.
    11221188
    11231189        @param name: the normalized name (from the wire) of the command.
     1190        @type name: C{bytes}
    11241191
    11251192        @return: a 1-argument function that takes a Box and returns a box or a
    11261193        Deferred which fires a Box, for handling the command identified by the
    class CommandLocator: 
    11311198        cd = self._commandDispatch
    11321199        if name in cd:
    11331200            commandClass, responderFunc = cd[name]
    1134             responderMethod = types.MethodType(
    1135                 responderFunc, self, self.__class__)
     1201            if _PY3:
     1202                responderMethod = types.MethodType(
     1203                    responderFunc, self)
     1204            else:
     1205                responderMethod = types.MethodType(
     1206                    responderFunc, self, self.__class__)
    11361207            return self._wrapWithSerialization(responderMethod, commandClass)
    11371208
    11381209
    11391210
     1211if _PY3:
     1212    # Python 3 ignores the __metaclass__ attribute and has instead new syntax
     1213    # for setting the metaclass. Unfortunately it's not valid Python 2 syntax
     1214    # so we work-around it by recreating CommandLocator using the metaclass
     1215    # here.
     1216    CommandLocator = CommandLocator.__metaclass__(
     1217        "CommandLocator", (CommandLocator, ), {})
     1218
     1219
     1220
     1221@implementer(IResponderLocator)
    11401222class SimpleStringLocator(object):
    11411223    """
    11421224    Implement the L{locateResponder} method to do simple, string-based
    11431225    dispatch.
    11441226    """
    11451227
    1146     implements(IResponderLocator)
    1147 
    1148     baseDispatchPrefix = 'amp_'
     1228    baseDispatchPrefix = b'amp_'
    11491229
    11501230    def locateResponder(self, name):
    11511231        """
    class SimpleStringLocator(object): 
    11561236        L{AmpBox} itself as an argument.
    11571237
    11581238        @param name: the normalized name (from the wire) of the command.
     1239        @type name: C{bytes}
    11591240        """
    1160         fName = self.baseDispatchPrefix + (name.upper())
     1241        fName = nativeString(self.baseDispatchPrefix + name.upper())
    11611242        return getattr(self, fName, None)
    11621243
    11631244
    def _wireNameToPythonIdentifier(key): 
    11881269    implemented in a lisp amp dialect may use dashes in argument or command
    11891270    names.
    11901271
    1191     @param key: a str, looking something like 'foo-bar-baz' or 'from'
     1272    @param key: a C{bytes}, looking something like 'foo-bar-baz' or 'from'
     1273    @type key: C{bytes}
    11921274
    1193     @return: a str which is a valid python identifier, looking something like
    1194     'foo_bar_baz' or 'From'.
     1275    @return: a native string which is a valid python identifier, looking
     1276    something like 'foo_bar_baz' or 'From'.
    11951277    """
    1196     lkey = key.replace("-", "_")
     1278    lkey = nativeString(key.replace(b"-", b"_"))
    11971279    if lkey in PYTHON_KEYWORDS:
    11981280        return lkey.title()
    11991281    return lkey
    12001282
    12011283
    12021284
     1285@implementer(IArgumentType)
    12031286class Argument:
    12041287    """
    12051288    Base-class of all objects that take values from Amp packets and convert
    class Argument: 
    12101293    which will be used to define the behavior of L{IArgumentType.toBox} and
    12111294    L{IArgumentType.fromBox}, respectively.
    12121295    """
    1213     implements(IArgumentType)
    12141296
    12151297    optional = False
    12161298
    class Argument: 
    12541336        decoded from an 'in' AmpBox mapping strings to string values.
    12551337
    12561338        @param name: the argument name to retrieve
    1257         @type name: str
     1339        @type name: C{bytes}
    12581340
    12591341        @param strings: The AmpBox to read string(s) from, a mapping of
    12601342        argument names to string values.
    12611343        @type strings: AmpBox
    12621344
    12631345        @param objects: The dictionary to write object(s) to, a mapping of
    1264         names to Python objects.
     1346        names to Python objects. Keys will be native strings.
    12651347        @type objects: dict
    12661348
    12671349        @param proto: an AMP instance.
    class Argument: 
    12801362        mapping names to Python values.
    12811363
    12821364        @param name: the argument name to retrieve
    1283         @type name: str
     1365        @type name: C{bytes}
    12841366
    12851367        @param strings: The AmpBox to write string(s) to, a mapping of
    12861368        argument names to string values.
    12871369        @type strings: AmpBox
    12881370
    12891371        @param objects: The dictionary to read object(s) from, a mapping of
    1290         names to Python objects.
     1372        names to Python objects. Keys should be native strings.
    12911373
    12921374        @type objects: dict
    12931375
    class Argument: 
    13071389        Convert a string to a Python value.
    13081390
    13091391        @param inString: the string to convert.
     1392        @type inString: C{bytes}
    13101393
    13111394        @param proto: the protocol we are converting for.
    13121395        @type proto: AMP
    class Argument: 
    13331416        Convert a string to a Python object.  Subclasses must implement this.
    13341417
    13351418        @param inString: the string to convert.
    1336         @type inString: str
     1419        @type inString: C{bytes}
    13371420
    1338         @return: the decoded value from inString
     1421        @return: the decoded value from L{inString}
    13391422        """
    13401423
    13411424
    class Argument: 
    13471430        to deal with.
    13481431
    13491432        @return: the wire encoding of inObject
    1350         @rtype: str
     1433        @rtype: C{bytes}
    13511434        """
    13521435
    13531436
    class Integer(Argument): 
    13611444    """
    13621445    fromString = int
    13631446    def toString(self, inObject):
    1364         return str(int(inObject))
     1447        return intToBytes(inObject)
    13651448
    13661449
    13671450
    class String(Argument): 
    13721455    def toString(self, inObject):
    13731456        return inObject
    13741457
    1375 
    13761458    def fromString(self, inString):
    13771459        return inString
    13781460
    class Boolean(Argument): 
    13921474    Encode True or False as "True" or "False" on the wire.
    13931475    """
    13941476    def fromString(self, inString):
    1395         if inString == 'True':
     1477        if inString == b'True':
    13961478            return True
    1397         elif inString == 'False':
     1479        elif inString == b'False':
    13981480            return False
    13991481        else:
    14001482            raise TypeError("Bad boolean value: %r" % (inString,))
    class Boolean(Argument): 
    14021484
    14031485    def toString(self, inObject):
    14041486        if inObject:
    1405             return 'True'
     1487            return b'True'
    14061488        else:
    1407             return 'False'
     1489            return b'False'
    14081490
    14091491
    14101492
    class Unicode(String): 
    14141496    """
    14151497
    14161498    def toString(self, inObject):
    1417         # assert isinstance(inObject, unicode)
    14181499        return String.toString(self, inObject.encode('utf-8'))
    14191500
    14201501
    14211502    def fromString(self, inString):
    1422         # assert isinstance(inString, str)
    14231503        return String.fromString(self, inString).decode('utf-8')
    14241504
    14251505
    class Path(Unicode): 
    14381518
    14391519
    14401520    def toString(self, inObject):
    1441         return Unicode.toString(self, inObject.path)
     1521        return Unicode.toString(self, inObject.asTextMode().path)
    14421522
    14431523
    14441524
    class ListOf(Argument): 
    14831563        parser = Int16StringReceiver()
    14841564        parser.stringReceived = strings.append
    14851565        parser.dataReceived(inString)
    1486         return map(self.elementType.fromString, strings)
     1566        elementFromString = self.elementType.fromString
     1567        return [elementFromString(string) for string in strings]
    14871568
    14881569
    14891570    def toString(self, inObject):
    class ListOf(Argument): 
    14951576            serialized = self.elementType.toString(obj)
    14961577            strings.append(pack('!H', len(serialized)))
    14971578            strings.append(serialized)
    1498         return ''.join(strings)
     1579        return b''.join(strings)
    14991580
    15001581
    15011582
    class AmpList(Argument): 
    15181599
    15191600        @param subargs: a list of 2-tuples of ('name', argument) describing the
    15201601        schema of the dictionaries in the sequence of amp boxes.
     1602        @type subargs: A C{list} of (C{bytes}, L{Argument}) tuples.
    15211603
    15221604        @param optional: a boolean indicating whether this argument can be
    15231605        omitted in the protocol.
    15241606        """
     1607        assert all(isinstance(name, bytes) for name, _ in subargs), (
     1608            "AmpList should be defined with a list of (name, argument) "
     1609            "tuples where `name' is a byte string, got: %r" % (subargs, ))
    15251610        self.subargs = subargs
    15261611        Argument.__init__(self, optional)
    15271612
    class AmpList(Argument): 
    15341619
    15351620
    15361621    def toStringProto(self, inObject, proto):
    1537         return ''.join([_objectsToStrings(
     1622        return b''.join([_objectsToStrings(
    15381623                    objects, self.subargs, Box(), proto
    15391624                    ).serialize() for objects in inObject])
    15401625
    class Command: 
    16561741            reverseErrors = attrs['reverseErrors'] = {}
    16571742            er = attrs['allErrors'] = {}
    16581743            if 'commandName' not in attrs:
    1659                 attrs['commandName'] = name
     1744                if _PY3:
     1745                    attrs['commandName'] = name.encode("ascii")
     1746                else:
     1747                    attrs['commandName'] = name
    16601748            newtype = type.__new__(cls, name, bases, attrs)
     1749
     1750            if not isinstance(newtype.commandName, bytes):
     1751                raise TypeError(
     1752                    "Command names must be byte strings, got: %r"
     1753                    % (newtype.commandName, ))
     1754            for name, _ in newtype.arguments:
     1755                if not isinstance(name, bytes):
     1756                    raise TypeError(
     1757                        "Argument names must be byte strings, got: %r"
     1758                        % (name, ))
     1759            for name, _ in newtype.response:
     1760                if not isinstance(name, bytes):
     1761                    raise TypeError(
     1762                        "Response names must be byte strings, got: %r"
     1763                        % (name, ))
     1764
    16611765            errors = {}
    16621766            fatalErrors = {}
    16631767            accumulateClassDict(newtype, 'errors', errors)
    16641768            accumulateClassDict(newtype, 'fatalErrors', fatalErrors)
    1665             for v, k in errors.iteritems():
     1769
     1770            if not isinstance(newtype.errors, dict):
     1771                newtype.errors = dict(newtype.errors)
     1772            if not isinstance(newtype.fatalErrors, dict):
     1773                newtype.fatalErrors = dict(newtype.fatalErrors)
     1774
     1775            for v, k in iteritems(errors):
    16661776                reverseErrors[k] = v
    16671777                er[v] = k
    1668             for v, k in fatalErrors.iteritems():
     1778            for v, k in iteritems(fatalErrors):
    16691779                reverseErrors[k] = v
    16701780                er[v] = k
     1781
     1782            for _, name in iteritems(newtype.errors):
     1783                if not isinstance(name, bytes):
     1784                    raise TypeError(
     1785                        "Error names must be byte strings, got: %r"
     1786                        % (name, ))
     1787            for _, name in iteritems(newtype.fatalErrors):
     1788                if not isinstance(name, bytes):
     1789                    raise TypeError(
     1790                        "Fatal error names must be byte strings, got: %r"
     1791                        % (name, ))
     1792
    16711793            return newtype
    16721794
    16731795    arguments = []
    class Command: 
    16871809        Create an instance of this command with specified values for its
    16881810        parameters.
    16891811
     1812        In Python 3, keyword arguments MUST be Unicode/native strings whereas
     1813        in Python 2 they could be either byte strings or Unicode strings.
     1814
     1815        A L{Command}'s arguments are defined in its schema using C{bytes}
     1816        names. The values for those arguments are plucked from the keyword
     1817        arguments using the name returned from L{_wireNameToPythonIdentifier}.
     1818        In other words, keyword arguments should be named using the
     1819        Python-side equivalent of the on-wire (C{bytes}) name.
     1820
    16901821        @param kw: a dict containing an appropriate value for each name
    16911822        specified in the L{arguments} attribute of my class.
    16921823
    16931824        @raise InvalidSignature: if you forgot any required arguments.
    16941825        """
    16951826        self.structured = kw
    1696         givenArgs = kw.keys()
    16971827        forgotten = []
    16981828        for name, arg in self.arguments:
    16991829            pythonName = _wireNameToPythonIdentifier(name)
    1700             if pythonName not in givenArgs and not arg.optional:
     1830            if pythonName not in self.structured and not arg.optional:
    17011831                forgotten.append(pythonName)
    17021832        if forgotten:
    17031833            raise InvalidSignature("forgot %s for %s" % (
    1704                     ', '.join(forgotten), self.commandName))
     1834                ', '.join(forgotten), self.commandName))
    17051835        forgotten = []
    17061836
    17071837
    class Command: 
    18501980
    18511981
    18521982
     1983if _PY3:
     1984    # Python 3 ignores the __metaclass__ attribute and has instead new syntax
     1985    # for setting the metaclass. Unfortunately it's not valid Python 2 syntax
     1986    # so we work-around it by recreating Command using the metaclass here.
     1987    Command = Command.__metaclass__("Command", (Command, ), {})
     1988
     1989
     1990
    18531991class _NoCertificate:
    18541992    """
    18551993    This is for peers which don't want to use a local certificate.  Used by
    class _TLSBox(AmpBox): 
    19122050
    19132051    def __init__(self):
    19142052        if ssl is None:
    1915             raise RemoteAmpError("TLS_ERROR", "TLS not available")
     2053            raise RemoteAmpError(b"TLS_ERROR", "TLS not available")
    19162054        AmpBox.__init__(self)
    19172055
    19182056
    class _TLSBox(AmpBox): 
    19212059
    19222060
    19232061    # These properties are described in startTLS
    1924     certificate = _keyprop('tls_localCertificate', _NoCertificate(False))
    1925     verify = _keyprop('tls_verifyAuthorities', None)
     2062    certificate = _keyprop(b'tls_localCertificate', _NoCertificate(False))
     2063    verify = _keyprop(b'tls_verifyAuthorities', None)
    19262064
    19272065    def _sendTo(self, proto):
    19282066        """
    19292067        Send my encoded value to the protocol, then initiate TLS.
    19302068        """
    19312069        ab = AmpBox(self)
    1932         for k in ['tls_localCertificate',
    1933                   'tls_verifyAuthorities']:
     2070        for k in [b'tls_localCertificate',
     2071                  b'tls_verifyAuthorities']:
    19342072            ab.pop(k, None)
    19352073        ab._sendTo(proto)
    19362074        proto._startTLS(self.certificate, self.verify)
    class StartTLS(Command): 
    19682106    response dictionary.
    19692107    """
    19702108
    1971     arguments = [("tls_localCertificate", _LocalArgument(optional=True)),
    1972                  ("tls_verifyAuthorities", _LocalArgument(optional=True))]
     2109    arguments = [(b"tls_localCertificate", _LocalArgument(optional=True)),
     2110                 (b"tls_verifyAuthorities", _LocalArgument(optional=True))]
    19732111
    1974     response = [("tls_localCertificate", _LocalArgument(optional=True)),
    1975                 ("tls_verifyAuthorities", _LocalArgument(optional=True))]
     2112    response = [(b"tls_localCertificate", _LocalArgument(optional=True)),
     2113                (b"tls_verifyAuthorities", _LocalArgument(optional=True))]
    19762114
    19772115    responseType = _TLSBox
    19782116
    class ProtocolSwitchCommand(Command): 
    20622200
    20632201
    20642202
     2203@implementer(IFileDescriptorReceiver)
    20652204class _DescriptorExchanger(object):
    20662205    """
    20672206    L{_DescriptorExchanger} is a mixin for L{BinaryBoxProtocol} which adds
    class _DescriptorExchanger(object): 
    20842223        ordinals, starting from 0.  This is used to construct values for
    20852224        C{fileDescriptorReceived}.
    20862225    """
    2087     implements(IFileDescriptorReceiver)
    20882226
    20892227    def __init__(self):
    20902228        self._descriptors = {}
    20912229        self._getDescriptor = self._descriptors.pop
    2092         self._sendingDescriptorCounter = count().next
    2093         self._receivingDescriptorCounter = count().next
     2230        self._sendingDescriptorCounter = partial(next, count())
     2231        self._receivingDescriptorCounter = partial(next, count())
    20942232
    20952233
    20962234    def _sendFileDescriptor(self, descriptor):
    class _DescriptorExchanger(object): 
    21132251
    21142252
    21152253
     2254@implementer(IBoxSender)
    21162255class BinaryBoxProtocol(StatefulStringProtocol, Int16StringReceiver,
    21172256                        _DescriptorExchanger):
    21182257    """
    class BinaryBoxProtocol(StatefulStringProtocol, Int16StringReceiver, 
    21462285    method will be invoked for each L{AmpBox} that is received.
    21472286    """
    21482287
    2149     implements(IBoxSender)
    2150 
    21512288    _justStartedTLS = False
    21522289    _startingTLSBuffer = None
    21532290    _locked = False
    class AMP(BinaryBoxProtocol, BoxDispatcher, 
    24422579        Unify the implementations of L{CommandLocator} and
    24432580        L{SimpleStringLocator} to perform both kinds of dispatch, preferring
    24442581        L{CommandLocator}.
     2582
     2583        @type name: C{bytes}
    24452584        """
    24462585        firstResponder = CommandLocator.locateResponder(self, name)
    24472586        if firstResponder is not None:
    class _ParserHelper: 
    25472686
    25482687        @return: a list of AmpBoxes encoded in the given string.
    25492688        """
    2550         return cls.parse(StringIO(data))
     2689        return cls.parse(BytesIO(data))
    25512690    parseString = classmethod(parseString)
    25522691
    25532692
    class Decimal(Argument): 
    26302769    U{http://speleotrove.com/decimal/} should be considered the authoritative
    26312770    specification for the format.
    26322771    """
    2633     fromString = decimal.Decimal
     2772
     2773    def fromString(self, inString):
     2774        inString = nativeString(inString)
     2775        return decimal.Decimal(inString)
    26342776
    26352777    def toString(self, inObject):
    26362778        """
    class Decimal(Argument): 
    26382780        """
    26392781        if isinstance(inObject, decimal.Decimal):
    26402782            # Hopefully decimal.Decimal.__str__ actually does what we want.
    2641             return str(inObject)
     2783            return str(inObject).encode("ascii")
    26422784        raise ValueError(
    26432785            "amp.Decimal can only encode instances of decimal.Decimal")
    26442786
    class DateTime(Argument): 
    26762818        Parse a string containing a date and time in the wire format into a
    26772819        C{datetime.datetime} instance.
    26782820        """
     2821        s = nativeString(s)
     2822
    26792823        if len(s) != 32:
    26802824            raise ValueError('invalid date format %r' % (s,))
    26812825
    class DateTime(Argument): 
    27072851        # strftime has no way to format the microseconds, or put a ':' in the
    27082852        # timezone. Surprise!
    27092853
    2710         return '%04i-%02i-%02iT%02i:%02i:%02i.%06i%s%02i:%02i' % (
     2854        # Python 3.4 cannot do % interpolation on byte strings so we pack into
     2855        # an explicitly Unicode string then encode as ASCII.
     2856        packed = u'%04i-%02i-%02iT%02i:%02i:%02i.%06i%s%02i:%02i' % (
    27112857            i.year,
    27122858            i.month,
    27132859            i.day,
    class DateTime(Argument): 
    27182864            sign,
    27192865            abs(minutesOffset) // 60,
    27202866            abs(minutesOffset) % 60)
     2867
     2868        return packed.encode("ascii")
  • twisted/python/dist3.py

    diff --git a/twisted/python/dist3.py b/twisted/python/dist3.py
    index 45c46b1..9a46625 100644
    a b modules = [ 
    145145    "twisted.positioning.ipositioning",
    146146    "twisted.positioning.nmea",
    147147    "twisted.protocols",
     148    "twisted.protocols.amp",
    148149    "twisted.protocols.basic",
    149150    "twisted.protocols.policies",
    150151    "twisted.protocols.test",
    testModules = [ 
    320321    "twisted.python.test.test_versions",
    321322    "twisted.python.test.test_zippath",
    322323    "twisted.test.test_abstract",
     324    "twisted.test.test_amp",
    323325    "twisted.test.test_application",
    324326    "twisted.test.test_compat",
    325327    "twisted.test.test_context",
  • twisted/test/test_amp.py

    diff --git a/twisted/test/test_amp.py b/twisted/test/test_amp.py
    index be389ee..abc51c4 100644
    a b Tests for L{twisted.protocols.amp}. 
    99import datetime
    1010import decimal
    1111
    12 from zope.interface import implements
     12from zope.interface import implementer
    1313from zope.interface.verify import verifyClass, verifyObject
    1414
    1515from twisted.python import filepath
     16from twisted.python.compat import intToBytes
    1617from twisted.python.failure import Failure
    1718from twisted.protocols import amp
    1819from twisted.trial import unittest
    class TestProto(protocol.Protocol): 
    5354    instanceCount = 0
    5455
    5556    def __init__(self, onConnLost, dataToSend):
     57        assert isinstance(dataToSend, bytes), repr(dataToSend)
    5658        self.onConnLost = onConnLost
    5759        self.dataToSend = dataToSend
    5860        self.instanceId = TestProto.instanceCount
    class SimpleSymmetricProtocol(amp.AMP): 
    9092
    9193    def sendHello(self, text):
    9294        return self.callRemoteString(
    93             "hello",
     95            b"hello",
    9496            hello=text)
    9597
    9698    def amp_HELLO(self, box):
    97         return amp.Box(hello=box['hello'])
    98 
    99     def amp_HOWDOYOUDO(self, box):
    100         return amp.QuitBox(howdoyoudo='world')
     99        return amp.Box(hello=box[b'hello'])
    101100
    102101
    103102
    class TransportPeer(amp.Argument): 
    118117    # this serves as some informal documentation for how to get variables from
    119118    # the protocol or your environment and pass them to methods as arguments.
    120119    def retrieve(self, d, name, proto):
    121         return ''
     120        return b''
    122121
    123122    def fromStringProto(self, notAString, proto):
    124123        return proto.transport.getPeer()
    class TransportPeer(amp.Argument): 
    130129
    131130class Hello(amp.Command):
    132131
    133     commandName = 'hello'
     132    commandName = b'hello'
    134133
    135     arguments = [('hello', amp.String()),
    136                  ('optional', amp.Boolean(optional=True)),
    137                  ('print', amp.Unicode(optional=True)),
    138                  ('from', TransportPeer(optional=True)),
    139                  ('mixedCase', amp.String(optional=True)),
    140                  ('dash-arg', amp.String(optional=True)),
    141                  ('underscore_arg', amp.String(optional=True))]
     134    arguments = [(b'hello', amp.String()),
     135                 (b'optional', amp.Boolean(optional=True)),
     136                 (b'print', amp.Unicode(optional=True)),
     137                 (b'from', TransportPeer(optional=True)),
     138                 (b'mixedCase', amp.String(optional=True)),
     139                 (b'dash-arg', amp.String(optional=True)),
     140                 (b'underscore_arg', amp.String(optional=True))]
    142141
    143     response = [('hello', amp.String()),
    144                 ('print', amp.Unicode(optional=True))]
     142    response = [(b'hello', amp.String()),
     143                (b'print', amp.Unicode(optional=True))]
    145144
    146     errors = {UnfriendlyGreeting: 'UNFRIENDLY'}
     145    errors = {UnfriendlyGreeting: b'UNFRIENDLY'}
    147146
    148     fatalErrors = {DeathThreat: 'DEAD'}
     147    fatalErrors = {DeathThreat: b'DEAD'}
    149148
    150149class NoAnswerHello(Hello):
    151150    commandName = Hello.commandName
    152151    requiresAnswer = False
    153152
    154153class FutureHello(amp.Command):
    155     commandName = 'hello'
    156 
    157     arguments = [('hello', amp.String()),
    158                  ('optional', amp.Boolean(optional=True)),
    159                  ('print', amp.Unicode(optional=True)),
    160                  ('from', TransportPeer(optional=True)),
    161                  ('bonus', amp.String(optional=True)), # addt'l arguments
    162                                                        # should generally be
    163                                                        # added at the end, and
    164                                                        # be optional...
     154    commandName = b'hello'
     155
     156    arguments = [(b'hello', amp.String()),
     157                 (b'optional', amp.Boolean(optional=True)),
     158                 (b'print', amp.Unicode(optional=True)),
     159                 (b'from', TransportPeer(optional=True)),
     160                 (b'bonus', amp.String(optional=True)), # addt'l arguments
     161                                                        # should generally be
     162                                                        # added at the end, and
     163                                                        # be optional...
    165164                 ]
    166165
    167     response = [('hello', amp.String()),
    168                 ('print', amp.Unicode(optional=True))]
     166    response = [(b'hello', amp.String()),
     167                (b'print', amp.Unicode(optional=True))]
    169168
    170     errors = {UnfriendlyGreeting: 'UNFRIENDLY'}
     169    errors = {UnfriendlyGreeting: b'UNFRIENDLY'}
    171170
    172171class WTF(amp.Command):
    173172    """
    class BrokenReturn(amp.Command): 
    180179    None...
    181180    """
    182181
    183     commandName = 'broken_return'
     182    commandName = b'broken_return'
    184183
    185184class Goodbye(amp.Command):
    186185    # commandName left blank on purpose: this tests implicit command names.
    187     response = [('goodbye', amp.String())]
     186    response = [(b'goodbye', amp.String())]
    188187    responseType = amp.QuitBox
    189188
    190 class Howdoyoudo(amp.Command):
    191     commandName = 'howdoyoudo'
    192     # responseType = amp.QuitBox
    193 
    194189class WaitForever(amp.Command):
    195     commandName = 'wait_forever'
     190    commandName = b'wait_forever'
    196191
    197192class GetList(amp.Command):
    198     commandName = 'getlist'
    199     arguments = [('length', amp.Integer())]
    200     response = [('body', amp.AmpList([('x', amp.Integer())]))]
     193    commandName = b'getlist'
     194    arguments = [(b'length', amp.Integer())]
     195    response = [(b'body', amp.AmpList([(b'x', amp.Integer())]))]
    201196
    202197class DontRejectMe(amp.Command):
    203     commandName = 'dontrejectme'
     198    commandName = b'dontrejectme'
    204199    arguments = [
    205             ('magicWord', amp.Unicode()),
    206             ('list', amp.AmpList([('name', amp.Unicode())], optional=True)),
     200            (b'magicWord', amp.Unicode()),
     201            (b'list', amp.AmpList([(b'name', amp.Unicode())], optional=True)),
    207202            ]
    208     response = [('response', amp.Unicode())]
     203    response = [(b'response', amp.Unicode())]
    209204
    210205class SecuredPing(amp.Command):
    211206    # XXX TODO: actually make this refuse to send over an insecure connection
    212     response = [('pinged', amp.Boolean())]
     207    response = [(b'pinged', amp.Boolean())]
    213208
    214209class TestSwitchProto(amp.ProtocolSwitchCommand):
    215     commandName = 'Switch-Proto'
     210    commandName = b'Switch-Proto'
    216211
    217212    arguments = [
    218         ('name', amp.String()),
     213        (b'name', amp.String()),
    219214        ]
    220     errors = {UnknownProtocol: 'UNKNOWN'}
     215    errors = {UnknownProtocol: b'UNKNOWN'}
    221216
    222217class SingleUseFactory(protocol.ClientFactory):
    223218    def __init__(self, proto):
    class SingleUseFactory(protocol.ClientFactory): 
    234229        self.reasonFailed = reason
    235230        return
    236231
    237 THING_I_DONT_UNDERSTAND = 'gwebol nargo'
     232THING_I_DONT_UNDERSTAND = b'gwebol nargo'
    238233class ThingIDontUnderstandError(Exception):
    239234    pass
    240235
    class SimpleSymmetricCommandProtocol(FactoryNotifier): 
    273268        assert From == self.transport.getPeer()
    274269        if hello == THING_I_DONT_UNDERSTAND:
    275270            raise ThingIDontUnderstandError()
    276         if hello.startswith('fuck'):
     271        if hello.startswith(b'fuck'):
    277272            raise UnfriendlyGreeting("Don't be a dick.")
    278         if hello == 'die':
     273        if hello == b'die':
    279274            raise DeathThreat("aieeeeeeeee")
    280275        result = dict(hello=hello)
    281276        if Print is not None:
    class SimpleSymmetricCommandProtocol(FactoryNotifier): 
    301296        return self.waiting
    302297    WaitForever.responder(waitforit)
    303298
    304     def howdo(self):
    305         return dict(howdoyoudo='world')
    306     Howdoyoudo.responder(howdo)
    307 
    308299    def saybye(self):
    309         return dict(goodbye="everyone")
     300        return dict(goodbye=b"everyone")
    310301    Goodbye.responder(saybye)
    311302
    312303    def switchToTestProtocol(self, fail=False):
    313304        if fail:
    314             name = 'no-proto'
     305            name = b'no-proto'
    315306        else:
    316             name = 'test-proto'
     307            name = b'test-proto'
    317308        p = TestProto(self.onConnLost, SWITCH_CLIENT_DATA)
    318309        return self.callRemote(
    319310            TestSwitchProto,
    320311            SingleUseFactory(p), name=name).addCallback(lambda ign: p)
    321312
    322313    def switchit(self, name):
    323         if name == 'test-proto':
     314        if name == b'test-proto':
    324315            return TestProto(self.onConnLost, SWITCH_SERVER_DATA)
    325316        raise UnknownProtocol(name)
    326317    TestSwitchProto.responder(switchit)
    class SimpleSymmetricCommandProtocol(FactoryNotifier): 
    332323
    333324class DeferredSymmetricCommandProtocol(SimpleSymmetricCommandProtocol):
    334325    def switchit(self, name):
    335         if name == 'test-proto':
     326        if name == b'test-proto':
    336327            self.maybeLaterProto = TestProto(self.onConnLost, SWITCH_SERVER_DATA)
    337328            self.maybeLater = defer.Deferred()
    338329            return self.maybeLater
    339         raise UnknownProtocol(name)
    340330    TestSwitchProto.responder(switchit)
    341331
    342332class BadNoAnswerCommandProtocol(SimpleSymmetricCommandProtocol):
    class BadNoAnswerCommandProtocol(SimpleSymmetricCommandProtocol): 
    350340class NoAnswerCommandProtocol(SimpleSymmetricCommandProtocol):
    351341    def goodNoAnswerResponder(self, hello, From, optional=None, Print=None,
    352342                              mixedCase=None, dash_arg=None, underscore_arg=None):
    353         return dict(hello=hello+"-noanswer")
     343        return dict(hello=hello+b"-noanswer")
    354344    NoAnswerHello.responder(goodNoAnswerResponder)
    355345
    356346def connectedServerAndClient(ServerClass=SimpleSymmetricProtocol,
    def connectedServerAndClient(ServerClass=SimpleSymmetricProtocol, 
    363353        *a, **kw)
    364354
    365355class TotallyDumbProtocol(protocol.Protocol):
    366     buf = ''
     356    buf = b''
    367357    def dataReceived(self, data):
    368358        self.buf += data
    369359
    class AmpBoxTests(unittest.TestCase): 
    387377        """
    388378        Make sure that strs serialize to strs.
    389379        """
    390         a = amp.AmpBox(key='value')
    391         self.assertEqual(type(a.serialize()), str)
     380        a = amp.AmpBox(key=b'value')
     381        self.assertEqual(type(a.serialize()), bytes)
    392382
    393383    def test_serializeUnicodeKeyRaises(self):
    394384        """
    class ParsingTests(unittest.TestCase): 
    415405        else.
    416406        """
    417407        b = amp.Boolean()
    418         self.assertEqual(b.fromString("True"), True)
    419         self.assertEqual(b.fromString("False"), False)
    420         self.assertRaises(TypeError, b.fromString, "ninja")
    421         self.assertRaises(TypeError, b.fromString, "true")
    422         self.assertRaises(TypeError, b.fromString, "TRUE")
    423         self.assertEqual(b.toString(True), 'True')
    424         self.assertEqual(b.toString(False), 'False')
     408        self.assertEqual(b.fromString(b"True"), True)
     409        self.assertEqual(b.fromString(b"False"), False)
     410        self.assertRaises(TypeError, b.fromString, b"ninja")
     411        self.assertRaises(TypeError, b.fromString, b"true")
     412        self.assertRaises(TypeError, b.fromString, b"TRUE")
     413        self.assertEqual(b.toString(True), b'True')
     414        self.assertEqual(b.toString(False), b'False')
    425415
    426416    def test_pathValueRoundTrip(self):
    427417        """
    class ParsingTests(unittest.TestCase): 
    452442        c, s, p = connectedServerAndClient(ClientClass=LiteralAmp,
    453443                                           ServerClass=LiteralAmp)
    454444
    455         SIMPLE = ('simple', 'test')
    456         CE = ('ceq', ': ')
    457         CR = ('crtest', 'test\r')
    458         LF = ('lftest', 'hello\n')
    459         NEWLINE = ('newline', 'test\r\none\r\ntwo')
    460         NEWLINE2 = ('newline2', 'test\r\none\r\n two')
    461         BODYTEST = ('body', 'blah\r\n\r\ntesttest')
     445        SIMPLE = (b'simple', b'test')
     446        CE = (b'ceq', b': ')
     447        CR = (b'crtest', b'test\r')
     448        LF = (b'lftest', b'hello\n')
     449        NEWLINE = (b'newline', b'test\r\none\r\ntwo')
     450        NEWLINE2 = (b'newline2', b'test\r\none\r\n two')
     451        BODYTEST = (b'body', b'blah\r\n\r\ntesttest')
    462452
    463453        testData = [
    464454            [SIMPLE],
    class CommandDispatchTests(unittest.TestCase): 
    621611        fired, and the results translated via the given L{Command}'s response
    622612        de-serialization.
    623613        """
    624         D = self.dispatcher.callRemote(Hello, hello='world')
     614        D = self.dispatcher.callRemote(Hello, hello=b'world')
    625615        self.assertEqual(self.sender.sentBoxes,
    626                           [amp.AmpBox(_command="hello",
    627                                       _ask="1",
    628                                       hello="world")])
     616                          [amp.AmpBox(_command=b"hello",
     617                                      _ask=b"1",
     618                                      hello=b"world")])
    629619        answers = []
    630620        D.addCallback(answers.append)
    631621        self.assertEqual(answers, [])
    632         self.dispatcher.ampBoxReceived(amp.AmpBox({'hello': "yay",
    633                                                    'print': "ignored",
    634                                                    '_answer': "1"}))
    635         self.assertEqual(answers, [dict(hello="yay",
     622        self.dispatcher.ampBoxReceived(amp.AmpBox({b'hello': b"yay",
     623                                                   b'print': b"ignored",
     624                                                   b'_answer': b"1"}))
     625        self.assertEqual(answers, [dict(hello=b"yay",
    636626                                         Print=u"ignored")])
    637627
    638628
    class CommandDispatchTests(unittest.TestCase): 
    659649        """
    660650        self.sender.expectError()
    661651
    662         callResult = self.dispatcher.callRemote(Hello, hello='world')
     652        callResult = self.dispatcher.callRemote(Hello, hello=b'world')
    663653        callResult.addCallback(lambda result: 1 // 0)
    664654
    665655        self.dispatcher.ampBoxReceived(amp.AmpBox({
    666                     'hello': "yay", 'print': "ignored", '_answer': "1"}))
     656                    b'hello': b"yay", b'print': b"ignored", b'_answer': b"1"}))
    667657
    668658        self._localCallbackErrorLoggingTest(callResult)
    669659
    class CommandDispatchTests(unittest.TestCase): 
    675665        """
    676666        self.sender.expectError()
    677667
    678         callResult = self.dispatcher.callRemote(Hello, hello='world')
     668        callResult = self.dispatcher.callRemote(Hello, hello=b'world')
    679669        callResult.addErrback(lambda result: 1 // 0)
    680670
    681671        self.dispatcher.ampBoxReceived(amp.AmpBox({
    682                     '_error': '1', '_error_code': 'bugs',
    683                     '_error_description': 'stuff'}))
     672                    b'_error': b'1', b'_error_code': b'bugs',
     673                    b'_error_description': b'stuff'}))
    684674
    685675        self._localCallbackErrorLoggingTest(callResult)
    686676
    class SimpleGreeting(amp.Command): 
    690680    """
    691681    A very simple greeting command that uses a few basic argument types.
    692682    """
    693     commandName = 'simple'
    694     arguments = [('greeting', amp.Unicode()),
    695                  ('cookie', amp.Integer())]
    696     response = [('cookieplus', amp.Integer())]
     683    commandName = b'simple'
     684    arguments = [(b'greeting', amp.Unicode()),
     685                 (b'cookie', amp.Integer())]
     686    response = [(b'cookieplus', amp.Integer())]
    697687
    698688
    699689
    class OverrideLocatorAMP(amp.AMP): 
    738728    def __init__(self):
    739729        amp.AMP.__init__(self)
    740730        self.customResponder = object()
    741         self.expectations = {"custom": self.customResponder}
     731        self.expectations = {b"custom": self.customResponder}
    742732        self.greetings = []
    743733
    744734
    class CommandLocatorTests(unittest.TestCase): 
    775765        command.
    776766        """
    777767        locator = locatorClass()
    778         responderCallable = locator.locateResponder("simple")
    779         result = responderCallable(amp.Box(greeting="ni hao", cookie="5"))
     768        responderCallable = locator.locateResponder(b"simple")
     769        result = responderCallable(amp.Box(greeting=b"ni hao", cookie=b"5"))
    780770        def done(values):
    781             self.assertEqual(values, amp.AmpBox(cookieplus=str(expected)))
     771            self.assertEqual(values, amp.AmpBox(cookieplus=intToBytes(expected)))
    782772        return result.addCallback(done)
    783773
    784774
    class CommandLocatorTests(unittest.TestCase): 
    820810        customResponderObject = self.assertWarns(
    821811            PendingDeprecationWarning,
    822812            "Override locateResponder, not lookupFunction.",
    823             __file__, lambda : locator.locateResponder("custom"))
     813            __file__, lambda : locator.locateResponder(b"custom"))
    824814        self.assertEqual(locator.customResponder, customResponderObject)
    825815        # Make sure upcalling works too
    826816        normalResponderObject = self.assertWarns(
    827817            PendingDeprecationWarning,
    828818            "Override locateResponder, not lookupFunction.",
    829             __file__, lambda : locator.locateResponder("simple"))
    830         result = normalResponderObject(amp.Box(greeting="ni hao", cookie="5"))
     819            __file__, lambda : locator.locateResponder(b"simple"))
     820        result = normalResponderObject(amp.Box(greeting=b"ni hao", cookie=b"5"))
    831821        def done(values):
    832             self.assertEqual(values, amp.AmpBox(cookieplus='8'))
     822            self.assertEqual(values, amp.AmpBox(cookieplus=b'8'))
    833823        return result.addCallback(done)
    834824
    835825
    class CommandLocatorTests(unittest.TestCase): 
    842832        responderCallable = self.assertWarns(
    843833            PendingDeprecationWarning,
    844834            "Call locateResponder, not lookupFunction.", __file__,
    845             lambda : locator.lookupFunction("simple"))
    846         result = responderCallable(amp.Box(greeting="ni hao", cookie="5"))
     835            lambda : locator.lookupFunction(b"simple"))
     836        result = responderCallable(amp.Box(greeting=b"ni hao", cookie=b"5"))
    847837        def done(values):
    848             self.assertEqual(values, amp.AmpBox(cookieplus='8'))
     838            self.assertEqual(values, amp.AmpBox(cookieplus=b'8'))
    849839        return result.addCallback(done)
    850840
    851841
    852842
    853 SWITCH_CLIENT_DATA = 'Success!'
    854 SWITCH_SERVER_DATA = 'No, really.  Success.'
     843SWITCH_CLIENT_DATA = b'Success!'
     844SWITCH_SERVER_DATA = b'No, really.  Success.'
    855845
    856846
    857847class BinaryProtocolTests(unittest.TestCase):
    class BinaryProtocolTests(unittest.TestCase): 
    903893
    904894
    905895    def write(self, data):
     896        self.assertIsInstance(data, bytes)
    906897        self.data.append(data)
    907898
    908899
    class BinaryProtocolTests(unittest.TestCase): 
    926917        """
    927918        class SynchronouslySendingReceiver:
    928919            def startReceivingBoxes(self, sender):
    929                 sender.sendBox(amp.Box({'foo': 'bar'}))
     920                sender.sendBox(amp.Box({b'foo': b'bar'}))
    930921
    931922        transport = StringTransport()
    932923        protocol = amp.BinaryBoxProtocol(SynchronouslySendingReceiver())
    933924        protocol.makeConnection(transport)
    934925        self.assertEqual(
    935926            transport.value(),
    936             '\x00\x03foo\x00\x03bar\x00\x00')
     927            b'\x00\x03foo\x00\x03bar\x00\x00')
    937928
    938929
    939930    def test_receiveBoxStateMachine(self):
    class BinaryProtocolTests(unittest.TestCase): 
    945936        it should emit a box and send it to its boxReceiver.
    946937        """
    947938        a = amp.BinaryBoxProtocol(self)
    948         a.stringReceived("hello")
    949         a.stringReceived("world")
    950         a.stringReceived("")
    951         self.assertEqual(self.boxes, [amp.AmpBox(hello="world")])
     939        a.stringReceived(b"hello")
     940        a.stringReceived(b"world")
     941        a.stringReceived(b"")
     942        self.assertEqual(self.boxes, [amp.AmpBox(hello=b"world")])
    952943
    953944
    954945    def test_firstBoxFirstKeyExcessiveLength(self):
    class BinaryProtocolTests(unittest.TestCase): 
    959950        transport = StringTransport()
    960951        protocol = amp.BinaryBoxProtocol(self)
    961952        protocol.makeConnection(transport)
    962         protocol.dataReceived('\x01\x00')
     953        protocol.dataReceived(b'\x01\x00')
    963954        self.assertTrue(transport.disconnecting)
    964955
    965956
    class BinaryProtocolTests(unittest.TestCase): 
    971962        transport = StringTransport()
    972963        protocol = amp.BinaryBoxProtocol(self)
    973964        protocol.makeConnection(transport)
    974         protocol.dataReceived('\x00\x01k\x00\x01v')
     965        protocol.dataReceived(b'\x00\x01k\x00\x01v')
    975966        self.assertFalse(transport.disconnecting)
    976         protocol.dataReceived('\x01\x00')
     967        protocol.dataReceived(b'\x01\x00')
    977968        self.assertTrue(transport.disconnecting)
    978969
    979970
    class BinaryProtocolTests(unittest.TestCase): 
    985976        transport = StringTransport()
    986977        protocol = amp.BinaryBoxProtocol(self)
    987978        protocol.makeConnection(transport)
    988         protocol.dataReceived('\x00\x01k\x00\x01v\x00\x00')
     979        protocol.dataReceived(b'\x00\x01k\x00\x01v\x00\x00')
    989980        self.assertFalse(transport.disconnecting)
    990         protocol.dataReceived('\x01\x00')
     981        protocol.dataReceived(b'\x01\x00')
    991982        self.assertTrue(transport.disconnecting)
    992983
    993984
    class BinaryProtocolTests(unittest.TestCase): 
    999990        """
    1000991        protocol = amp.BinaryBoxProtocol(self)
    1001992        protocol.makeConnection(StringTransport())
    1002         protocol.dataReceived('\x01\x00')
     993        protocol.dataReceived(b'\x01\x00')
    1003994        protocol.connectionLost(
    1004995            Failure(error.ConnectionDone("simulated connection done")))
    1005996        self.stopReason.trap(amp.TooLong)
    class BinaryProtocolTests(unittest.TestCase): 
    10401031        it should emit a similar box to its boxReceiver.
    10411032        """
    10421033        a = amp.BinaryBoxProtocol(self)
    1043         a.dataReceived(amp.Box({"testKey": "valueTest",
    1044                                 "anotherKey": "anotherValue"}).serialize())
     1034        a.dataReceived(amp.Box({b"testKey": b"valueTest",
     1035                                b"anotherKey": b"anotherValue"}).serialize())
    10451036        self.assertEqual(self.boxes,
    1046                           [amp.Box({"testKey": "valueTest",
    1047                                     "anotherKey": "anotherValue"})])
     1037                          [amp.Box({b"testKey": b"valueTest",
     1038                                    b"anotherKey": b"anotherValue"})])
    10481039
    10491040
    10501041    def test_receiveLongerBoxData(self):
    class BinaryProtocolTests(unittest.TestCase): 
    10531044        values of up to (2 ** 16 - 1) bytes.
    10541045        """
    10551046        length = (2 ** 16 - 1)
    1056         value = 'x' * length
     1047        value = b'x' * length
    10571048        transport = StringTransport()
    10581049        protocol = amp.BinaryBoxProtocol(self)
    10591050        protocol.makeConnection(transport)
    class BinaryProtocolTests(unittest.TestCase): 
    10691060        """
    10701061        a = amp.BinaryBoxProtocol(self)
    10711062        a.makeConnection(self)
    1072         aBox = amp.Box({"testKey": "valueTest",
    1073                         "someData": "hello"})
     1063        aBox = amp.Box({b"testKey": b"valueTest",
     1064                        b"someData": b"hello"})
    10741065        a.makeConnection(self)
    10751066        a.sendBox(aBox)
    1076         self.assertEqual(''.join(self.data), aBox.serialize())
     1067        self.assertEqual(b''.join(self.data), aBox.serialize())
    10771068
    10781069
    10791070    def test_connectionLostStopSendingBoxes(self):
    class BinaryProtocolTests(unittest.TestCase): 
    10941085        on a box boundary.  When a protocol is in the process of switching, it
    10951086        cannot receive traffic.
    10961087        """
    1097         otherProto = TestProto(None, "outgoing data")
     1088        otherProto = TestProto(None, b"outgoing data")
    10981089        test = self
    10991090        class SwitchyReceiver:
    11001091            switched = False
    class BinaryProtocolTests(unittest.TestCase): 
    11071098                a._lockForSwitch()
    11081099                a._switchTo(otherProto)
    11091100        a = amp.BinaryBoxProtocol(SwitchyReceiver())
    1110         anyOldBox = amp.Box({"include": "lots",
    1111                              "of": "data"})
     1101        anyOldBox = amp.Box({b"include": b"lots",
     1102                             b"of": b"data"})
    11121103        a.makeConnection(self)
    11131104        # Include a 0-length box at the beginning of the next protocol's data,
    11141105        # to make sure that AMP doesn't eat the data or try to deliver extra
    11151106        # boxes either...
    1116         moreThanOneBox = anyOldBox.serialize() + "\x00\x00Hello, world!"
     1107        moreThanOneBox = anyOldBox.serialize() + b"\x00\x00Hello, world!"
    11171108        a.dataReceived(moreThanOneBox)
    11181109        self.assertIdentical(otherProto.transport, self)
    1119         self.assertEqual("".join(otherProto.data), "\x00\x00Hello, world!")
    1120         self.assertEqual(self.data, ["outgoing data"])
    1121         a.dataReceived("more data")
    1122         self.assertEqual("".join(otherProto.data),
    1123                           "\x00\x00Hello, world!more data")
     1110        self.assertEqual(b"".join(otherProto.data), b"\x00\x00Hello, world!")
     1111        self.assertEqual(self.data, [b"outgoing data"])
     1112        a.dataReceived(b"more data")
     1113        self.assertEqual(b"".join(otherProto.data),
     1114                          b"\x00\x00Hello, world!more data")
    11241115        self.assertRaises(amp.ProtocolSwitched, a.sendBox, anyOldBox)
    11251116
    11261117
    class BinaryProtocolTests(unittest.TestCase): 
    11321123        """
    11331124        a = amp.BinaryBoxProtocol(self)
    11341125        a.makeConnection(self)
    1135         otherProto = TestProto(None, "")
     1126        otherProto = TestProto(None, b"")
    11361127        a._switchTo(otherProto)
    11371128        self.assertEqual(otherProto.data, [])
    11381129
    class BinaryProtocolTests(unittest.TestCase): 
    11461137        """
    11471138        a = amp.BinaryBoxProtocol(self)
    11481139        a.makeConnection(self)
    1149         sampleBox = amp.Box({"some": "data"})
     1140        sampleBox = amp.Box({b"some": b"data"})
    11501141        a._lockForSwitch()
    11511142        self.assertRaises(amp.ProtocolSwitched, a.sendBox, sampleBox)
    11521143        a._unlockFromSwitch()
    11531144        a.sendBox(sampleBox)
    1154         self.assertEqual(''.join(self.data), sampleBox.serialize())
     1145        self.assertEqual(b''.join(self.data), sampleBox.serialize())
    11551146        a._lockForSwitch()
    1156         otherProto = TestProto(None, "outgoing data")
     1147        otherProto = TestProto(None, b"outgoing data")
    11571148        a._switchTo(otherProto)
    11581149        self.assertRaises(amp.ProtocolSwitched, a._unlockFromSwitch)
    11591150
    class AMPTests(unittest.TestCase): 
    12231214        """
    12241215        c, s, p = connectedServerAndClient()
    12251216        L = []
    1226         HELLO = 'world'
     1217        HELLO = b'world'
    12271218        c.sendHello(HELLO).addCallback(L.append)
    12281219        p.flush()
    1229         self.assertEqual(L[0]['hello'], HELLO)
     1220        self.assertEqual(L[0][b'hello'], HELLO)
    12301221
    12311222
    12321223    def test_wireFormatRoundTrip(self):
    class AMPTests(unittest.TestCase): 
    12361227        """
    12371228        c, s, p = connectedServerAndClient()
    12381229        L = []
    1239         HELLO = 'world'
     1230        HELLO = b'world'
    12401231        c.sendHello(HELLO).addCallback(L.append)
    12411232        p.flush()
    1242         self.assertEqual(L[0]['hello'], HELLO)
     1233        self.assertEqual(L[0][b'hello'], HELLO)
    12431234
    12441235
    12451236    def test_helloWorldUnicode(self):
    class AMPTests(unittest.TestCase): 
    12501241            ServerClass=SimpleSymmetricCommandProtocol,
    12511242            ClientClass=SimpleSymmetricCommandProtocol)
    12521243        L = []
    1253         HELLO = 'world'
    1254         HELLO_UNICODE = 'wor\u1234ld'
     1244        HELLO = b'world'
     1245        HELLO_UNICODE = u'wor\u1234ld'
    12551246        c.sendUnicodeHello(HELLO, HELLO_UNICODE).addCallback(L.append)
    12561247        p.flush()
    12571248        self.assertEqual(L[0]['hello'], HELLO)
    class AMPTests(unittest.TestCase): 
    12641255        is C{False}.
    12651256        """
    12661257        c, s, p = connectedServerAndClient()
    1267         ret = c.callRemoteString("WTF", requiresAnswer=False)
     1258        ret = c.callRemoteString(b"WTF", requiresAnswer=False)
    12681259        self.assertIdentical(ret, None)
    12691260
    12701261
    class AMPTests(unittest.TestCase): 
    12811272            """
    12821273            e.trap(amp.UnhandledCommand)
    12831274            return "OK"
    1284         c.callRemoteString("WTF").addErrback(clearAndAdd).addCallback(L.append)
     1275        c.callRemoteString(b"WTF").addErrback(clearAndAdd).addCallback(L.append)
    12851276        p.flush()
    12861277        self.assertEqual(L.pop(), "OK")
    1287         HELLO = 'world'
     1278        HELLO = b'world'
    12881279        c.sendHello(HELLO).addCallback(L.append)
    12891280        p.flush()
    1290         self.assertEqual(L[0]['hello'], HELLO)
     1281        self.assertEqual(L[0][b'hello'], HELLO)
    12911282
    12921283
    12931284    def test_unknownCommandHigh(self):
    class AMPTests(unittest.TestCase): 
    13061297        c.callRemote(WTF).addErrback(clearAndAdd).addCallback(L.append)
    13071298        p.flush()
    13081299        self.assertEqual(L.pop(), "OK")
    1309         HELLO = 'world'
     1300        HELLO = b'world'
    13101301        c.sendHello(HELLO).addCallback(L.append)
    13111302        p.flush()
    1312         self.assertEqual(L[0]['hello'], HELLO)
     1303        self.assertEqual(L[0][b'hello'], HELLO)
    13131304
    13141305
    13151306    def test_brokenReturnValue(self):
    class AMPTests(unittest.TestCase): 
    13361327            ServerClass=SimpleSymmetricCommandProtocol,
    13371328            ClientClass=SimpleSymmetricCommandProtocol)
    13381329        L = []
    1339         HELLO = 'world'
     1330        HELLO = b'world'
    13401331        # c.sendHello(HELLO).addCallback(L.append)
    13411332        c.callRemote(FutureHello,
    13421333                     hello=HELLO,
    1343                      bonus="I'm not in the book!").addCallback(
     1334                     bonus=b"I'm not in the book!").addCallback(
    13441335            L.append)
    13451336        p.flush()
    13461337        self.assertEqual(L[0]['hello'], HELLO)
    class AMPTests(unittest.TestCase): 
    13601351        """
    13611352        Verify that L{AMP} objects output their innerProtocol when set.
    13621353        """
    1363         otherProto = TestProto(None, "outgoing data")
     1354        otherProto = TestProto(None, b"outgoing data")
    13641355        a = amp.AMP()
    13651356        a.innerProtocol = otherProto
    13661357
    class AMPTests(unittest.TestCase): 
    13951386        c, s, p = connectedServerAndClient()
    13961387        x = "H" * (0xff+1)
    13971388        tl = self.assertRaises(amp.TooLong,
    1398                                c.callRemoteString, "Hello",
    1399                                **{x: "hi"})
     1389                               c.callRemoteString, b"Hello",
     1390                               **{x: b"hi"})
    14001391        self.assertTrue(tl.isKey)
    14011392        self.assertTrue(tl.isLocal)
    14021393        self.assertIdentical(tl.keyName, None)
    1403         self.assertEqual(tl.value, x)
     1394        self.assertEqual(tl.value, x.encode("ascii"))
    14041395        self.assertIn(str(len(x)), repr(tl))
    14051396        self.assertIn("key", repr(tl))
    14061397
    class AMPTests(unittest.TestCase): 
    14111402        raise an exception.
    14121403        """
    14131404        c, s, p = connectedServerAndClient()
    1414         x = "H" * (0xffff+1)
     1405        x = b"H" * (0xffff+1)
    14151406        tl = self.assertRaises(amp.TooLong, c.sendHello, x)
    14161407        p.flush()
    14171408        self.assertFalse(tl.isKey)
    14181409        self.assertTrue(tl.isLocal)
    1419         self.assertEqual(tl.keyName, 'hello')
     1410        self.assertEqual(tl.keyName, b'hello')
    14201411        self.failUnlessIdentical(tl.value, x)
    14211412        self.assertTrue(str(len(x)) in repr(tl))
    14221413        self.assertTrue("value" in repr(tl))
    class AMPTests(unittest.TestCase): 
    14321423            ServerClass=SimpleSymmetricCommandProtocol,
    14331424            ClientClass=SimpleSymmetricCommandProtocol)
    14341425        L = []
    1435         HELLO = 'world'
     1426        HELLO = b'world'
    14361427        c.sendHello(HELLO).addCallback(L.append)
    14371428        p.flush()
    14381429        self.assertEqual(L[0]['hello'], HELLO)
    class AMPTests(unittest.TestCase): 
    14481439        c, s, p = connectedServerAndClient(
    14491440            ServerClass=SimpleSymmetricCommandProtocol,
    14501441            ClientClass=SimpleSymmetricCommandProtocol)
    1451         HELLO = 'fuck you'
     1442        HELLO = b'fuck you'
    14521443        c.sendHello(HELLO).addErrback(L.append)
    14531444        p.flush()
    14541445        L[0].trap(UnfriendlyGreeting)
    class AMPTests(unittest.TestCase): 
    14661457        c, s, p = connectedServerAndClient(
    14671458            ServerClass=SimpleSymmetricCommandProtocol,
    14681459            ClientClass=SimpleSymmetricCommandProtocol)
    1469         HELLO = 'die'
     1460        HELLO = b'die'
    14701461        c.sendHello(HELLO).addErrback(L.append)
    14711462        p.flush()
    14721463        L.pop().trap(DeathThreat)
    class AMPTests(unittest.TestCase): 
    15261517        c, s, p = connectedServerAndClient(
    15271518            ServerClass=SimpleSymmetricCommandProtocol,
    15281519            ClientClass=SimpleSymmetricCommandProtocol)
    1529         HELLO = 'world'
     1520        HELLO = b'world'
    15301521        c.callRemote(NoAnswerHello, hello=HELLO)
    15311522        p.flush()
    15321523        self.assertTrue(s.greeted)
    class AMPTests(unittest.TestCase): 
    15401531        c, s, p = connectedServerAndClient(
    15411532            ServerClass=SimpleSymmetricCommandProtocol,
    15421533            ClientClass=SimpleSymmetricCommandProtocol)
    1543         HELLO = 'fuck you'
     1534        HELLO = b'fuck you'
    15441535        c.callRemote(NoAnswerHello, hello=HELLO)
    15451536        p.flush()
    15461537        # This should be logged locally.
    15471538        self.assertTrue(self.flushLoggedErrors(amp.RemoteAmpError))
    1548         HELLO = 'world'
     1539        HELLO = b'world'
    15491540        c.callRemote(Hello, hello=HELLO).addErrback(L.append)
    15501541        p.flush()
    15511542        L.pop().trap(error.ConnectionDone)
    class AMPTests(unittest.TestCase): 
    15641555        c, s, p = connectedServerAndClient(
    15651556            ServerClass=BadNoAnswerCommandProtocol,
    15661557            ClientClass=SimpleSymmetricCommandProtocol)
    1567         c.callRemote(NoAnswerHello, hello="hello")
     1558        c.callRemote(NoAnswerHello, hello=b"hello")
    15681559        p.flush()
    15691560        le = self.flushLoggedErrors(amp.BadLocalReturn)
    15701561        self.assertEqual(len(le), 1)
    class AMPTests(unittest.TestCase): 
    15801571            ServerClass=NoAnswerCommandProtocol,
    15811572            ClientClass=SimpleSymmetricCommandProtocol)
    15821573        L = []
    1583         c.callRemote(Hello, hello="Hello!").addCallback(L.append)
     1574        c.callRemote(Hello, hello=b"Hello!").addCallback(L.append)
    15841575        p.flush()
    15851576        self.assertEqual(len(L), 1)
    1586         self.assertEqual(L, [dict(hello="Hello!-noanswer",
     1577        self.assertEqual(L, [dict(hello=b"Hello!-noanswer",
    15871578                                   Print=None)])  # Optional response argument
    15881579
    15891580
    class AMPTests(unittest.TestCase): 
    16251616            ClientClass=SimpleSymmetricCommandProtocol)
    16261617        L = []
    16271618        c.callRemote(DontRejectMe, magicWord=u'please',
    1628                 list=[{'name': 'foo'}]).addCallback(L.append)
     1619                list=[{'name': u'foo'}]).addCallback(L.append)
    16291620        p.flush()
    16301621        response = L.pop().get('response')
    16311622        self.assertEqual(response, 'foo accepted')
    class AMPTests(unittest.TestCase): 
    16801671            c.callRemote(WaitForever).addErrback(wfdr.append)
    16811672        switchDeferred = c.switchToTestProtocol()
    16821673        if spuriousTraffic:
    1683             self.assertRaises(amp.ProtocolSwitched, c.sendHello, 'world')
     1674            self.assertRaises(amp.ProtocolSwitched, c.sendHello, b'world')
    16841675
    1685         def cbConnsLost(((serverSuccess, serverData),
    1686                          (clientSuccess, clientData))):
     1676        def cbConnsLost(info):
     1677            ((serverSuccess, serverData), (clientSuccess, clientData)) = info
    16871678            self.assertTrue(serverSuccess)
    16881679            self.assertTrue(clientSuccess)
    1689             self.assertEqual(''.join(serverData), SWITCH_CLIENT_DATA)
    1690             self.assertEqual(''.join(clientData), SWITCH_SERVER_DATA)
     1680            self.assertEqual(b''.join(serverData), SWITCH_CLIENT_DATA)
     1681            self.assertEqual(b''.join(clientData), SWITCH_SERVER_DATA)
    16911682            self.testSucceeded = True
    16921683
    16931684        def cbSwitch(proto):
    class AMPTests(unittest.TestCase): 
    17041695            # going to corrupt the connection, we do it before it's closed.
    17051696            if spuriousError:
    17061697                s.waiting.errback(amp.RemoteAmpError(
    1707                         "SPURIOUS",
     1698                        b"SPURIOUS",
    17081699                        "Here's some traffic in the form of an error."))
    17091700            else:
    17101701                s.waiting.callback({})
    class AMPTests(unittest.TestCase): 
    17421733        self.assertFalse(self.testSucceeded)
    17431734        # It's a known error, so let's send a "hello" on the same connection;
    17441735        # it should work.
    1745         c.sendHello('world').addCallback(L.append)
     1736        c.sendHello(b'world').addCallback(L.append)
    17461737        p.flush()
    1747         self.assertEqual(L.pop()['hello'], 'world')
     1738        self.assertEqual(L.pop()['hello'], b'world')
    17481739
    17491740
    17501741    def test_trafficAfterSwitch(self):
    class AMPTests(unittest.TestCase): 
    17741765            ClientClass=SimpleSymmetricCommandProtocol)
    17751766
    17761767        L = []
    1777         HELLO = 'world'
    1778         GOODBYE = 'everyone'
     1768        HELLO = b'world'
     1769        GOODBYE = b'everyone'
    17791770        c.sendHello(HELLO).addCallback(L.append)
    17801771        p.flush()
    17811772        self.assertEqual(L.pop()['hello'], HELLO)
    class AMPTests(unittest.TestCase): 
    17941785        c, s, p = connectedServerAndClient()
    17951786        L = []
    17961787        s.ampBoxReceived = L.append
    1797         c.callRemote(Hello, hello='hello test', mixedCase='mixed case arg test',
    1798                      dash_arg='x', underscore_arg='y')
     1788        c.callRemote(Hello, hello=b'hello test', mixedCase=b'mixed case arg test',
     1789                     dash_arg=b'x', underscore_arg=b'y')
    17991790        p.flush()
    18001791        self.assertEqual(len(L), 1)
    1801         for k, v in [('_command', Hello.commandName),
    1802                      ('hello', 'hello test'),
    1803                      ('mixedCase', 'mixed case arg test'),
    1804                      ('dash-arg', 'x'),
    1805                      ('underscore_arg', 'y')]:
     1792        for k, v in [(b'_command', Hello.commandName),
     1793                     (b'hello', b'hello test'),
     1794                     (b'mixedCase', b'mixed case arg test'),
     1795                     (b'dash-arg', b'x'),
     1796                     (b'underscore_arg', b'y')]:
    18061797            self.assertEqual(L[-1].pop(k), v)
    1807         L[-1].pop('_ask')
     1798        L[-1].pop(b'_ask')
    18081799        self.assertEqual(L[-1], {})
    18091800
    18101801
    class AMPTests(unittest.TestCase): 
    18181809        class StructuredHello(amp.AMP):
    18191810            def h(self, *a, **k):
    18201811                L.append((a, k))
    1821                 return dict(hello='aaa')
     1812                return dict(hello=b'aaa')
    18221813            Hello.responder(h)
    18231814        c, s, p = connectedServerAndClient(ServerClass=StructuredHello)
    1824         c.callRemote(Hello, hello='hello test', mixedCase='mixed case arg test',
    1825                      dash_arg='x', underscore_arg='y').addCallback(L.append)
     1815        c.callRemote(Hello, hello=b'hello test', mixedCase=b'mixed case arg test',
     1816                     dash_arg=b'x', underscore_arg=b'y').addCallback(L.append)
    18261817        p.flush()
    18271818        self.assertEqual(len(L), 2)
    18281819        self.assertEqual(L[0],
    18291820                          ((), dict(
    1830                     hello='hello test',
    1831                     mixedCase='mixed case arg test',
    1832                     dash_arg='x',
    1833                     underscore_arg='y',
     1821                    hello=b'hello test',
     1822                    mixedCase=b'mixed case arg test',
     1823                    dash_arg=b'x',
     1824                    underscore_arg=b'y',
    18341825                    From=s.transport.getPeer(),
    18351826
    18361827                    # XXX - should optional arguments just not be passed?
    class AMPTests(unittest.TestCase): 
    18391830                    Print=None,
    18401831                    optional=None,
    18411832                    )))
    1842         self.assertEqual(L[1], dict(Print=None, hello='aaa'))
     1833        self.assertEqual(L[1], dict(Print=None, hello=b'aaa'))
    18431834
    18441835class PretendRemoteCertificateAuthority:
    18451836    def checkIsPretendRemote(self):
    class TLSNotAvailableTests(unittest.TestCase): 
    20522043        okc = OKCert()
    20532044        svr.certFactory = lambda : okc
    20542045        box = amp.Box()
    2055         box['_command'] = 'StartTLS'
    2056         box['_ask'] = '1'
     2046        box[b'_command'] = b'StartTLS'
     2047        box[b'_ask'] = b'1'
    20572048        boxes = []
    20582049        svr.sendBox = boxes.append
    20592050        svr.makeConnection(StringTransport())
    20602051        svr.ampBoxReceived(box)
    20612052        self.assertEqual(boxes,
    2062             [{'_error_code': 'TLS_ERROR',
    2063               '_error': '1',
    2064               '_error_description': 'TLS not available'}])
     2053            [{b'_error_code': b'TLS_ERROR',
     2054              b'_error': b'1',
     2055              b'_error_description': b'TLS not available'}])
    20652056
    20662057
    20672058
    class BaseCommand(amp.Command): 
    20832074    """
    20842075    This provides a command that will be subclassed.
    20852076    """
    2086     errors = {InheritedError: 'INHERITED_ERROR'}
     2077    errors = {InheritedError: b'INHERITED_ERROR'}
    20872078
    20882079
    20892080
    class AddErrorsCommand(BaseCommand): 
    21002091    This is a command which subclasses another command but adds errors to the
    21012092    list.
    21022093    """
    2103     arguments = [('other', amp.Boolean())]
    2104     errors = {OtherInheritedError: 'OTHER_INHERITED_ERROR'}
     2094    arguments = [(b'other', amp.Boolean())]
     2095    errors = {OtherInheritedError: b'OTHER_INHERITED_ERROR'}
    21052096
    21062097
    21072098
    class ProtocolIncludingArgument(amp.Argument): 
    23822373        @type obj: L{object}
    23832374        @type protocol: L{amp.AMP}
    23842375        """
    2385         return "%s:%s" % (id(obj), id(protocol))
     2376        ident = u"%d:%d" % (id(obj), id(protocol))
     2377        return ident.encode("ascii")
    23862378
    23872379
    23882380
    class ProtocolIncludingCommand(amp.Command): 
    23912383    A command that has argument and response schemas which use
    23922384    L{ProtocolIncludingArgument}.
    23932385    """
    2394     arguments = [('weird', ProtocolIncludingArgument())]
    2395     response = [('weird', ProtocolIncludingArgument())]
     2386    arguments = [(b'weird', ProtocolIncludingArgument())]
     2387    response = [(b'weird', ProtocolIncludingArgument())]
    23962388
    23972389
    23982390
    class CommandTests(unittest.TestCase): 
    24992491        Command's response schema.
    25002492        """
    25012493        protocol = object()
    2502         result = 'whatever'
    2503         strings = {'weird': result}
     2494        result = b'whatever'
     2495        strings = {b'weird': result}
    25042496        self.assertEqual(
    25052497            ProtocolIncludingCommand.parseResponse(strings, protocol),
    25062498            {'weird': (result, protocol)})
    class CommandTests(unittest.TestCase): 
    25132505        C{parseResponse} method to get the response.
    25142506        """
    25152507        client = NoNetworkProtocol()
    2516         thingy = "weeoo"
     2508        thingy = b"weeoo"
    25172509        response = client.callRemote(MagicSchemaCommand, weird=thingy)
    25182510        def gotResponse(ign):
    25192511            self.assertEqual(client.parseResponseArguments,
    class CommandTests(unittest.TestCase): 
    25302522        command's argument schema.
    25312523        """
    25322524        protocol = object()
    2533         result = 'whatever'
    2534         strings = {'weird': result}
     2525        result = b'whatever'
     2526        strings = {b'weird': result}
    25352527        self.assertEqual(
    25362528            ProtocolIncludingCommand.parseArguments(strings, protocol),
    25372529            {'weird': (result, protocol)})
    class CommandTests(unittest.TestCase): 
    25632555        protocol = object()
    25642556        argument = object()
    25652557        objects = {'weird': argument}
     2558        ident = u"%d:%d" % (id(argument), id(protocol))
    25662559        self.assertEqual(
    25672560            ProtocolIncludingCommand.makeArguments(objects, protocol),
    2568             {'weird': "%d:%d" % (id(argument), id(protocol))})
     2561            {b'weird': ident.encode("ascii")})
    25692562
    25702563
    25712564    def test_makeArgumentsUsesCommandType(self):
    class CommandTests(unittest.TestCase): 
    25742567        of the result of L{amp.Command.commandType}.
    25752568        """
    25762569        protocol = object()
    2577         objects = {"weird": "whatever"}
     2570        objects = {"weird": b"whatever"}
    25782571
    25792572        result = ProtocolIncludingCommandWithDifferentCommandType.makeArguments(
    25802573            objects, protocol)
    class CommandTests(unittest.TestCase): 
    26272620            None)
    26282621
    26292622
     2623    def test_commandNameDefaultsToClassNameAsByteString(self):
     2624        """
     2625        A L{Command} subclass without a defined C{commandName} that's
     2626        not a byte string.
     2627        """
     2628        class NewCommand(amp.Command):
     2629            """A new command."""
     2630
     2631        self.assertEqual(b"NewCommand", NewCommand.commandName)
     2632
     2633
     2634    def test_commandNameMustBeAByteString(self):
     2635        """
     2636        A L{Command} subclass cannot be defined with a C{commandName} that's
     2637        not a byte string.
     2638        """
     2639        error = self.assertRaises(
     2640            TypeError, type, "NewCommand", (amp.Command, ),
     2641            {"commandName": u"FOO"})
     2642        self.assertRegexpMatches(
     2643            str(error), "^Command names must be byte strings, got: u?'FOO'$")
     2644
     2645
     2646    def test_commandArgumentsMustBeNamedWithByteStrings(self):
     2647        """
     2648        A L{Command} subclass's C{arguments} must have byte string names.
     2649        """
     2650        error = self.assertRaises(
     2651            TypeError, type, "NewCommand", (amp.Command, ),
     2652            {"arguments": [(u"foo", None)]})
     2653        self.assertRegexpMatches(
     2654            str(error), "^Argument names must be byte strings, got: u?'foo'$")
     2655
     2656
     2657    def test_commandResponseMustBeNamedWithByteStrings(self):
     2658        """
     2659        A L{Command} subclass's C{response} must have byte string names.
     2660        """
     2661        error = self.assertRaises(
     2662            TypeError, type, "NewCommand", (amp.Command, ),
     2663            {"response": [(u"foo", None)]})
     2664        self.assertRegexpMatches(
     2665            str(error), "^Response names must be byte strings, got: u?'foo'$")
     2666
     2667
     2668    def test_commandErrorsIsConvertedToDict(self):
     2669        """
     2670        A L{Command} subclass's C{errors} is coerced into a C{dict}.
     2671        """
     2672        class NewCommand(amp.Command):
     2673            errors = [(ZeroDivisionError, b"ZDE")]
     2674
     2675        self.assertEqual(
     2676            {ZeroDivisionError: b"ZDE"},
     2677            NewCommand.errors)
     2678
     2679
     2680    def test_commandErrorsMustUseBytesForOnWireRepresentation(self):
     2681        """
     2682        A L{Command} subclass's C{errors} must map exceptions to byte strings.
     2683        """
     2684        error = self.assertRaises(
     2685            TypeError, type, "NewCommand", (amp.Command, ),
     2686            {"errors": [(ZeroDivisionError, u"foo")]})
     2687        self.assertRegexpMatches(
     2688            str(error), "^Error names must be byte strings, got: u?'foo'$")
     2689
     2690
     2691    def test_commandFatalErrorsIsConvertedToDict(self):
     2692        """
     2693        A L{Command} subclass's C{fatalErrors} is coerced into a C{dict}.
     2694        """
     2695        class NewCommand(amp.Command):
     2696            fatalErrors = [(ZeroDivisionError, b"ZDE")]
     2697
     2698        self.assertEqual(
     2699            {ZeroDivisionError: b"ZDE"},
     2700            NewCommand.fatalErrors)
     2701
     2702
     2703    def test_commandFatalErrorsMustUseBytesForOnWireRepresentation(self):
     2704        """
     2705        A L{Command} subclass's C{fatalErrors} must map exceptions to byte
     2706        strings.
     2707        """
     2708        error = self.assertRaises(
     2709            TypeError, type, "NewCommand", (amp.Command, ),
     2710            {"fatalErrors": [(ZeroDivisionError, u"foo")]})
     2711        self.assertRegexpMatches(
     2712            str(error), "^Fatal error names must be byte strings, "
     2713            "got: u?'foo'$")
     2714
     2715
     2716
    26302717class ListOfTestsMixin:
    26312718    """
    26322719    Base class for testing L{ListOf}, a parameterized zero-or-more argument
    class ListOfTestsMixin: 
    26362723        instance.  The tests will make a L{ListOf} using this.
    26372724
    26382725    @ivar strings: Subclasses should set this to a dictionary mapping some
    2639         number of keys to the correct serialized form for some example
    2640         values. These should agree with what L{elementType}
     2726        number of keys -- as BYTE strings -- to the correct serialized form
     2727        for some example values. These should agree with what L{elementType}
    26412728        produces/accepts.
    26422729
    26432730    @ivar objects: Subclasses should set this to a dictionary with the same
    2644         keys as C{strings} and with values which are the lists which should
    2645         serialize to the values in the C{strings} dictionary.
     2731        keys as C{strings} -- as NATIVE strings -- and with values which are
     2732        the lists which should serialize to the values in the C{strings}
     2733        dictionary.
    26462734    """
    26472735    def test_toBox(self):
    26482736        """
    class ListOfTestsMixin: 
    26562744        stringList = amp.ListOf(self.elementType)
    26572745        strings = amp.AmpBox()
    26582746        for key in self.objects:
    2659             stringList.toBox(key, strings, self.objects.copy(), None)
     2747            stringList.toBox(
     2748                key.encode("ascii"), strings, self.objects.copy(), None)
    26602749        self.assertEqual(strings, self.strings)
    26612750
    26622751
    class ListOfStringsTests(unittest.TestCase, ListOfTestsMixin): 
    26792768    elementType = amp.String()
    26802769
    26812770    strings = {
    2682         "empty": "",
    2683         "single": "\x00\x03foo",
    2684         "multiple": "\x00\x03bar\x00\x03baz\x00\x04quux"}
     2771        b"empty": b"",
     2772        b"single": b"\x00\x03foo",
     2773        b"multiple": b"\x00\x03bar\x00\x03baz\x00\x04quux"}
    26852774
    26862775    objects = {
    26872776        "empty": [],
    2688         "single": ["foo"],
    2689         "multiple": ["bar", "baz", "quux"]}
     2777        "single": [b"foo"],
     2778        "multiple": [b"bar", b"baz", b"quux"]}
    26902779
    26912780
    26922781class ListOfIntegersTests(unittest.TestCase, ListOfTestsMixin):
    class ListOfIntegersTests(unittest.TestCase, ListOfTestsMixin): 
    27002789        9999999999999999999999999999999999999999999999999999999999)
    27012790
    27022791    strings = {
    2703         "empty": "",
    2704         "single": "\x00\x0210",
    2705         "multiple": "\x00\x011\x00\x0220\x00\x03500",
    2706         "huge": "\x00\x74%d" % (huge,),
    2707         "negative": "\x00\x02-1"}
     2792        b"empty": b"",
     2793        b"single": b"\x00\x0210",
     2794        b"multiple": b"\x00\x011\x00\x0220\x00\x03500",
     2795        b"huge": b"\x00\x74" + intToBytes(huge),
     2796        b"negative": b"\x00\x02-1"}
    27082797
    27092798    objects = {
    27102799        "empty": [],
    class ListOfUnicodeTests(unittest.TestCase, ListOfTestsMixin): 
    27222811    elementType = amp.Unicode()
    27232812
    27242813    strings = {
    2725         "empty": "",
    2726         "single": "\x00\x03foo",
    2727         "multiple": "\x00\x03\xe2\x98\x83\x00\x05Hello\x00\x05world"}
     2814        b"empty": b"",
     2815        b"single": b"\x00\x03foo",
     2816        b"multiple": b"\x00\x03\xe2\x98\x83\x00\x05Hello\x00\x05world"}
    27282817
    27292818    objects = {
    27302819        "empty": [],
    class ListOfDecimalTests(unittest.TestCase, ListOfTestsMixin): 
    27402829    elementType = amp.Decimal()
    27412830
    27422831    strings = {
    2743         "empty": "",
    2744         "single": "\x00\x031.1",
    2745         "extreme": "\x00\x08Infinity\x00\x09-Infinity",
    2746         "scientist": "\x00\x083.141E+5\x00\x0a0.00003141\x00\x083.141E-7"
    2747                      "\x00\x09-3.141E+5\x00\x0b-0.00003141\x00\x09-3.141E-7",
    2748         "engineer": "\x00\x04%s\x00\x06%s" % (
    2749             decimal.Decimal("0e6").to_eng_string(),
    2750             decimal.Decimal("1.5E-9").to_eng_string()),
     2832        b"empty": b"",
     2833        b"single": b"\x00\x031.1",
     2834        b"extreme": b"\x00\x08Infinity\x00\x09-Infinity",
     2835        b"scientist": b"\x00\x083.141E+5\x00\x0a0.00003141\x00\x083.141E-7"
     2836                      b"\x00\x09-3.141E+5\x00\x0b-0.00003141\x00\x09-3.141E-7",
     2837        b"engineer": (
     2838            b"\x00\x04" +
     2839            decimal.Decimal("0e6").to_eng_string().encode("ascii") +
     2840            b"\x00\x06" +
     2841            decimal.Decimal("1.5E-9").to_eng_string().encode("ascii")),
    27512842    }
    27522843
    27532844    objects = {
    class ListOfDecimalNanTests(unittest.TestCase, ListOfTestsMixin): 
    27842875    elementType = amp.Decimal()
    27852876
    27862877    strings = {
    2787         "nan": "\x00\x03NaN\x00\x04-NaN\x00\x04sNaN\x00\x05-sNaN",
     2878        b"nan": b"\x00\x03NaN\x00\x04-NaN\x00\x04sNaN\x00\x05-sNaN",
    27882879    }
    27892880
    27902881    objects = {
    class ListOfDateTimeTests(unittest.TestCase, ListOfTestsMixin): 
    28492940    elementType = amp.DateTime()
    28502941
    28512942    strings = {
    2852         "christmas": "\x00\x202010-12-25T00:00:00.000000-00:00"
    2853                      "\x00\x202010-12-25T00:00:00.000000-00:00",
    2854         "christmas in eu": "\x00\x202010-12-25T00:00:00.000000+01:00",
    2855         "christmas in iran": "\x00\x202010-12-25T00:00:00.000000+03:30",
    2856         "christmas in nyc": "\x00\x202010-12-25T00:00:00.000000-05:00",
    2857         "previous tests": "\x00\x202010-12-25T00:00:00.000000+03:19"
    2858                           "\x00\x202010-12-25T00:00:00.000000-06:59",
     2943        b"christmas": b"\x00\x202010-12-25T00:00:00.000000-00:00"
     2944                      b"\x00\x202010-12-25T00:00:00.000000-00:00",
     2945        b"christmas in eu": b"\x00\x202010-12-25T00:00:00.000000+01:00",
     2946        b"christmas in iran": b"\x00\x202010-12-25T00:00:00.000000+03:30",
     2947        b"christmas in nyc": b"\x00\x202010-12-25T00:00:00.000000-05:00",
     2948        b"previous tests": b"\x00\x202010-12-25T00:00:00.000000+03:19"
     2949                           b"\x00\x202010-12-25T00:00:00.000000-06:59",
    28592950    }
    28602951
    28612952    objects = {
    class ListOfOptionalTests(unittest.TestCase): 
    28922983        """
    28932984        stringList = amp.ListOf(amp.Integer())
    28942985        self.assertRaises(
    2895             TypeError, stringList.toBox, 'omitted', amp.AmpBox(),
     2986            TypeError, stringList.toBox, b'omitted', amp.AmpBox(),
    28962987            {'omitted': None}, None)
    28972988
    28982989
    class ListOfOptionalTests(unittest.TestCase): 
    29032994        """
    29042995        stringList = amp.ListOf(amp.Integer(), optional=True)
    29052996        strings = amp.AmpBox()
    2906         stringList.toBox('omitted', strings, {'omitted': None}, None)
     2997        stringList.toBox(b'omitted', strings, {b'omitted': None}, None)
    29072998        self.assertEqual(strings, {})
    29082999
    29093000
    class ListOfOptionalTests(unittest.TestCase): 
    29143005        """
    29153006        stringList = amp.ListOf(amp.Integer())
    29163007        self.assertRaises(
    2917             KeyError, stringList.toBox, 'ommited', amp.AmpBox(),
     3008            KeyError, stringList.toBox, b'ommited', amp.AmpBox(),
    29183009            {'someOtherKey': 0}, None)
    29193010
    29203011
    class ListOfOptionalTests(unittest.TestCase): 
    29243015        as optional whose key is not present in the objects dictionary.
    29253016        """
    29263017        stringList = amp.ListOf(amp.Integer(), optional=True)
    2927         stringList.toBox('ommited', amp.AmpBox(), {'someOtherKey': 0}, None)
     3018        stringList.toBox(b'ommited', amp.AmpBox(), {b'someOtherKey': 0}, None)
    29283019
    29293020
    29303021    def test_omittedOptionalArgumentDeserializesAsNone(self):
    class ListOfOptionalTests(unittest.TestCase): 
    29343025        """
    29353026        stringList = amp.ListOf(amp.Integer(), optional=True)
    29363027        objects = {}
    2937         stringList.fromBox('omitted', {}, objects, None)
     3028        stringList.fromBox(b'omitted', {}, objects, None)
    29383029        self.assertEqual(objects, {'omitted': None})
    29393030
    29403031
    29413032
     3033@implementer(interfaces.IUNIXTransport)
    29423034class UNIXStringTransport(object):
    29433035    """
    29443036    An in-memory implementation of L{interfaces.IUNIXTransport} which collects
    class UNIXStringTransport(object): 
    29483040        eg via C{write} or C{sendFileDescriptor}.  Elements are two-tuples of a
    29493041        string (identifying the destination of the data) and the data itself.
    29503042    """
    2951     implements(interfaces.IUNIXTransport)
    29523043
    29533044    def __init__(self, descriptorFuzz):
    29543045        """
    class DescriptorTests(unittest.TestCase): 
    30383129        state inspection and mutation.
    30393130        """
    30403131        argument = amp.Descriptor()
    3041         self.assertEqual("0", argument.toStringProto(2, self.protocol))
     3132        self.assertEqual(b"0", argument.toStringProto(2, self.protocol))
    30423133        self.assertEqual(
    30433134            ("fileDescriptorReceived", 2 + self.fuzz), self.transport._queue.pop(0))
    3044         self.assertEqual("1", argument.toStringProto(4, self.protocol))
     3135        self.assertEqual(b"1", argument.toStringProto(4, self.protocol))
    30453136        self.assertEqual(
    30463137            ("fileDescriptorReceived", 4 + self.fuzz), self.transport._queue.pop(0))
    3047         self.assertEqual("2", argument.toStringProto(6, self.protocol))
     3138        self.assertEqual(b"2", argument.toStringProto(6, self.protocol))
    30483139        self.assertEqual(
    30493140            ("fileDescriptorReceived", 6 + self.fuzz), self.transport._queue.pop(0))
    30503141        self.assertEqual({}, self.protocol._descriptors)
    class DescriptorTests(unittest.TestCase): 
    30563147        L{amp.Descriptor.toBox} to reconstruct a file descriptor value.
    30573148        """
    30583149        name = "alpha"
     3150        nameAsBytes = name.encode("ascii")
    30593151        strings = {}
    30603152        descriptor = 17
    30613153        sendObjects = {name: descriptor}
    30623154
    30633155        argument = amp.Descriptor()
    3064         argument.toBox(name, strings, sendObjects.copy(), self.protocol)
     3156        argument.toBox(nameAsBytes, strings, sendObjects.copy(), self.protocol)
    30653157
    30663158        receiver = amp.BinaryBoxProtocol(
    30673159            amp.BoxDispatcher(amp.CommandLocator()))
    class DescriptorTests(unittest.TestCase): 
    30693161            getattr(receiver, event[0])(*event[1:])
    30703162
    30713163        receiveObjects = {}
    3072         argument.fromBox(name, strings.copy(), receiveObjects, receiver)
     3164        argument.fromBox(
     3165            nameAsBytes, strings.copy(), receiveObjects, receiver)
    30733166
    30743167        # Make sure we got the descriptor.  Adjust by fuzz to be more convincing
    30753168        # of having gone through L{IUNIXTransport.sendFileDescriptor}, not just
    class DateTimeTests(unittest.TestCase): 
    30823175    """
    30833176    Tests for L{amp.DateTime}, L{amp._FixedOffsetTZInfo}, and L{amp.utc}.
    30843177    """
    3085     string = '9876-01-23T12:34:56.054321-01:23'
     3178    string = b'9876-01-23T12:34:56.054321-01:23'
    30863179    tzinfo = tz('-', 1, 23)
    30873180    object = datetime.datetime(9876, 1, 23, 12, 34, 56, 54321, tzinfo)
    30883181
    class UTCTests(unittest.TestCase): 
    31623255
    31633256
    31643257
     3258class RemoteAmpErrorTests(unittest.TestCase):
     3259    """
     3260    Tests for L{amp.RemoteAmpError}.
     3261    """
     3262
     3263    def test_stringMessage(self):
     3264        error = amp.RemoteAmpError(b"BROKEN", "Something has broken")
     3265        self.assertEqual("Code<BROKEN>: Something has broken", str(error))
     3266
     3267
     3268    def test_stringMessageReplacesNonAsciiText(self):
     3269        error = amp.RemoteAmpError(b"BROKEN-\xff", "Something has broken")
     3270        self.assertEqual("Code<BROKEN-\\xff>: Something has broken", str(error))
     3271
     3272
     3273    def test_stringMessageWithLocalFailure(self):
     3274        failure = Failure(Exception("Something came loose"))
     3275        error = amp.RemoteAmpError(
     3276            b"BROKEN", "Something has broken", local=failure)
     3277        self.assertRegexpMatches(
     3278            str(error), (
     3279                "^Code<BROKEN> [(]local[)]: Something has broken\n"
     3280                "Traceback [(]failure with no frames[)]: "
     3281                "<.+Exception.>: Something came loose\n"
     3282            ))
     3283
     3284
     3285
    31653286if not interfaces.IReactorSSL.providedBy(reactor):
    31663287    skipMsg = 'This test case requires SSL support in the reactor'
    31673288    TLSTests.skip = skipMsg
  • new file twisted/topfiles/6833.feature

    diff --git a/twisted/topfiles/6833.feature b/twisted/topfiles/6833.feature
    new file mode 100644
    index 0000000..dd2a030
    - +  
     1twisted.protocols.amp has been ported to Python 3.