diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..a098d0d --- /dev/null +++ b/.travis.yml @@ -0,0 +1,17 @@ +language: python +dist: trusty +sudo: required + +python: + - "2.7" + - "3.6" + +install: + - "pip install nose-cov" + - "pip install pep8" + - "pip install robotframework" + - "pip install six" + - "pip install ." + +script: + - python utest/run.py diff --git a/atest/Protocols.robot b/atest/Protocols.robot index 3875c6e..ed1c9c3 100644 --- a/atest/Protocols.robot +++ b/atest/Protocols.robot @@ -118,7 +118,7 @@ Server '${server}' should get '${msg}' from '${ip}':'${port}' Verify server gets from [Arguments] ${ip} ${port} ${expected} ${server} ${connection}= ${msg} ${from ip} ${from port} = Server receives binary from name=${server} connection=${connection} - Should be equal ${msg} ${expected} + Should be equal as Strings ${msg} ${expected} Should be equal ${from ip} ${ip} Should be equal as integers ${from port} ${port} diff --git a/atest/basic_network_operations.robot b/atest/basic_network_operations.robot index 89a9a41..818a0e4 100644 --- a/atest/basic_network_operations.robot +++ b/atest/basic_network_operations.robot @@ -8,12 +8,12 @@ Resource Protocols.robot TCP Client sends binary to server Client sends binary foo ${message}= Server receives binary - Should be equal ${message} foo + Should be equal as strings ${message} foo TCP Server sends binary to client Server sends binary foo ${message}= Client receives binary - Should be equal ${message} foo + Should be equal as strings ${message} foo Multiple UDP clients [Setup] Start two udp clients diff --git a/atest/ipv6.robot b/atest/ipv6.robot index 89ccd71..8cf47b7 100644 --- a/atest/ipv6.robot +++ b/atest/ipv6.robot @@ -35,7 +35,7 @@ IPv6 with protocols Client and server send and receive binary Client sends binary foo ${message}= Server receives binary - Should be equal ${message} foo + Should be equal as strings ${message} foo Server sends binary bar ${message}= Client receives binary - Should be equal ${message} bar + Should be equal as strings ${message} bar diff --git a/atest/terminated_fields.robot b/atest/terminated_fields.robot index 09d7c66..3928d15 100644 --- a/atest/terminated_fields.robot +++ b/atest/terminated_fields.robot @@ -16,7 +16,7 @@ Get message with chars and end byte long termination Message with chars and end byte 0x0d0a ${msg} get message arbitrary_length:foo.bar.zig Should be equal foo.bar.zig ${msg.arbitrary_length.ascii} - Should be equal foo.bar.zig\r\n ${msg.arbitrary_length._raw} + Should be equal as strings foo.bar.zig\r\n ${msg.arbitrary_length._raw} should be equal as integers 13 ${msg.arbitrary_length.len} Send and receive message with chars with end byte diff --git a/gen_docs.py b/gen_docs.py index cdd727e..7ae2740 100644 --- a/gen_docs.py +++ b/gen_docs.py @@ -2,6 +2,6 @@ from robot.libdoc import libdoc from os.path import join, dirname -execfile(join(dirname(__file__), 'src', 'Rammbock', 'version.py')) +exec(compile(open(join(dirname(__file__), 'src', 'Rammbock', 'version.py')).read(), 'version.py', 'exec')) libdoc(join(dirname(__file__),'src','Rammbock'), join(dirname(__file__),'Rammbock-%s.html' % VERSION)) \ No newline at end of file diff --git a/proto/generate_message_sequence.py b/proto/generate_message_sequence.py index a33ca39..37ae032 100644 --- a/proto/generate_message_sequence.py +++ b/proto/generate_message_sequence.py @@ -15,10 +15,10 @@ def _get_message_text(messages): return "Message content not found, run at DEBUG level to generate message contents" def _print_element(elem, separator): - print '\n'.join(kw_stack) - print separator - print _get_message_text(elem.findall('msg')) - print '--------------------------------------' + print('\n'.join(kw_stack)) + print(separator) + print(_get_message_text(elem.findall('msg'))) + print('--------------------------------------') for event, elem in ET.iterparse(source, events=('start', 'end')): if elem.tag not in ("kw", "test", "suite", "statistics"): diff --git a/setup.py b/setup.py index 88987f9..d7db796 100755 --- a/setup.py +++ b/setup.py @@ -3,15 +3,16 @@ from os.path import join, dirname, abspath CURDIR = dirname(abspath(__file__)) -execfile(join(CURDIR, 'src', 'Rammbock', 'version.py')) +exec(compile(open(join(CURDIR, 'src', 'Rammbock', 'version.py')).read(), 'version.py', 'exec')) -setup(name = 'robotframework-rammbock', - version = VERSION, - description = 'Protocol testing library for Robot Framework', - author = 'Robot Framework Developers', - author_email = 'robotframework-users@googlegroups.com', - url = 'http://github.com/robotframework/Rammbock/', - package_dir = {'' : 'src'}, - packages = ['Rammbock', 'Rammbock.templates'], - long_description = open(join(CURDIR, 'README.rst')).read() +setup(name='robotframework-rammbock', + version=VERSION, + description='Protocol testing library for Robot Framework', + author='Robot Framework Developers', + author_email='robotframework-users@googlegroups.com', + url='http://github.com/robotframework/Rammbock/', + package_dir={'': 'src'}, + packages=['Rammbock', 'Rammbock.templates'], + long_description=open(join(CURDIR, 'README.rst')).read(), + install_requires=['robotframework', 'six'] ) diff --git a/src/Rammbock/__init__.py b/src/Rammbock/__init__.py index 73c8176..673151b 100644 --- a/src/Rammbock/__init__.py +++ b/src/Rammbock/__init__.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -from rammbock import Rammbock +from .rammbock import Rammbock diff --git a/src/Rammbock/binary_tools.py b/src/Rammbock/binary_tools.py index f0c5ba9..bfe12f2 100644 --- a/src/Rammbock/binary_tools.py +++ b/src/Rammbock/binary_tools.py @@ -15,10 +15,12 @@ import binascii import struct +from robot.libraries.BuiltIn import BuiltIn + try: if bin(0): pass -except NameError, name_error: +except NameError as name_error: def bin(value): """ Support for Python 2.5 @@ -44,8 +46,8 @@ def bin(value): def to_bin(string_value): if string_value in (None, ''): - return '' - string_value = str(string_value) + return b'' + string_value = BuiltIn().convert_to_string(string_value) if string_value.startswith('0x'): return _hex_to_bin(string_value) elif string_value.startswith('0b'): @@ -55,9 +57,9 @@ def to_bin(string_value): def _int_to_bin(integer): - if integer >= 18446744073709551616L: + if integer >= 18446744073709551616: return to_bin(hex(integer)) - return LONGLONG.pack(integer).lstrip('\x00') or '\x00' + return LONGLONG.pack(integer).lstrip(b'\x00') or b'\x00' def _hex_to_bin(string_value): @@ -72,7 +74,7 @@ def to_bin_of_length(length, string_value): if len(bin) > length: raise AssertionError('Too long binary value %s (max length %d)' % (string_value, length)) - return bin.rjust(length, '\x00') + return bin.rjust(length, b'\x00') def to_hex(binary): @@ -80,7 +82,7 @@ def to_hex(binary): def to_0xhex(binary): - return '0x' + to_hex(binary) + return b'0x' + to_hex(binary) def to_binary_string_of_length(length, bytes): @@ -136,8 +138,9 @@ def _invert(value): def to_int(string_value): - if string_value in (None, ''): + if string_value in (None, '', b''): raise Exception("No value or empty value given") + string_value = BuiltIn().convert_to_string(string_value) if string_value.startswith('0x') or string_value[:3] == '-0x': return int(string_value, 16) elif string_value.startswith('0b') or string_value[:3] == '-0b': diff --git a/src/Rammbock/core.py b/src/Rammbock/core.py index 95317af..2b4870a 100644 --- a/src/Rammbock/core.py +++ b/src/Rammbock/core.py @@ -28,6 +28,9 @@ TBCDContainerTemplate) from .binary_tools import to_0xhex, to_bin +from robot.libraries.BuiltIn import BuiltIn +from robot.utils import is_string, PY3 + class RammbockCore(object): @@ -351,6 +354,8 @@ def client_sends_binary(self, message, name=None, label=None): | Client sends binary | Hello! | | Client sends binary | ${some binary} | Client1 | label=DebugMessage | """ + if PY3 and isinstance(message, str): + message = BuiltIn().convert_to_bytes(message) client, name = self._clients.get_with_name(name) client.send(message) self._register_send(client, label, name) @@ -367,6 +372,8 @@ def server_sends_binary(self, message, name=None, connection=None, label=None): | Server sends binary | ${some binary} | Server1 | label=DebugMessage | | Server sends binary | ${some binary} | connection=my_connection | """ + if PY3 and isinstance(message, str): + message = message.encode() server, name = self._servers.get_with_name(name) server.send(message, alias=connection) self._register_send(server, label, name, connection=connection) @@ -451,7 +458,7 @@ def save_template(self, name, unlocked=False): | Save Template | MyMessage | | Save Template | MyOtherMessage | unlocked=True | """ - if isinstance(unlocked, basestring): + if is_string(unlocked): unlocked = unlocked.lower() != 'false' template = self._get_message_template() if not unlocked: @@ -661,7 +668,7 @@ def _receive(self, nodes, *parameters): yield msg, message_fields, header_fields self._register_receive(node, self._current_container.name, name) logger.debug("Received %s" % repr(msg)) - except AssertionError, e: + except AssertionError as e: self._register_receive(node, self._current_container.name, name, error=e.args[0]) raise e @@ -992,6 +999,8 @@ def _name_and_value(self, separator, parameter): index = parameter.find(separator) try: key = str(parameter[:index].strip()) + if PY3: + key.encode('ascii') except UnicodeError: raise Exception("Only ascii characters are supported in parameters.") return key, parameter[index + 1:].strip() diff --git a/src/Rammbock/message.py b/src/Rammbock/message.py index ce3aa37..2ffb67a 100644 --- a/src/Rammbock/message.py +++ b/src/Rammbock/message.py @@ -16,8 +16,11 @@ from .binary_tools import to_0xhex, to_binary_string_of_length, \ to_bin_of_length, to_tbcd_value, to_tbcd_binary, from_twos_comp from .ordered_dict import OrderedDict +from robot.libraries.BuiltIn import BuiltIn +from robot.utils import py2to3, unic +@py2to3 class _StructuredElement(object): _type = None @@ -28,17 +31,17 @@ def __init__(self, name): self._parent = None def __setitem__(self, name, child): - self._fields[unicode(name)] = child + self._fields[unic(name)] = child child._parent = self def __getitem__(self, name): - return self._fields[unicode(name)] + return self._fields[unic(name)] def __getattr__(self, name): return self[name] def __delitem__(self, name): - name = unicode(name) + name = unic(name) item = self._fields[name] del self._fields[name] item._parent = None @@ -53,7 +56,7 @@ def __repr__(self): return result def __contains__(self, key): - return unicode(key) in self._fields + return unic(key) in self._fields def _format_indented(self, text): return ''.join([' %s\n' % line for line in text.splitlines()]) @@ -66,7 +69,7 @@ def _get_name(self): return '%s %s' % (self._type, self._name) def _get_raw_bytes(self): - return ''.join((field._raw for field in self._fields.values())) + return b''.join((field._raw for field in self._fields.values())) def __len__(self): return sum(len(field) for field in self._fields.values()) @@ -134,8 +137,8 @@ def _get_aligned(self, length): return length + (self._align - length % self._align) % self._align def _get_raw_bytes(self): - result = ''.join((field._raw for field in self._fields.values())) - return result.ljust(self._get_aligned(len(result)), '\x00') + result = b''.join((field._raw for field in self._fields.values())) + return result.ljust(self._get_aligned(len(result)), b'\x00') class Union(_StructuredElement): @@ -151,7 +154,7 @@ def _get_raw_bytes(self): for field in self._fields.values(): if len(field._raw) > len(max_raw): max_raw = field._raw - return max_raw.ljust(self._length, '\x00') + return max_raw.ljust(self._length, b'\x00') def __len__(self): return self._length @@ -169,7 +172,7 @@ def _binlength(self): return sum(field.binlength for field in self._fields.values()) def __len__(self): - return self._binlength() / 8 + return self._binlength() // 8 def _get_raw_bytes(self): # TODO: faster implementation... @@ -219,6 +222,7 @@ class Header(_StructuredElement): _type = 'Header' +@py2to3 class Field(object): def __init__(self, type, name, value, aligned_len=None, little_endian=False): @@ -258,15 +262,12 @@ def sint(self): @property def hex(self): - return hex(self) + return BuiltIn().convert_to_string(to_0xhex(self._value)) @property def tbcd(self): return to_tbcd_value(self._original_value) - def __hex__(self): - return to_0xhex(self._value) - def __nonzero__(self): return True @@ -287,11 +288,15 @@ def _bin(self): @property def ascii(self): - return ''.join(i for i in self._value if 128 > ord(i) >= 32) + try: + result = ''.join(i for i in self._value if 128 > ord(i) >= 32) + except TypeError: + result = ''.join(chr(i) for i in self._value if 128 > i >= 32) + return result @property def _raw(self): - return self._original_value.ljust(self._length, '\x00') + return self._original_value.ljust(self._length, b'\x00') def __str__(self): return str(self.__getattribute__(self._type)) diff --git a/src/Rammbock/networking.py b/src/Rammbock/networking.py index 5b4950c..43da3b8 100644 --- a/src/Rammbock/networking.py +++ b/src/Rammbock/networking.py @@ -19,6 +19,9 @@ from .synchronization import SynchronizedType from .binary_tools import to_hex +from robot.libraries.BuiltIn import BuiltIn +from six import itervalues + try: from sctp import sctpsocket_tcp SCTP_ENABLED = True @@ -97,10 +100,18 @@ def _get_from_stream(self, message_template, stream, timeout, header_filter, lat return stream.get(message_template, timeout=timeout, header_filter=header_filter, latest=latest) def log_send(self, binary, ip, port): - logger.debug("Send %d bytes: %s to %s:%s over %s" % (len(binary), to_hex(binary), ip, port, self._transport_layer_name)) + logger.debug("Send %d bytes: %s to %s:%s over %s" % (len(binary), + BuiltIn().convert_to_string(to_hex(binary)), + ip, + port, + self._transport_layer_name)) def log_receive(self, binary, ip, port): - logger.trace("Trying to read %d bytes: %s from %s:%s over %s" % (len(binary), to_hex(binary), ip, port, self._transport_layer_name)) + logger.trace("Trying to read %d bytes: %s from %s:%s over %s" % (len(binary), + BuiltIn().convert_to_string(to_hex(binary)), + ip, + port, + self._transport_layer_name)) def empty(self): result = True @@ -190,8 +201,8 @@ def __init__(self, ip, port, timeout=None): def _bind_socket(self): try: self._socket.bind((self._ip, self._port)) - except socket.error, e: - raise Exception("error: [Errno %d] %s for address %s:%d" % (e[0], e[1], self._ip, self._port)) + except socket.error as e: + raise Exception("error: [Errno %d] %s for address %s:%d" % (e.args[0], e.args[1], self._ip, self._port)) self._is_connected = True @@ -382,7 +393,7 @@ def get(self, name=None): return self.get_with_name(name)[0] def __iter__(self): - return self._cache.itervalues() + return itervalues(self._cache) def set_current(self, name): if name in self._cache: @@ -395,11 +406,11 @@ class BufferedStream(_WithTimeouts): def __init__(self, connection, default_timeout): self._connection = connection - self._buffer = '' + self._buffer = b'' self._default_timeout = default_timeout def read(self, size, timeout=None): - result = '' + result = b'' timeout = float(timeout if timeout else self._default_timeout) cutoff = time.time() + timeout while time.time() < cutoff: @@ -420,7 +431,7 @@ def _get(self, size): if size == -1: size = len(self._buffer) if not self._buffer: - return '' + return b'' result = self._buffer[:size] self._buffer = self._buffer[size:] return result @@ -429,4 +440,4 @@ def _fill_buffer(self, timeout): self._buffer += self._connection.receive(timeout=timeout) def empty(self): - self._buffer = '' + self._buffer = b'' diff --git a/src/Rammbock/ordered_dict.py b/src/Rammbock/ordered_dict.py index da3505e..87b7f6d 100644 --- a/src/Rammbock/ordered_dict.py +++ b/src/Rammbock/ordered_dict.py @@ -21,15 +21,28 @@ # Backport of OrderedDict() class that runs on Python 2.4, 2.5, 2.6, 2.7 and pypy. # Passes Python2.7's test suite and incorporates all the latest updates. -try: - from thread import get_ident as _get_ident -except ImportError: - from dummy_thread import get_ident as _get_ident - -try: - from _abcoll import KeysView, ValuesView, ItemsView -except ImportError: - pass +import sys + +from six import itervalues + +if sys.version_info < (3,): + try: + from thread import get_ident as _get_ident + except ImportError: + from dummy_thread import get_ident as _get_ident + try: + from collections import KeysView, ValuesView, ItemsView + except ImportError: + pass +else: + try: + from _thread import get_ident as _get_ident + except ImportError: + from _dummy_thread import get_ident as _get_ident + try: + from collections.abc import KeysView, ValuesView, ItemsView + except ImportError: + pass class OrderedDict(dict): @@ -98,7 +111,7 @@ def __reversed__(self): def clear(self): 'od.clear() -> None. Remove all items from od.' try: - for node in self.__map.itervalues(): + for node in itervalues(self.__map): del node[:] root = self.__root root[:] = [root, root, None] diff --git a/src/Rammbock/robotbackgroundlogger.py b/src/Rammbock/robotbackgroundlogger.py index 6a4c9d8..e229036 100644 --- a/src/Rammbock/robotbackgroundlogger.py +++ b/src/Rammbock/robotbackgroundlogger.py @@ -72,13 +72,13 @@ def log_background_messages(self, name=None): def _log_messages_by_thread(self, name): for message in self._messages.pop(name, []): - print message.format() + print(message.format()) def _log_all_messages(self): for thread in list(self._messages): - print "*HTML* Messages by '%s'" % thread + print("*HTML* Messages by '%s'" % thread) for message in self._messages.pop(thread): - print message.format() + print(message.format()) def reset_background_messages(self, name=None): with self.lock: diff --git a/src/Rammbock/templates/__init__.py b/src/Rammbock/templates/__init__.py index 7a7a894..99f731c 100644 --- a/src/Rammbock/templates/__init__.py +++ b/src/Rammbock/templates/__init__.py @@ -12,6 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -from containers import Protocol, MessageTemplate, StructTemplate, ListTemplate, \ +from .containers import Protocol, MessageTemplate, StructTemplate, ListTemplate, \ UnionTemplate, BinaryContainerTemplate, ConditionalTemplate, TBCDContainerTemplate -from primitives import UInt, Int, Char, PDU, Binary, Length, TBCD +from .primitives import UInt, Int, Char, PDU, Binary, Length, TBCD diff --git a/src/Rammbock/templates/containers.py b/src/Rammbock/templates/containers.py index c08c66d..6e97c25 100644 --- a/src/Rammbock/templates/containers.py +++ b/src/Rammbock/templates/containers.py @@ -18,8 +18,8 @@ from Rammbock.message import (Field, Union, Message, Header, List, Struct, BinaryContainer, BinaryField, TBCDContainer, Conditional, Bag) -from message_stream import MessageStream -from primitives import Length, Binary, TBCD, BagSize +from .message_stream import MessageStream +from .primitives import Length, Binary, TBCD, BagSize from Rammbock.ordered_dict import OrderedDict from Rammbock.binary_tools import (to_binary_string_of_length, to_bin, to_tbcd_value, to_tbcd_binary) @@ -76,7 +76,7 @@ def _get_field_recursive(self, field_name): if self.parent else None def _check_params_empty(self, message_fields, name): - for key in message_fields.keys(): + for key in list(message_fields): if key.startswith('*'): message_fields.pop(key) if message_fields: @@ -113,7 +113,7 @@ def validate(self, message, message_fields): def _get_params_sub_tree(self, params, name=None): result = {'*': params['*']} if '*' in params else {} name = name or self.name - for key in params.keys(): + for key in list(params): prefix, _, ending = key.partition('.') if prefix == name: result[ending] = params.pop(key) @@ -312,7 +312,7 @@ def validate(self, parent, message_fields, name=None): return errors + _Template.validate(self, message, self._get_params_sub_tree(message_fields, name)) def _add_struct_params(self, params): - for key in self._parameters.keys(): + for key in list(self._parameters): params[key] = self._parameters.pop(key) if key not in params else params[key] @@ -392,7 +392,7 @@ def _decode_one(self, data, bag, little_endian=False): logger.trace("'%s' matches in bag '%s'. value: %r" % (case.name, self.name, match[match.len - 1])) return match except Exception as e: - logger.trace("'%s' does not match in bag '%s'. Error: %s" % (case.name, self.name, e.message)) + logger.trace("'%s' does not match in bag '%s'. Error: %s" % (case.name, self.name, str(e))) raise AssertionError("Unable to decode bag value.") def _get_struct(self, name, parent): @@ -423,7 +423,7 @@ def __init__(self, size, parent): @property def field(self): - return self._fields.values()[0] + return list(self._fields.values())[0] def add(self, field): self.name = field.name @@ -488,7 +488,7 @@ def encode(self, message_params, parent, name=None, little_endian=False): @property def field(self): - return self._fields.values()[0] + return list(self._fields.values())[0] def _get_struct(self, name=None, parent=None): ls = List(name or self.name, self.field.type) @@ -520,7 +520,7 @@ def validate(self, parent, message_fields, name=None): def _get_params_sub_tree(self, params, name=None): result = OrderedDict({'*': params['*']} if '*' in params else {}) name = name or self.name - for key in params.keys(): + for key in list(params): self._consume_params_with_brackets(name, params, result, key) self._consume_dot_syntax(name, params, result, key) return result @@ -548,7 +548,7 @@ class BinaryContainerTemplate(_Template): type = 'BinaryContainer' def get_static_length(self): - return self.binlength / 8 + return self.binlength // 8 def add(self, field): if not isinstance(field, Binary): @@ -572,7 +572,7 @@ def decode(self, data, parent=None, name=None, little_endian=False): container = self._get_struct(name, parent, little_endian=little_endian) if little_endian: data = data[::-1] - bin_str = to_binary_string_of_length(self.binlength, data[:self.binlength / 8]) + bin_str = to_binary_string_of_length(self.binlength, data[:self.binlength // 8]) data_index = 2 for field in self._fields.values(): container[field.name] = self._create_field(bin_str, data_index, @@ -606,7 +606,7 @@ class TBCDContainerTemplate(_Template): type = 'TBCDContainer' def get_static_length(self): - return self.binlength / 8 + return self.binlength // 8 def _verify_not_little_endian(self, little_endian): if little_endian: diff --git a/src/Rammbock/templates/message_stream.py b/src/Rammbock/templates/message_stream.py index 2a40d29..10de28a 100644 --- a/src/Rammbock/templates/message_stream.py +++ b/src/Rammbock/templates/message_stream.py @@ -161,7 +161,10 @@ def _try_matching_cached_to_templates(self): def _call_handler_function(self, func, msg): func = self._get_call_handler(func) node, connection = self._get_node_and_connection() - args = func.func_code.co_argcount + try: + args = func.func_code.co_argcount + except AttributeError: + args = func.__code__.co_argcount if args == 3: return func(self._protocol.library, msg, node) if args == 4: diff --git a/src/Rammbock/templates/primitives.py b/src/Rammbock/templates/primitives.py index 5ec2213..ffee77e 100644 --- a/src/Rammbock/templates/primitives.py +++ b/src/Rammbock/templates/primitives.py @@ -20,8 +20,11 @@ from Rammbock.message import Field, BinaryField from Rammbock.binary_tools import to_bin_of_length, to_0xhex, to_tbcd_binary, \ to_tbcd_value, to_bin, to_twos_comp, to_int +from robot.libraries.BuiltIn import BuiltIn +from robot.utils import PY3, is_bytes, py2to3 +@py2to3 class _TemplateField(object): def __init__(self, name, default_value): @@ -67,24 +70,27 @@ def decode(self, data, message, name=None, little_endian=False): little_endian=little_endian and self.can_be_little_endian) def _prepare_data(self, data): - return data + return BuiltIn().convert_to_bytes(data) def validate(self, parent, paramdict, name=None): name = name or self.name field = parent[name] value = field.bytes forced_value = self._get_element_value_and_remove_from_params(paramdict, name) + forced_value_unicode = forced_value + if PY3 and is_bytes(forced_value): + forced_value_unicode = BuiltIn().convert_to_string(forced_value) try: - if not forced_value or forced_value == 'None': + if not forced_value_unicode or forced_value_unicode == 'None': return [] - elif forced_value.startswith('('): - return self._validate_pattern(forced_value, value, field) + elif forced_value_unicode.startswith('('): + return self._validate_pattern(forced_value_unicode, value, field) except AttributeError as e: e.args = ('Validating {}:{} failed. {}.\n Did you set default value as numeric object instead of string?' - .format(name, forced_value, e.args[0]),) + .format(name, forced_value_unicode, e.args[0]),) raise e - if forced_value.startswith('REGEXP'): - return self._validate_regexp(forced_value, value, field) + if forced_value_unicode.startswith('REGEXP'): + return self._validate_regexp(forced_value_unicode, value, field) return self._validate_exact_match(forced_value, value, field) def _validate_regexp(self, forced_pattern, value, field): @@ -97,7 +103,7 @@ def _validate_pattern(self, forced_pattern, value, field): if self._validate_masked(forced_pattern, value): return [] return ["Value of field '%s' does not match pattern '%s!=%s'" % - (field._get_recursive_name(), to_0xhex(value), forced_pattern)] + (field._get_recursive_name(), BuiltIn().convert_to_string(to_0xhex(value)), forced_pattern)] def _validate_or(self, forced_pattern, value, field): if forced_pattern.find('|') != -1: @@ -127,7 +133,7 @@ def _is_match(self, forced_value, value, parent): def _validate_exact_match(self, forced_value, value, field): if not self._is_match(forced_value, value, field._parent): return ['Value of field %s does not match %s!=%s' % - (field._get_recursive_name(), self._default_presentation_format(value), forced_value)] + (field._get_recursive_name(), BuiltIn().convert_to_string(self._default_presentation_format(value)), forced_value)] return [] def _default_presentation_format(self, value): @@ -146,7 +152,7 @@ def _get_recursive_name(self, parent): return parent._get_recursive_name() + self.name def _set_default_value(self, value): - self.default_value = str(value) if value and value != '""' else None + self.default_value = BuiltIn().convert_to_string(value) if value and value != '""' else None class PlaceHolderField(object): @@ -211,12 +217,17 @@ def _encode_value(self, value, message, little_endian=False): if isinstance(value, Field): value = value._value else: - value = str(value or '') + if not is_bytes(value): + value = str(value or '') + if PY3: + value = BuiltIn().convert_to_bytes(value) value += self._terminator length, aligned_length = self.length.find_length_and_set_if_necessary(message, len(value)) - return value.ljust(length, '\x00'), aligned_length + return value.ljust(length, b'\x00'), aligned_length def _prepare_data(self, data): + if PY3 and isinstance(data, str): + data = data.encode("UTF-8") if self._terminator: return data[0:data.index(self._terminator) + len(self._terminator)] return data @@ -509,7 +520,7 @@ def __init__(self, size): # TODO: add open range 2-n size = size.strip() if size == '*': - self._set_min_max(0, sys.maxint) + self._set_min_max(0, sys.maxsize) elif self.fixed.match(size): self._set_min_max(size, size) elif self.range.match(size): @@ -526,6 +537,6 @@ def _set_min_max(self, min_, max_): def __str__(self): if self.min == self.max: return str(self.min) - elif self.min == 0 and self.max == sys.maxint: + elif self.min == 0 and self.max == sys.maxsize: return '*' return '%s-%s' % (self.min, self.max) diff --git a/utest/test_binary_tools.py b/utest/test_binary_tools.py index f4d4228..7ef53cd 100644 --- a/utest/test_binary_tools.py +++ b/utest/test_binary_tools.py @@ -7,69 +7,69 @@ class TestBinaryConversions(TestCase): def test_empty_values_to_bin(self): - self.assertEquals('', to_bin(None)) - self.assertEquals('', to_bin('')) + self.assertEquals(b'', to_bin(None)) + self.assertEquals(b'', to_bin('')) def test_integer_to_bin(self): - self.assertEquals(to_bin(0), '\x00') - self.assertEquals(to_bin(5), '\x05') - self.assertEquals(to_bin(255), '\xff') - self.assertEquals(to_bin(256), '\x01\x00') - self.assertEquals(to_bin(18446744073709551615L), '\xff\xff\xff\xff\xff\xff\xff\xff') + self.assertEquals(to_bin(0), b'\x00') + self.assertEquals(to_bin(5), b'\x05') + self.assertEquals(to_bin(255), b'\xff') + self.assertEquals(to_bin(256), b'\x01\x00') + self.assertEquals(to_bin(18446744073709551615), b'\xff\xff\xff\xff\xff\xff\xff\xff') def test_string_integer_to_bin(self): - self.assertEquals(to_bin('0'), '\x00') - self.assertEquals(to_bin('5'), '\x05') - self.assertEquals(to_bin('255'), '\xff') - self.assertEquals(to_bin('256'), '\x01\x00') - self.assertEquals(to_bin('18446744073709551615'), '\xff\xff\xff\xff\xff\xff\xff\xff') + self.assertEquals(to_bin('0'), b'\x00') + self.assertEquals(to_bin('5'), b'\x05') + self.assertEquals(to_bin('255'), b'\xff') + self.assertEquals(to_bin('256'), b'\x01\x00') + self.assertEquals(to_bin('18446744073709551615'), b'\xff\xff\xff\xff\xff\xff\xff\xff') def test_binary_to_bin(self): - self.assertEquals(to_bin('0b0'), '\x00') - self.assertEquals(to_bin('0b1'), '\x01') - self.assertEquals(to_bin('0b1111 1111'), '\xff') - self.assertEquals(to_bin('0b1 0000 0000'), '\x01\x00') - self.assertEquals(to_bin('0b01 0b01 0b01'), '\x15') - self.assertEquals(to_bin('0b11' * 32), '\xff\xff\xff\xff\xff\xff\xff\xff') - self.assertEquals(to_bin('0b11' * 1024), '\xff\xff\xff\xff\xff\xff\xff\xff' * 32) + self.assertEquals(to_bin('0b0'), b'\x00') + self.assertEquals(to_bin('0b1'), b'\x01') + self.assertEquals(to_bin('0b1111 1111'), b'\xff') + self.assertEquals(to_bin('0b1 0000 0000'), b'\x01\x00') + self.assertEquals(to_bin('0b01 0b01 0b01'), b'\x15') + self.assertEquals(to_bin('0b11' * 32), b'\xff\xff\xff\xff\xff\xff\xff\xff') + self.assertEquals(to_bin('0b11' * 1024), b'\xff\xff\xff\xff\xff\xff\xff\xff' * 32) def test_hex_to_bin(self): - self.assertEquals(to_bin('0x0'), '\x00') - self.assertEquals(to_bin('0x00'), '\x00') - self.assertEquals(to_bin('0x5'), '\x05') - self.assertEquals(to_bin('0xff'), '\xff') - self.assertEquals(to_bin('0x100'), '\x01\x00') - self.assertEquals(to_bin('0x01 0x02 0x03'), '\x01\x02\x03') + self.assertEquals(to_bin('0x0'), b'\x00') + self.assertEquals(to_bin('0x00'), b'\x00') + self.assertEquals(to_bin('0x5'), b'\x05') + self.assertEquals(to_bin('0xff'), b'\xff') + self.assertEquals(to_bin('0x100'), b'\x01\x00') + self.assertEquals(to_bin('0x01 0x02 0x03'), b'\x01\x02\x03') def test_integer_larger_than_8_bytes_works(self): - self.assertEquals(to_bin('18446744073709551616'), '\x01\x00\x00\x00\x00\x00\x00\x00\x00') + self.assertEquals(to_bin('18446744073709551616'), b'\x01\x00\x00\x00\x00\x00\x00\x00\x00') def test_hex_larger_than_8_bytes_works(self): - self.assertEquals(to_bin('0xcafebabe f00dd00d deadbeef'), '\xca\xfe\xba\xbe\xf0\x0d\xd0\x0d\xde\xad\xbe\xef') + self.assertEquals(to_bin('0xcafebabe f00dd00d deadbeef'), b'\xca\xfe\xba\xbe\xf0\x0d\xd0\x0d\xde\xad\xbe\xef') def test_to_bin_of_length(self): - self.assertEquals(to_bin_of_length(1, 0), '\x00') - self.assertEquals(to_bin_of_length(2, 0), '\x00\x00') - self.assertEquals(to_bin_of_length(3, 256), '\x00\x01\x00') + self.assertEquals(to_bin_of_length(1, 0), b'\x00') + self.assertEquals(to_bin_of_length(2, 0), b'\x00\x00') + self.assertEquals(to_bin_of_length(3, 256), b'\x00\x01\x00') self.assertRaises(AssertionError, to_bin_of_length, 1, 256) def test_to_hex(self): - self.assertEquals(to_hex('\x00'), '00') - self.assertEquals(to_hex('\x00\x00'), '0000') - self.assertEquals(to_hex('\x00\xff\x00'), '00ff00') - self.assertEquals(to_hex('\xca\xfe\xba\xbe\xf0\x0d\xd0\x0d\xde\xad\xbe\xef'), 'cafebabef00dd00ddeadbeef') + self.assertEquals(to_hex(b'\x00'), b'00') + self.assertEquals(to_hex(b'\x00\x00'), b'0000') + self.assertEquals(to_hex(b'\x00\xff\x00'), b'00ff00') + self.assertEquals(to_hex(b'\xca\xfe\xba\xbe\xf0\x0d\xd0\x0d\xde\xad\xbe\xef'), b'cafebabef00dd00ddeadbeef') def test_to_0xhex(self): - self.assertEquals(to_0xhex('\x00'), '0x00') - self.assertEquals(to_0xhex('\xca\xfe\xba\xbe\xf0\x0d\xd0\x0d\xde\xad\xbe\xef'), '0xcafebabef00dd00ddeadbeef') + self.assertEquals(to_0xhex(b'\x00'), b'0x00') + self.assertEquals(to_0xhex(b'\xca\xfe\xba\xbe\xf0\x0d\xd0\x0d\xde\xad\xbe\xef'), b'0xcafebabef00dd00ddeadbeef') def test_to_0bbinary(self): - self.assertEquals(to_binary_string_of_length(1, '\x00'), '0b0') - self.assertEquals(to_binary_string_of_length(3, '\x00'), '0b000') - self.assertEquals(to_binary_string_of_length(9, '\x01\xff'), '0b111111111') - self.assertEquals(to_binary_string_of_length(12, '\x01\xff'), '0b000111111111') - self.assertEquals(to_binary_string_of_length(68, '\x01\x00\x00\x00\x00\x00\x00\x00\x00'), '0b0001' + ('0000' * 16)) - self.assertEquals(to_binary_string_of_length(2048, '\xff\xff\xff\xff\xff\xff\xff\xff' * 32), '0b' + ('11' * 1024)) + self.assertEquals(to_binary_string_of_length(1, b'\x00'), '0b0') + self.assertEquals(to_binary_string_of_length(3, b'\x00'), '0b000') + self.assertEquals(to_binary_string_of_length(9, b'\x01\xff'), '0b111111111') + self.assertEquals(to_binary_string_of_length(12, b'\x01\xff'), '0b000111111111') + self.assertEquals(to_binary_string_of_length(68, b'\x01\x00\x00\x00\x00\x00\x00\x00\x00'), '0b0001' + ('0000' * 16)) + self.assertEquals(to_binary_string_of_length(2048, b'\xff\xff\xff\xff\xff\xff\xff\xff' * 32), '0b' + ('11' * 1024)) def test_to_tbcd_value(self): self.assertEquals('1', to_tbcd_value(to_bin('0b11110001'))) diff --git a/utest/test_messages.py b/utest/test_messages.py index 8c7d6b7..4556ca2 100644 --- a/utest/test_messages.py +++ b/utest/test_messages.py @@ -30,7 +30,7 @@ def test_conversions(self): self.assertEquals(field.int, 0x00616200) self.assertEquals(field.hex, '0x00616200') self.assertEquals(field.ascii, 'ab') - self.assertEquals(field.bytes, '\x00\x61\x62\x00') + self.assertEquals(field.bytes, b'\x00\x61\x62\x00') self.assertEquals(field.chars, 'ab') self.assertEquals(field.bin, '0b00000000' + '01100001' + '01100010' + '00000000') diff --git a/utest/test_networking.py b/utest/test_networking.py index 61fc773..774db49 100644 --- a/utest/test_networking.py +++ b/utest/test_networking.py @@ -29,17 +29,17 @@ def tearDown(self): return TestCase.tearDown(self) def _verify_emptying(self, server, client): - client.send('to connect') + client.send(b'to connect') server.receive() - client.send('before emptying') - server.send('before emptying') + client.send(b'before emptying') + server.send(b'before emptying') time.sleep(0.01) client.empty() server.empty() - client.send('after') - server.send('after') - self._assert_receive(client, 'after') - self._assert_receive(server, 'after') + client.send(b'after') + server.send(b'after') + self._assert_receive(client, b'after') + self._assert_receive(server, b'after') def _assert_timeout(self, node, timeout=None): self._assert_timeout_with_type(node, socket.timeout, timeout) @@ -79,25 +79,25 @@ class TestNetworking(_NetworkingTests): def test_send_and_receive_udp(self): server, client = self._udp_server_and_client(ports['SERVER_PORT'], ports['CLIENT_PORT']) - client.send('foofaa') - self._assert_receive(server, 'foofaa') + client.send(b'foofaa') + self._assert_receive(server, b'foofaa') def test_server_send_udp(self): server, client = self._udp_server_and_client(ports['SERVER_PORT'], ports['CLIENT_PORT']) - server.send_to('foofaa', LOCAL_IP, ports['CLIENT_PORT']) - self._assert_receive(client, 'foofaa') + server.send_to(b'foofaa', LOCAL_IP, ports['CLIENT_PORT']) + self._assert_receive(client, b'foofaa') def test_server_send_tcp(self): server, client = self._tcp_server_and_client(ports['SERVER_PORT']) server.accept_connection() - server.send('foofaa') - self._assert_receive(client, 'foofaa') + server.send(b'foofaa') + self._assert_receive(client, b'foofaa') def test_send_and_receive_tcp(self): server, client = self._tcp_server_and_client(ports['SERVER_PORT']) - client.send('foofaa') + client.send(b'foofaa') server.accept_connection() - self._assert_receive(server, 'foofaa') + self._assert_receive(server, b'foofaa') def test_tcp_server_with_queued_connections(self): server, client = self._tcp_server_and_client(ports['SERVER_PORT']) @@ -115,18 +115,18 @@ def test_tcp_server_with_no_connections(self): server = TCPServer(LOCAL_IP, 1338) client = TCPClient() client.connect_to(LOCAL_IP, 1338) - client.send('foofaa') + client.send(b'foofaa') self.assertRaises(AssertionError, server.receive) def test_setting_port_no_ip(self): server, client = self._udp_server_and_client(ports['SERVER_PORT'], ports['CLIENT_PORT'], client_ip='') - server.send_to('foofaa', LOCAL_IP, client.get_own_address()[1]) - self._assert_receive(client, 'foofaa') + server.send_to(b'foofaa', LOCAL_IP, client.get_own_address()[1]) + self._assert_receive(client, b'foofaa') def test_setting_ip_no_port(self): server, client = self._udp_server_and_client(ports['SERVER_PORT'], '') - server.send_to('foofaa', *client.get_own_address()) - self._assert_receive(client, 'foofaa') + server.send_to(b'foofaa', *client.get_own_address()) + self._assert_receive(client, b'foofaa') def test_setting_client_default_timeout(self): _, client = self._udp_server_and_client(ports['SERVER_PORT'], ports['CLIENT_PORT'], timeout=0.1) @@ -186,9 +186,9 @@ def test_connection_timeout_failure(self): # FIXME: this deadlocks def xtest_blocking_timeout(self): server, client = self._udp_server_and_client(ports['SERVER_PORT'], ports['CLIENT_PORT'], timeout=0.1) - t = Timer(0.2, client.send, args=['foofaa']) + t = Timer(0.2, client.send, args=[b'foofaa']) t.start() - self.assertEquals(server.receive(timeout='blocking'), 'foofaa') + self.assertEquals(server.receive(timeout='blocking'), b'foofaa') def test_empty_udp_stream(self): server, client = self._udp_server_and_client(ports['SERVER_PORT'], ports['CLIENT_PORT'], timeout=0.1) @@ -204,7 +204,7 @@ class TestGetEndPoints(_NetworkingTests): def test_get_udp_endpoints(self): server, client = self._udp_server_and_client(ports['SERVER_PORT'], ports['CLIENT_PORT']) - client.send('foofaa') + client.send(b'foofaa') server.receive() self.assertEquals(client.get_own_address(), (LOCAL_IP, ports['CLIENT_PORT'])) self.assertEquals(server.get_own_address(), (LOCAL_IP, ports['SERVER_PORT'])) @@ -230,7 +230,7 @@ def _get_template(): class TestBufferedStream(TestCase): - DATA = 'foobardiibadaa' + DATA = b'foobardiibadaa' def setUp(self): self._buffered_stream = BufferedStream(MockConnection(self.DATA), 0.1) @@ -239,9 +239,9 @@ def test_normal_read(self): self.assertEquals(self.DATA, self._buffered_stream.read(len(self.DATA))) def test_empty(self): - self._buffered_stream.read(len('foobar')) + self._buffered_stream.read(len(b'foobar')) self._buffered_stream.empty() - self.assertRaises(AssertionError, self._buffered_stream.read, len(self.DATA) - len('foobar')) + self.assertRaises(AssertionError, self._buffered_stream.read, len(self.DATA) - len(b'foobar')) def test_read_all(self): data = self._buffered_stream.read(-1) @@ -249,9 +249,9 @@ def test_read_all(self): def test_read_and_return(self): self._buffered_stream.read(-1) - self._buffered_stream.return_data('badaa') + self._buffered_stream.return_data(b'badaa') data = self._buffered_stream.read(-1) - self.assertEquals(data, 'badaa') + self.assertEquals(data, b'badaa') class MockConnection(object): @@ -261,7 +261,7 @@ def __init__(self, mock_data_to_receive): def receive(self, timeout): ret = self._data - self._data = '' + self._data = b'' return ret diff --git a/utest/test_rammbock.py b/utest/test_rammbock.py index 9e9dd16..9fd2379 100644 --- a/utest/test_rammbock.py +++ b/utest/test_rammbock.py @@ -82,13 +82,13 @@ def test_validation_failure(self): def test_send_binary_without_protocol(self): self._start_client_server() - self.rammbock.client_sends_binary('foobar') + self.rammbock.client_sends_binary(b'foobar') self._sequence_should_equal(self.rammbock._message_sequence.get(), [['Client', '127.0.0.1:12345', 'binary', '', 'sent']]) def test_receive_binary_without_protocol(self): self._start_client_server() - self.rammbock.client_sends_binary('foobar') + self.rammbock.client_sends_binary(b'foobar') self.rammbock.server_receives_binary() self._sequence_should_equal(self.rammbock._message_sequence.get(), [['Client', 'Server', 'binary', '', 'received']]) diff --git a/utest/test_templates/test_bags.py b/utest/test_templates/test_bags.py index 5de1625..b7bec87 100644 --- a/utest/test_templates/test_bags.py +++ b/utest/test_templates/test_bags.py @@ -6,7 +6,7 @@ class TestBagSize(TestCase): def test_free_size(self): - self._assert_min_max('*', 0, sys.maxint) + self._assert_min_max('*', 0, sys.maxsize) def test_fixed_size(self): self._assert_min_max('1', 1, 1) diff --git a/utest/test_templates/test_message_stream.py b/utest/test_templates/test_message_stream.py index ff64e0e..50da93b 100644 --- a/utest/test_templates/test_message_stream.py +++ b/utest/test_templates/test_message_stream.py @@ -18,7 +18,7 @@ def test_read_header_and_pdu(self): stream = MockStream(to_bin('0xff0004cafe')) header, data = self._protocol.read(stream) self.assertEquals(header.id.hex, '0xff') - self.assertEquals(data, '\xca\xfe') + self.assertEquals(data, b'\xca\xfe') class TestMessageStream(TestCase): diff --git a/utest/test_templates/test_message_templates.py b/utest/test_templates/test_message_templates.py index b05f4b1..62c207c 100644 --- a/utest/test_templates/test_message_templates.py +++ b/utest/test_templates/test_message_templates.py @@ -28,7 +28,7 @@ def test_message_field_type_conversions(self): msg = self.tmp.encode({'field_1': 1024}, {}) self.assertEquals(msg.field_1.int, 1024) self.assertEquals(msg.field_1.hex, '0x0400') - self.assertEquals(msg.field_1.bytes, '\x04\x00') + self.assertEquals(msg.field_1.bytes, b'\x04\x00') def test_encode_template_with_params(self): msg = self.tmp.encode({'field_1': 111, 'field_2': 222}, {}) diff --git a/utest/test_templates/test_primitives.py b/utest/test_templates/test_primitives.py index fe62014..cff330d 100644 --- a/utest/test_templates/test_primitives.py +++ b/utest/test_templates/test_primitives.py @@ -28,14 +28,14 @@ def test_char_static_field(self): self.assertEquals(field.name, "char_field") self.assertEquals(field.default_value, 'foo') self.assertEquals(field.type, 'chars') - self.assertEquals(field.encode({}, {}, None)._raw, 'foo\x00\x00') - self.assertEquals(field.encode({}, {}, None).bytes, 'foo\x00\x00') + self.assertEquals(field.encode({}, {}, None)._raw, b'foo\x00\x00') + self.assertEquals(field.encode({}, {}, None).bytes, b'foo\x00\x00') def test_set_char_value_from_message_field(self): - msg_field = Field('chars', 'char_field', '\x00a\x00b', aligned_len=5) + msg_field = Field('chars', 'char_field', b'\x00a\x00b', aligned_len=5) field = Char(5, "char_field", '') - self.assertEquals(field.encode({'char_field': msg_field}, {}, None)._raw, '\x00a\x00b\x00') - self.assertEquals(field.encode({'char_field': msg_field}, {}, None).bytes, '\x00a\x00b\x00') + self.assertEquals(field.encode({'char_field': msg_field}, {}, None)._raw, b'\x00a\x00b\x00') + self.assertEquals(field.encode({'char_field': msg_field}, {}, None).bytes, b'\x00a\x00b\x00') def test_binary_field(self): field = Binary(3, 'field', 1) @@ -118,8 +118,8 @@ def test_little_endian_int_decode(self): def test_little_endian_char_decode(self): template = Char(5, 'field', None) field = template.decode('hello', None, little_endian=True) - self.assertEquals(field._raw, 'hello') - self.assertEquals(field.bytes, 'hello') + self.assertEquals(field._raw, b'hello') + self.assertEquals(field.bytes, b'hello') self.assertEquals(field.ascii, 'hello') def test_little_endian_uint_encode(self): @@ -158,7 +158,7 @@ def test_validate_int(self): self._should_fail(Int(2, 'field', 'REGEXP:.*').validate({'field': field}, {}), 1) def test_validate_chars(self): - field = Field('chars', 'field', 'foo\x00\x00') + field = Field('chars', 'field', b'foo\x00\x00') field_regEx = Field('chars', 'field', '{ Message In Braces }') self._should_pass(Char(5, 'field', 'foo').validate({'field': field}, {})) self._should_pass(Char(5, 'field', '(what|foo|bar)').validate({'field': field}, {}))