diff --git a/OSC.py b/OSC.py index a65ae20..1472a30 100755 --- a/OSC.py +++ b/OSC.py @@ -159,17 +159,17 @@ """ import math, re, socket, select, string, struct, sys, threading, time, types, array, errno, inspect -from SocketServer import UDPServer, DatagramRequestHandler, ForkingMixIn, ThreadingMixIn, StreamRequestHandler, TCPServer +from socketserver import UDPServer, DatagramRequestHandler, ForkingMixIn, ThreadingMixIn, StreamRequestHandler, TCPServer from contextlib import closing global version version = ("0.3","6", "$Rev: 6382 $"[6:-2]) global FloatTypes -FloatTypes = [types.FloatType] +FloatTypes = [float] global IntTypes -IntTypes = [types.IntType] +IntTypes = [int] global NTP_epoch from calendar import timegm @@ -274,8 +274,8 @@ def append(self, argument, typehint=None): 'argument' may also be a list or tuple, in which case its elements will get appended one-by-one, all using the provided typehint """ - if type(argument) == types.DictType: - argument = argument.items() + if type(argument) == dict: + argument = list(argument.items()) elif isinstance(argument, OSCMessage): raise TypeError("Can only append 'OSCMessage' to 'OSCBundle'") @@ -314,7 +314,7 @@ def __repr__(self): def __str__(self): """Returns the Message's address and contents as a string. """ - return "%s %s" % (self.address, str(self.values())) + return "%s %s" % (self.address, str(list(self.values()))) def __len__(self): """Returns the number of arguments appended so far @@ -355,9 +355,9 @@ def __radd__(self, values): Returns the extended 'values' (list or tuple) """ out = list(values) - out.extend(self.values()) + out.extend(list(self.values())) - if type(values) == types.TupleType: + if type(values) == tuple: return tuple(out) return out @@ -384,7 +384,7 @@ def items(self): the arguments appended so far """ out = [] - values = self.values() + values = list(self.values()) typetags = self.tags() for i in range(len(values)): out.append((typetags[i], values[i])) @@ -394,32 +394,32 @@ def items(self): def __contains__(self, val): """Test if the given value appears in the OSCMessage's arguments """ - return (val in self.values()) + return (val in list(self.values())) def __getitem__(self, i): """Returns the indicated argument (or slice) """ - return self.values()[i] + return list(self.values())[i] def __delitem__(self, i): """Removes the indicated argument (or slice) """ - items = self.items() + items = list(self.items()) del items[i] self._reencode(items) def _buildItemList(self, values, typehint=None): if isinstance(values, OSCMessage): - items = values.items() - elif type(values) == types.ListType: + items = list(values.items()) + elif type(values) == list: items = [] for val in values: - if type(val) == types.TupleType: + if type(val) == tuple: items.append(val[:2]) else: items.append((typehint, val)) - elif type(values) == types.TupleType: + elif type(values) == tuple: items = [values[:2]] else: items = [(typehint, values)] @@ -431,11 +431,11 @@ def __setitem__(self, i, val): 'val' can be a single int/float/string, or a (typehint, value) tuple. Or, if 'i' is a slice, a list of these or another OSCMessage. """ - items = self.items() + items = list(self.items()) new_items = self._buildItemList(val) - if type(i) != types.SliceType: + if type(i) != slice: if len(new_items) != 1: raise TypeError("single-item assignment expects a single value or a (typetag, value) tuple") @@ -449,7 +449,7 @@ def __setitem__(self, i, val): def setItem(self, i, val, typehint=None): """Set indicated argument to a new value (with typehint) """ - items = self.items() + items = list(self.items()) items[i] = (typehint, val) @@ -466,19 +466,19 @@ def copy(self): def count(self, val): """Returns the number of times the given value occurs in the OSCMessage's arguments """ - return self.values().count(val) + return list(self.values()).count(val) def index(self, val): """Returns the index of the first occurence of the given value in the OSCMessage's arguments. Raises ValueError if val isn't found """ - return self.values().index(val) + return list(self.values()).index(val) def extend(self, values): """Append the contents of 'values' to this OSCMessage. 'values' can be another OSCMessage, or a list/tuple of ints/floats/strings """ - items = self.items() + self._buildItemList(values) + items = list(self.items()) + self._buildItemList(values) self._reencode(items) @@ -486,7 +486,7 @@ def insert(self, i, val, typehint = None): """Insert given value (with optional typehint) into the OSCMessage at the given index. """ - items = self.items() + items = list(self.items()) for item in reversed(self._buildItemList(val)): items.insert(i, item) @@ -497,7 +497,7 @@ def popitem(self, i): """Delete the indicated argument from the OSCMessage, and return it as a (typetag, value) tuple. """ - items = self.items() + items = list(self.items()) item = items.pop(i) @@ -513,7 +513,7 @@ def pop(self, i): def reverse(self): """Reverses the arguments of the OSCMessage (in place) """ - items = self.items() + items = list(self.items()) items.reverse() @@ -523,7 +523,7 @@ def remove(self, val): """Removes the first argument with the given value from the OSCMessage. Raises ValueError if val isn't found. """ - items = self.items() + items = list(self.items()) # this is not very efficient... i = 0 @@ -543,23 +543,23 @@ def remove(self, val): def __iter__(self): """Returns an iterator of the OSCMessage's arguments """ - return iter(self.values()) + return iter(list(self.values())) def __reversed__(self): """Returns a reverse iterator of the OSCMessage's arguments """ - return reversed(self.values()) + return reversed(list(self.values())) def itervalues(self): """Returns an iterator of the OSCMessage's arguments """ - return iter(self.values()) + return iter(list(self.values())) def iteritems(self): """Returns an iterator of the OSCMessage's arguments as (typetag, value) tuples """ - return iter(self.items()) + return iter(list(self.items())) def itertags(self): """Returns an iterator of the OSCMessage's arguments' typetags @@ -599,7 +599,7 @@ def __str__(self): out = "#bundle [" if self.__len__(): - for val in self.values(): + for val in list(self.values()): out += "%s, " % str(val) out = out[:-2] # strip trailing space and comma @@ -634,7 +634,7 @@ def append(self, argument, typehint = None): binary = OSCBlob(argument.getBinary()) else: msg = OSCMessage(self.address) - if type(argument) == types.DictType: + if type(argument) == dict: if 'addr' in argument: msg.setAddress(argument['addr']) if 'args' in argument: @@ -717,7 +717,7 @@ def OSCBlob(next): The blob ends with 0 to 3 zero-bytes ('\x00') """ - if type(next) in types.StringTypes: + if type(next) in str: OSCblobLength = math.ceil((len(next)) / 4.0) * 4 binary = struct.pack(">i%ds" % (OSCblobLength), OSCblobLength, next) else: @@ -776,9 +776,9 @@ def OSCTimeTag(time): if time > 0: fract, secs = math.modf(time) secs = secs - NTP_epoch - binary = struct.pack('>LL', long(secs), long(fract * NTP_units_per_second)) + binary = struct.pack('>LL', int(secs), int(fract * NTP_units_per_second)) else: - binary = struct.pack('>LL', 0L, 1L) + binary = struct.pack('>LL', 0, 1) return binary @@ -808,7 +808,7 @@ def _readInt(data): as a 32-bit integer. """ if(len(data)<4): - print "Error: too few bytes for int", data, len(data) + print("Error: too few bytes for int", data, len(data)) rest = data integer = 0 else: @@ -823,7 +823,7 @@ def _readLong(data): """ high, low = struct.unpack(">ll", data[0:8]) - big = (long(high) << 32) + low + big = (int(high) << 32) + low rest = data[8:] return (big, rest) @@ -845,7 +845,7 @@ def _readFloat(data): """ if(len(data)<4): - print "Error: too few bytes for float", data, len(data) + print("Error: too few bytes for float", data, len(data)) rest = data float = 0 else: @@ -860,7 +860,7 @@ def _readDouble(data): """ if(len(data)<8): - print "Error: too few bytes for double", data, len(data) + print("Error: too few bytes for double", data, len(data)) rest = data float = 0 else: @@ -913,7 +913,7 @@ def decodeOSC(data): def hexDump(bytes): """ Useful utility; prints the string in hexadecimal. """ - print "byte 0 1 2 3 4 5 6 7 8 9 A B C D E F" + print("byte 0 1 2 3 4 5 6 7 8 9 A B C D E F") num = len(bytes) for i in range(num): @@ -921,12 +921,12 @@ def hexDump(bytes): line = "%02X0 : " % (i/16) line += "%02X " % ord(bytes[i]) if (i+1) % 16 == 0: - print "%s: %s" % (line, repr(bytes[i-15:i+1])) + print("%s: %s" % (line, repr(bytes[i-15:i+1]))) line = "" bytes_left = num % 16 if bytes_left: - print "%s: %s" % (line.ljust(54), repr(bytes[-bytes_left:])) + print("%s: %s" % (line.ljust(54), repr(bytes[-bytes_left:]))) def getUrlStr(*args): """Convert provided arguments to a string in 'host:port/prefix' format @@ -939,7 +939,7 @@ def getUrlStr(*args): if not len(args): return "" - if type(args[0]) == types.TupleType: + if type(args[0]) == tuple: host = args[0][0] port = args[0][1] args = args[1:] @@ -961,7 +961,7 @@ def getUrlStr(*args): else: host = 'localhost' - if type(port) == types.IntType: + if type(port) == int: return "%s:%d%s" % (host, port, prefix) else: return host + prefix @@ -970,7 +970,7 @@ def parseUrlStr(url): """Convert provided string in 'host:port/prefix' format to it's components Returns ((host, port), prefix) """ - if not (type(url) in types.StringTypes and len(url)): + if not (type(url) in str and len(url)): return (None, '') i = url.find("://") @@ -1153,7 +1153,7 @@ def connect(self, address): try: self._ensureConnected(address) self.client_address = address - except socket.error, e: + except socket.error as e: self.client_address = None raise OSCClientError("SocketError: %s" % str(e)) @@ -1185,7 +1185,7 @@ def sendto(self, msg, address, timeout=None): if self.client_address: self.socket.connect(self.client_address) - except socket.error, e: + except socket.error as e: if e[0] in (7, 65): # 7 = 'no address associated with nodename', 65 = 'no route to host' raise e else: @@ -1215,7 +1215,7 @@ def send(self, msg, timeout=None): try: self.socket.sendall(msg.getBinary()) - except socket.error, e: + except socket.error as e: if e[0] in (7, 65): # 7 = 'no address associated with nodename', 65 = 'no route to host' raise e else: @@ -1234,7 +1234,7 @@ def parseFilterStr(args): """ out = {} - if type(args) in types.StringTypes: + if type(args) in str: args = [args] prefix = None @@ -1275,18 +1275,18 @@ def getFilterStr(filters): if not len(filters): return [] - if '/*' in filters.keys(): + if '/*' in list(filters.keys()): if filters['/*']: out = ["+/*"] else: out = ["-/*"] else: - if False in filters.values(): + if False in list(filters.values()): out = ["+/*"] else: out = ["-/*"] - for (addr, bool) in filters.items(): + for (addr, bool) in list(filters.items()): if addr == '/*': continue @@ -1298,7 +1298,7 @@ def getFilterStr(filters): return out # A translation-table for mapping OSC-address expressions to Python 're' expressions -OSCtrans = string.maketrans("{,}?","(|).") +OSCtrans = bytes.maketrans(b"{,}?", b"(|).") def getRegEx(pattern): """Compiles and returns a 'regular expression' object for the given address-pattern. @@ -1342,7 +1342,7 @@ def _searchHostAddr(self, host): except socket.error: pass - for addr in self.targets.keys(): + for addr in list(self.targets.keys()): if host == addr[0]: return addr @@ -1354,13 +1354,13 @@ def _updateFilters(self, dst, src): - src[a] == False and dst[a] == True: del dst[a] - a not in dst: dst[a] == src[a] """ - if '/*' in src.keys(): # reset filters + if '/*' in list(src.keys()): # reset filters dst.clear() # 'match everything' == no filters if not src.pop('/*'): dst['/*'] = False # 'match nothing' - for (addr, bool) in src.items(): - if (addr in dst.keys()) and (dst[addr] != bool): + for (addr, bool) in list(src.items()): + if (addr in list(dst.keys())) and (dst[addr] != bool): del dst[addr] else: dst[addr] = bool @@ -1371,7 +1371,7 @@ def _setTarget(self, address, prefix=None, filters=None): - prefix (string): The OSC-address prefix prepended to the address of each OSCMessage sent to this OSCTarget (optional) """ - if address not in self.targets.keys(): + if address not in list(self.targets.keys()): self.targets[address] = ["",{}] if prefix != None: @@ -1382,9 +1382,9 @@ def _setTarget(self, address, prefix=None, filters=None): self.targets[address][0] = prefix if filters != None: - if type(filters) in types.StringTypes: + if type(filters) in str: (_, filters) = parseFilterStr(filters) - elif type(filters) != types.DictType: + elif type(filters) != dict: raise TypeError("'filters' argument must be a dict with {addr:bool} entries") self._updateFilters(self.targets[address][1], filters) @@ -1396,10 +1396,10 @@ def setOSCTarget(self, address, prefix=None, filters=None): - prefix (string): The OSC-address prefix prepended to the address of each OSCMessage sent to this OSCTarget (optional) """ - if type(address) in types.StringTypes: + if type(address) in str: address = self._searchHostAddr(address) - elif (type(address) == types.TupleType): + elif (type(address) == tuple): (host, port) = address[:2] try: host = socket.gethostbyname(host) @@ -1438,10 +1438,10 @@ def delOSCTarget(self, address, prefix=None): the 'address' argument can be a ((host, port) tuple), or a hostname. If the 'prefix' argument is given, the Target is only deleted if the address and prefix match. """ - if type(address) in types.StringTypes: + if type(address) in str: address = self._searchHostAddr(address) - if type(address) == types.TupleType: + if type(address) == tuple: (host, port) = address[:2] try: host = socket.gethostbyname(host) @@ -1456,10 +1456,10 @@ def hasOSCTarget(self, address, prefix=None): the 'address' argument can be a ((host, port) tuple), or a hostname. If the 'prefix' argument is given, the return-value is only True if the address and prefix match. """ - if type(address) in types.StringTypes: + if type(address) in str: address = self._searchHostAddr(address) - if type(address) == types.TupleType: + if type(address) == tuple: (host, port) = address[:2] try: host = socket.gethostbyname(host) @@ -1467,7 +1467,7 @@ def hasOSCTarget(self, address, prefix=None): pass address = (host, port) - if address in self.targets.keys(): + if address in list(self.targets.keys()): if prefix == None: return True elif prefix == self.targets[address][0]: @@ -1479,7 +1479,7 @@ def getOSCTargets(self): """Returns the dict of OSCTargets: {addr:[prefix, filters], ...} """ out = {} - for ((host, port), pf) in self.targets.items(): + for ((host, port), pf) in list(self.targets.items()): try: (host, _, _) = socket.gethostbyaddr(host) except socket.error: @@ -1494,10 +1494,10 @@ def getOSCTarget(self, address): 'address' can be a (host, port) tuple, or a 'host' (string), in which case the first matching OSCTarget is returned Returns (None, ['',{}]) if address not found. """ - if type(address) in types.StringTypes: + if type(address) in str: address = self._searchHostAddr(address) - if (type(address) == types.TupleType): + if (type(address) == tuple): (host, port) = address[:2] try: host = socket.gethostbyname(host) @@ -1505,7 +1505,7 @@ def getOSCTarget(self, address): pass address = (host, port) - if (address in self.targets.keys()): + if (address in list(self.targets.keys())): try: (host, _, _) = socket.gethostbyaddr(host) except socket.error: @@ -1525,7 +1525,7 @@ def updateOSCTargets(self, dict): The given dict's items MUST be of the form { (host, port):[prefix, filters], ... } """ - for ((host, port), (prefix, filters)) in dict.items(): + for ((host, port), (prefix, filters)) in list(dict.items()): val = [prefix, {}] self._updateFilters(val[1], filters) @@ -1551,7 +1551,7 @@ def getOSCTargetStrings(self): """Returns a list of all OSCTargets as ('osc://:[]', ['', ...])' tuples. """ out = [] - for (addr, (prefix, filters)) in self.targets.items(): + for (addr, (prefix, filters)) in list(self.targets.items()): out.append(("osc://%s" % getUrlStr(addr, prefix), getFilterStr(filters))) return out @@ -1584,7 +1584,7 @@ def _filterMessage(self, filters, msg): """ if isinstance(msg, OSCBundle): out = msg.copy() - msgs = out.values() + msgs = list(out.values()) out.clearData() for m in msgs: m = self._filterMessage(filters, m) @@ -1592,13 +1592,13 @@ def _filterMessage(self, filters, msg): out.append(m) elif isinstance(msg, OSCMessage): - if '/*' in filters.keys(): + if '/*' in list(filters.keys()): if filters['/*']: out = msg else: out = None - elif False in filters.values(): + elif False in list(filters.values()): out = msg else: out = None @@ -1608,7 +1608,7 @@ def _filterMessage(self, filters, msg): expr = getRegEx(msg.address) - for addr in filters.keys(): + for addr in list(filters.keys()): if addr == '/*': continue @@ -1630,7 +1630,7 @@ def _prefixAddress(self, prefix, msg): out = msg.copy() if isinstance(msg, OSCBundle): - msgs = out.values() + msgs = list(out.values()) out.clearData() for m in msgs: out.append(self._prefixAddress(prefix, m)) @@ -1650,7 +1650,7 @@ def send(self, msg, timeout=None): this call blocks until socket is available for writing. Raises OSCClientError when timing out while waiting for the socket. """ - for (address, (prefix, filters)) in self.targets.items(): + for (address, (prefix, filters)) in list(self.targets.items()): if len(filters): out = self._filterMessage(filters, msg) if not out: # this catches 'None' and empty bundles. @@ -1675,7 +1675,7 @@ def send(self, msg, timeout=None): sent = self.socket.sendto(binary, address) binary = binary[sent:] - except socket.error, e: + except socket.error as e: if e[0] in (7, 65): # 7 = 'no address associated with nodename', 65 = 'no route to host' raise e else: @@ -1711,7 +1711,7 @@ def delMsgHandler(self, address): def getOSCAddressSpace(self): """Returns a list containing all OSC-addresses registerd with this Server. """ - return self.callbacks.keys() + return list(self.callbacks.keys()) def dispatchMessage(self, pattern, tags, data, client_address): """Attmept to match the given OSC-address pattern, which may contain '*', @@ -1731,7 +1731,7 @@ def dispatchMessage(self, pattern, tags, data, client_address): replies = [] matched = 0 - for addr in self.callbacks.keys(): + for addr in list(self.callbacks.keys()): match = expr.match(addr) if match and (match.end() == len(addr)): reply = self.callbacks[addr](pattern, tags, data, client_address) @@ -2172,7 +2172,7 @@ def serverInfo_handler(self, addr, tags, data, client_address): reply.append(('info_command', "clients | targets : list subscribed clients")) elif cmd in ('ls', 'list'): reply = OSCBundle(self.info_prefix) - for addr in self.callbacks.keys(): + for addr in list(self.callbacks.keys()): reply.append(('address', addr)) elif cmd in ('clients', 'targets'): if hasattr(self.client, 'getOSCTargetStrings'): @@ -2200,10 +2200,10 @@ def _subscribe(self, data, client_address): url = "" have_port = False for item in data: - if (type(item) == types.IntType) and not have_port: + if (type(item) == int) and not have_port: url += ":%d" % item have_port = True - elif type(item) in types.StringTypes: + elif type(item) in str: url += item (addr, tail) = parseUrlStr(url) @@ -2238,10 +2238,10 @@ def _unsubscribe(self, data, client_address): url = "" have_port = False for item in data: - if (type(item) == types.IntType) and not have_port: + if (type(item) == int) and not have_port: url += ":%d" % item have_port = True - elif type(item) in types.StringTypes: + elif type(item) in str: url += item (addr, _) = parseUrlStr(url) @@ -2262,7 +2262,7 @@ def _unsubscribe(self, data, client_address): try: self.client._delTarget(addr) - except NotSubscribedError, e: + except NotSubscribedError as e: txt = "%s: %s" % (e.__class__.__name__, str(e)) self.printErr(txt) @@ -2454,7 +2454,7 @@ def _unbundle(self, decoded): def setup(self): StreamRequestHandler.setup(self) - print "SERVER: New client connection." + print("SERVER: New client connection.") self.setupAddressSpace() self.server._clientRegister(self) @@ -2465,7 +2465,7 @@ def setupAddressSpace(self): def finish(self): StreamRequestHandler.finish(self) self.server._clientUnregister(self) - print "SERVER: Client connection handled." + print("SERVER: Client connection handled.") def _transmit(self, data): sent = 0 while sent < len(data): @@ -2492,7 +2492,7 @@ def _transmitMsg(self, msg): if self._transmit(len_big_endian) and self._transmit(binary): return True return False - except socket.error, e: + except socket.error as e: if e[0] == errno.EPIPE: # broken pipe return False raise e @@ -2518,14 +2518,14 @@ def _receiveMsg(self): # get OSC packet size from stream which is prepended each transmission chunk = self._receive(4) if chunk == None: - print "SERVER: Socket has been closed." + print("SERVER: Socket has been closed.") return None # extract message length from big endian unsigned long (32 bit) slen = struct.unpack(">L", chunk)[0] # receive the actual message chunk = self._receive(slen) if chunk == None: - print "SERVER: Socket has been closed." + print("SERVER: Socket has been closed.") return None # decode OSC data and dispatch msg = decodeOSC(chunk) @@ -2544,7 +2544,7 @@ def handle(self): # clean and blocking behaviour here self.connection.settimeout(None) - print "SERVER: Entered server loop" + print("SERVER: Entered server loop") try: while True: decoded = self._receiveMsg() @@ -2552,7 +2552,7 @@ def handle(self): return elif len(decoded) <= 0: # if message decoding fails we try to stay in sync but print a message - print "OSC stream server: Spurious message received." + print("OSC stream server: Spurious message received.") continue self.replies = [] @@ -2573,11 +2573,11 @@ def handle(self): if not txOk: break - except socket.error, e: + except socket.error as e: if e[0] == errno.ECONNRESET: # if connection has been reset by client, we do not care much # about it, we just assume our duty fullfilled - print "SERVER: Connection has been reset by peer." + print("SERVER: Connection has been reset by peer.") else: raise e @@ -2717,18 +2717,18 @@ def _receiveWithTimeout(self, count): tmp = self.socket.recv(count - len(chunk)) except socket.timeout: if not self._running: - print "CLIENT: Socket timed out and termination requested." + print("CLIENT: Socket timed out and termination requested.") return None else: continue - except socket.error, e: + except socket.error as e: if e[0] == errno.ECONNRESET: - print "CLIENT: Connection reset by peer." + print("CLIENT: Connection reset by peer.") return None else: raise e if not tmp or len(tmp) == 0: - print "CLIENT: Socket has been closed." + print("CLIENT: Socket has been closed.") return None chunk = chunk + tmp return chunk @@ -2753,7 +2753,7 @@ def _receiveMsgWithTimeout(self): return msg def _receiving_thread_entry(self): - print "CLIENT: Entered receiving thread." + print("CLIENT: Entered receiving thread.") self._running = True while self._running: decoded = self._receiveMsgWithTimeout() @@ -2777,7 +2777,7 @@ def _receiving_thread_entry(self): self._txMutex.release() if not txOk: break - print "CLIENT: Receiving thread terminated." + print("CLIENT: Receiving thread terminated.") def _unbundle(self, decoded): if decoded[0] != "#bundle": @@ -2810,13 +2810,13 @@ def _transmitWithTimeout(self, data): tmp = self.socket.send(data[sent:]) except socket.timeout: if not self._running: - print "CLIENT: Socket timed out and termination requested." + print("CLIENT: Socket timed out and termination requested.") return False else: continue - except socket.error, e: + except socket.error as e: if e[0] == errno.ECONNRESET: - print "CLIENT: Connection reset by peer." + print("CLIENT: Connection reset by peer.") return False else: raise e