Support python3.

Import queue on python3 and Queue on python2. Use bytestrings for all
string constants. Slice byte arrays when comparing to bytestrings. Don't
use basestring. Gear now expects its packet data to be byte strings.
Non data fields may be passed as unicode strings, bytes or bytearrays.
Unicode strings will be converted to bytes using the utf8 encoding.

Change-Id: Iccdd01f9ce6f649f8bbaa93370d330c78c89f087
This commit is contained in:
Clark Boylan 2013-06-03 20:09:34 -07:00
parent 8336e63685
commit 1e76bfa886
3 changed files with 126 additions and 106 deletions

View File

@ -1,4 +1,4 @@
[DEFAULT] [DEFAULT]
test_command=OS_TEST_TIMEOUT=60 ${PYTHON:-python} -m subunit.run discover -t ./ . $LISTOPT $IDOPTION test_command=OS_TEST_TIMEOUT=60 ${PYTHON:-python} -m subunit.run discover -t ./ gear/tests/ $LISTOPT $IDOPTION
test_id_option=--load-list $IDFILE test_id_option=--load-list $IDFILE
test_list_option=--list test_list_option=--list

View File

@ -14,7 +14,6 @@
import logging import logging
import os import os
import Queue
import select import select
import socket import socket
import struct import struct
@ -24,6 +23,11 @@ import uuid as uuid_module
from gear import constants from gear import constants
try:
import Queue as queue
except ImportError:
import queue as queue
PRECEDENCE_NORMAL = 0 PRECEDENCE_NORMAL = 0
PRECEDENCE_LOW = 1 PRECEDENCE_LOW = 1
PRECEDENCE_HIGH = 2 PRECEDENCE_HIGH = 2
@ -61,6 +65,14 @@ class GearmanError(Exception):
pass pass
def convert_to_bytes(data):
try:
data = data.encode('utf8')
except AttributeError:
pass
return data
class Task(object): class Task(object):
def __init__(self): def __init__(self):
self._wait_event = threading.Event() self._wait_event = threading.Event()
@ -208,7 +220,7 @@ class Connection(object):
if not c: if not c:
return None return None
if admin is None: if admin is None:
if c == '\x00': if c == b'\x00':
admin = False admin = False
else: else:
admin = True admin = True
@ -244,15 +256,15 @@ class Connection(object):
This method waits until the echo response has been received or the This method waits until the echo response has been received or the
timeout has been reached. timeout has been reached.
:arg str data: The data to request be echoed. If None, a random :arg bytes data: The data to request be echoed. If None, a random
unique string will be generated. unique byte string will be generated.
:arg numeric timeout: Number of seconds to wait until the response :arg numeric timeout: Number of seconds to wait until the response
is received. If None, wait forever (default: 30 seconds). is received. If None, wait forever (default: 30 seconds).
:raises TimeoutError: If the timeout is reached before the response :raises TimeoutError: If the timeout is reached before the response
is received. is received.
""" """
if data is None: if data is None:
data = str(uuid_module.uuid4().hex) data = uuid_module.uuid4().hex.encode('utf8')
self.echo_lock.acquire() self.echo_lock.acquire()
try: try:
if data in self.echo_conditions: if data in self.echo_conditions:
@ -302,15 +314,15 @@ class AdminRequest(object):
instantiated dircectly; a subclass implementing a specific command instantiated dircectly; a subclass implementing a specific command
must be used instead. must be used instead.
:arg list arguments: A list of string arguments for the command. :arg list arguments: A list of byte string arguments for the command.
The following instance attributes are available: The following instance attributes are available:
**response** (str) **response** (bytes)
The response from the server. The response from the server.
**arguments** (str) **arguments** (bytes)
The argument supplied with the constructor. The argument supplied with the constructor.
**command** (str) **command** (bytes)
The administrative command. The administrative command.
""" """
@ -333,15 +345,15 @@ class AdminRequest(object):
def getCommand(self): def getCommand(self):
cmd = self.command cmd = self.command
if self.arguments: if self.arguments:
cmd += ' ' + ' '.join(self.arguments) cmd += b' ' + b' '.join(self.arguments)
cmd += '\n' cmd += b'\n'
return cmd return cmd
def isComplete(self, data): def isComplete(self, data):
if (data[-3:] == '\n.\n' or if (data[-3:] == b'\n.\n' or
data[-5:] == '\r\n.\r\n' or data[-5:] == b'\r\n.\r\n' or
data == '.\n' or data == b'.\n' or
data == '.\r\n'): data == b'.\r\n'):
self.response = data self.response = data
return True return True
return False return False
@ -359,7 +371,7 @@ class StatusAdminRequest(AdminRequest):
The response from gearman may be found in the **response** attribute. The response from gearman may be found in the **response** attribute.
""" """
command = 'status' command = b'status'
def __init__(self): def __init__(self):
super(StatusAdminRequest, self).__init__() super(StatusAdminRequest, self).__init__()
@ -370,7 +382,7 @@ class ShowJobsAdminRequest(AdminRequest):
The response from gearman may be found in the **response** attribute. The response from gearman may be found in the **response** attribute.
""" """
command = 'show jobs' command = b'show jobs'
def __init__(self): def __init__(self):
super(ShowJobsAdminRequest, self).__init__() super(ShowJobsAdminRequest, self).__init__()
@ -382,7 +394,7 @@ class ShowUniqueJobsAdminRequest(AdminRequest):
The response from gearman may be found in the **response** attribute. The response from gearman may be found in the **response** attribute.
""" """
command = 'show unique jobs' command = b'show unique jobs'
def __init__(self): def __init__(self):
super(ShowUniqueJobsAdminRequest, self).__init__() super(ShowUniqueJobsAdminRequest, self).__init__()
@ -396,13 +408,14 @@ class CancelJobAdminRequest(AdminRequest):
The response from gearman may be found in the **response** attribute. The response from gearman may be found in the **response** attribute.
""" """
command = 'cancel job' command = b'cancel job'
def __init__(self, handle): def __init__(self, handle):
handle = convert_to_bytes(handle)
super(CancelJobAdminRequest, self).__init__(handle) super(CancelJobAdminRequest, self).__init__(handle)
def isComplete(self, data): def isComplete(self, data):
if data[-1] == '\n': if data[-1:] == b'\n':
self.response = data self.response = data
return True return True
return False return False
@ -414,13 +427,13 @@ class VersionAdminRequest(AdminRequest):
The response from gearman may be found in the **response** attribute. The response from gearman may be found in the **response** attribute.
""" """
command = 'version' command = b'version'
def __init__(self): def __init__(self):
super(VersionAdminRequest, self).__init__() super(VersionAdminRequest, self).__init__()
def isComplete(self, data): def isComplete(self, data):
if data[-1] == '\n': if data[-1:] == b'\n':
self.response = data self.response = data
return True return True
return False return False
@ -430,22 +443,26 @@ class Packet(object):
"""A data packet received from or to be sent over a """A data packet received from or to be sent over a
:py:class:`Connection`. :py:class:`Connection`.
:arg str code: The Gearman magic code (:py:data:`constants.REQ` or :arg bytes code: The Gearman magic code (:py:data:`constants.REQ` or
:py:data:`constants.RES`) :py:data:`constants.RES`)
:arg str ptype: The packet type (one of the packet types in constasts). :arg bytes ptype: The packet type (one of the packet types in constasts).
:arg str data: The data portion of the packet. :arg bytes data: The data portion of the packet.
:arg str connection: The connection on which the packet was received :arg Connection connection: The connection on which the packet
(optional). was received (optional).
:raises InvalidDataError: If the magic code is unknown. :raises InvalidDataError: If the magic code is unknown.
""" """
log = logging.getLogger("gear.Packet") log = logging.getLogger("gear.Packet")
def __init__(self, code, ptype, data, connection=None): def __init__(self, code, ptype, data, connection=None):
if code[0] != '\x00': if not isinstance(code, bytes) and not isinstance(code, bytearray):
raise TypeError("code must be of type bytes or bytearray")
if code[0:1] != b'\x00':
raise InvalidDataError("First byte of packet must be 0") raise InvalidDataError("First byte of packet must be 0")
self.code = code self.code = code
self.ptype = ptype self.ptype = ptype
if not isinstance(data, bytes) and not isinstance(data, bytearray):
raise TypeError("data must be of type bytes or bytearray")
self.data = data self.data = data
self.connection = connection self.connection = connection
@ -457,15 +474,11 @@ class Packet(object):
"""Return a Gearman wire protocol binary representation of the packet. """Return a Gearman wire protocol binary representation of the packet.
:returns: The packet in binary form. :returns: The packet in binary form.
:rtype: str :rtype: bytes
""" """
b = struct.pack('!4sii', self.code, self.ptype, len(self.data)) b = struct.pack('!4sii', self.code, self.ptype, len(self.data))
b = bytearray(b) b = bytearray(b)
if isinstance(self.data, basestring): b += self.data
data = bytearray(self.data, 'utf8')
else:
data = self.data
b += data
return b return b
def getArgument(self, index, last=False): def getArgument(self, index, last=False):
@ -475,7 +488,7 @@ class Packet(object):
:arg bool last: Whether this is the last argument (and thus :arg bool last: Whether this is the last argument (and thus
nulls should be ignored) nulls should be ignored)
:returns: The argument value. :returns: The argument value.
:rtype: str :rtype: bytes
""" """
parts = self.data.split(b'\x00') parts = self.data.split(b'\x00')
@ -488,7 +501,7 @@ class Packet(object):
this packet. this packet.
:returns: The :py:class:`Job` for this packet. :returns: The :py:class:`Job` for this packet.
:rtype: str :rtype: Job
:raises UnknownJobError: If the job is not known. :raises UnknownJobError: If the job is not known.
""" """
handle = self.getArgument(0) handle = self.getArgument(0)
@ -563,7 +576,7 @@ class BaseClientServer(object):
self.inactive_connections.remove(conn) self.inactive_connections.remove(conn)
self.active_connections.append(conn) self.active_connections.append(conn)
self.connections_condition.notifyAll() self.connections_condition.notifyAll()
os.write(self.wake_write, '1\n') os.write(self.wake_write, b'1\n')
self.connections_condition.release() self.connections_condition.release()
try: try:
@ -632,7 +645,7 @@ class BaseClientServer(object):
if fd == self.wake_read: if fd == self.wake_read:
self.log.debug("Woken by pipe") self.log.debug("Woken by pipe")
while True: while True:
if os.read(self.wake_read, 1) == '\n': if os.read(self.wake_read, 1) == b'\n':
break break
return return
conn = conn_dict[fd] conn = conn_dict[fd]
@ -877,7 +890,7 @@ class BaseClientServer(object):
self.running = False self.running = False
self.connections_condition.acquire() self.connections_condition.acquire()
self.connections_condition.notifyAll() self.connections_condition.notifyAll()
os.write(self.wake_write, '1\n') os.write(self.wake_write, b'1\n')
self.connections_condition.release() self.connections_condition.release()
def _cleanup(self): def _cleanup(self):
@ -1093,6 +1106,7 @@ class Client(BaseClient):
:rtype: bool :rtype: bool
""" """
tasks = {} tasks = {}
name = convert_to_bytes(name)
self.broadcast_lock.acquire() self.broadcast_lock.acquire()
try: try:
@ -1140,10 +1154,10 @@ class Client(BaseClient):
is supplied. is supplied.
""" """
if job.unique is None: if job.unique is None:
unique = '' unique = b''
else: else:
unique = job.unique unique = job.unique
data = '%s\x00%s\x00%s' % (job.name, unique, job.arguments) data = b'\x00'.join((job.name, unique, job.arguments))
if background: if background:
if precedence == PRECEDENCE_NORMAL: if precedence == PRECEDENCE_NORMAL:
cmd = constants.SUBMIT_JOB_BG cmd = constants.SUBMIT_JOB_BG
@ -1418,11 +1432,11 @@ class Worker(BaseClient):
log = logging.getLogger("gear.Worker") log = logging.getLogger("gear.Worker")
def __init__(self, worker_id): def __init__(self, worker_id):
self.worker_id = worker_id self.worker_id = convert_to_bytes(worker_id)
self.functions = {} self.functions = {}
self.job_lock = threading.Lock() self.job_lock = threading.Lock()
self.waiting_for_jobs = 0 self.waiting_for_jobs = 0
self.job_queue = Queue.Queue() self.job_queue = queue.Queue()
super(Worker, self).__init__() super(Worker, self).__init__()
def __repr__(self): def __repr__(self):
@ -1437,6 +1451,7 @@ class Worker(BaseClient):
:arg str name: The name of the function to register. :arg str name: The name of the function to register.
:arg numeric timeout: The timeout value (optional). :arg numeric timeout: The timeout value (optional).
""" """
name = convert_to_bytes(name)
self.functions[name] = FunctionRecord(name, timeout) self.functions[name] = FunctionRecord(name, timeout)
if timeout: if timeout:
self._sendCanDoTimeout(name, timeout) self._sendCanDoTimeout(name, timeout)
@ -1448,6 +1463,7 @@ class Worker(BaseClient):
:arg str name: The name of the function to remove. :arg str name: The name of the function to remove.
""" """
name = convert_to_bytes(name)
del self.functions[name] del self.functions[name]
self._sendCantDo(name) self._sendCantDo(name)
@ -1488,7 +1504,7 @@ class Worker(BaseClient):
def _sendCanDoTimeout(self, name, timeout): def _sendCanDoTimeout(self, name, timeout):
self.broadcast_lock.acquire() self.broadcast_lock.acquire()
try: try:
data = name + '\x00' + timeout data = name + b'\x00' + timeout
p = Packet(constants.REQ, constants.CAN_DO_TIMEOUT, data) p = Packet(constants.REQ, constants.CAN_DO_TIMEOUT, data)
self.broadcast(p) self.broadcast(p)
finally: finally:
@ -1505,17 +1521,17 @@ class Worker(BaseClient):
def _sendResetAbilities(self): def _sendResetAbilities(self):
self.broadcast_lock.acquire() self.broadcast_lock.acquire()
try: try:
p = Packet(constants.REQ, constants.RESET_ABILITIES, '') p = Packet(constants.REQ, constants.RESET_ABILITIES, b'')
self.broadcast(p) self.broadcast(p)
finally: finally:
self.broadcast_lock.release() self.broadcast_lock.release()
def _sendPreSleep(self, connection): def _sendPreSleep(self, connection):
p = Packet(constants.REQ, constants.PRE_SLEEP, '') p = Packet(constants.REQ, constants.PRE_SLEEP, b'')
self.sendPacket(p, connection) self.sendPacket(p, connection)
def _sendGrabJobUniq(self, connection=None): def _sendGrabJobUniq(self, connection=None):
p = Packet(constants.REQ, constants.GRAB_JOB_UNIQ, '') p = Packet(constants.REQ, constants.GRAB_JOB_UNIQ, b'')
if connection: if connection:
self.sendPacket(p, connection) self.sendPacket(p, connection)
else: else:
@ -1530,7 +1546,7 @@ class Worker(BaseClient):
super(Worker, self)._onConnect(conn) super(Worker, self)._onConnect(conn)
for f in self.functions.values(): for f in self.functions.values():
if f.timeout: if f.timeout:
data = f.name + '\x00' + f.timeout data = f.name + b'\x00' + f.timeout
p = Packet(constants.REQ, constants.CAN_DO_TIMEOUT, data) p = Packet(constants.REQ, constants.CAN_DO_TIMEOUT, data)
else: else:
p = Packet(constants.REQ, constants.CAN_DO, f.name) p = Packet(constants.REQ, constants.CAN_DO, f.name)
@ -1580,7 +1596,7 @@ class Worker(BaseClient):
try: try:
job = self.job_queue.get(False) job = self.job_queue.get(False)
except Queue.Empty: except queue.Empty:
job = None job = None
if not job: if not job:
@ -1702,7 +1718,7 @@ class Worker(BaseClient):
handle = packet.getArgument(0) handle = packet.getArgument(0)
name = packet.getArgument(1) name = packet.getArgument(1)
unique = packet.getArgument(2) unique = packet.getArgument(2)
if unique == '': if unique == b'':
unique = None unique = None
arguments = packet.getArgument(3, True) arguments = packet.getArgument(3, True)
return self._handleJobAssignment(packet, handle, name, return self._handleJobAssignment(packet, handle, name,
@ -1729,9 +1745,12 @@ class BaseJob(object):
log = logging.getLogger("gear.Job") log = logging.getLogger("gear.Job")
def __init__(self, name, arguments, unique=None, handle=None): def __init__(self, name, arguments, unique=None, handle=None):
self.name = name self.name = convert_to_bytes(name)
if (not isinstance(arguments, bytes) and
not isinstance(arguments, bytearray)):
raise TypeError("arguments must be of type bytes or bytearray")
self.arguments = arguments self.arguments = arguments
self.unique = unique self.unique = convert_to_bytes(unique)
self.handle = handle self.handle = handle
self.connection = None self.connection = None
@ -1744,26 +1763,26 @@ class Job(BaseJob):
"""A job to run or being run by Gearman. """A job to run or being run by Gearman.
:arg str name: The name of the job. :arg str name: The name of the job.
:arg str arguments: The opaque data blob to be passed to the worker :arg bytes arguments: The opaque data blob to be passed to the worker
as arguments. as arguments.
:arg str unique: A string to uniquely identify the job to Gearman :arg str unique: A byte string to uniquely identify the job to Gearman
(optional). (optional).
The following instance attributes are available: The following instance attributes are available:
**name** (str) **name** (str)
The name of the job. The name of the job.
**arguments** (str) **arguments** (bytes)
The opaque data blob passed to the worker as arguments. The opaque data blob passed to the worker as arguments.
**unique** (str or None) **unique** (str or None)
The unique ID of the job (if supplied). The unique ID of the job (if supplied).
**handle** (str or None) **handle** (bytes or None)
The Gearman job handle. None if no job handle has been received yet. The Gearman job handle. None if no job handle has been received yet.
**data** (list of byte-arrays) **data** (list of byte-arrays)
The result data returned from Gearman. Each packet appends an The result data returned from Gearman. Each packet appends an
element to the list. Depending on the nature of the data, the element to the list. Depending on the nature of the data, the
elements may need to be concatenated before use. elements may need to be concatenated before use.
**exception** (str or None) **exception** (bytes or None)
Exception information returned from Gearman. None if no exception Exception information returned from Gearman. None if no exception
has been received. has been received.
**warning** (bool) **warning** (bool)
@ -1772,10 +1791,10 @@ class Job(BaseJob):
Whether the job is complete. Whether the job is complete.
**failure** (bool) **failure** (bool)
Whether the job has failed. Only set when complete is True. Whether the job has failed. Only set when complete is True.
**numerator** (str or None) **numerator** (bytes or None)
The numerator of the completion ratio reported by the worker. The numerator of the completion ratio reported by the worker.
Only set when a status update is sent by the worker. Only set when a status update is sent by the worker.
**denominator** (str or None) **denominator** (bytes or None)
The denominator of the completion ratio reported by the The denominator of the completion ratio reported by the
worker. Only set when a status update is sent by the worker. worker. Only set when a status update is sent by the worker.
**fraction_complete** (float or None) **fraction_complete** (float or None)
@ -1815,20 +1834,20 @@ class WorkerJob(BaseJob):
:arg str handle: The job handle assigned by gearman. :arg str handle: The job handle assigned by gearman.
:arg str name: The name of the job. :arg str name: The name of the job.
:arg str arguments: The opaque data blob passed to the worker :arg bytes arguments: The opaque data blob passed to the worker
as arguments. as arguments.
:arg str unique: A string to uniquely identify the job to Gearman :arg str unique: A byte string to uniquely identify the job to Gearman
(optional). (optional).
The following instance attributes are available: The following instance attributes are available:
**name** (str) **name** (str)
The name of the job. The name of the job.
**arguments** (str) **arguments** (bytes)
The opaque data blob passed to the worker as arguments. The opaque data blob passed to the worker as arguments.
**unique** (str or None) **unique** (str or None)
The unique ID of the job (if supplied). The unique ID of the job (if supplied).
**handle** (str) **handle** (bytes)
The Gearman job handle. The Gearman job handle.
**connection** (:py:class:`Connection` or None) **connection** (:py:class:`Connection` or None)
The connection associated with the job. Only set after the job The connection associated with the job. Only set after the job
@ -1840,23 +1859,23 @@ class WorkerJob(BaseJob):
def __init__(self, handle, name, arguments, unique=None): def __init__(self, handle, name, arguments, unique=None):
super(WorkerJob, self).__init__(name, arguments, unique, handle) super(WorkerJob, self).__init__(name, arguments, unique, handle)
def sendWorkData(self, data=''): def sendWorkData(self, data=b''):
"""Send a WORK_DATA packet to the client. """Send a WORK_DATA packet to the client.
:arg str data: The data to be sent to the client (optional). :arg bytes data: The data to be sent to the client (optional).
""" """
data = self.handle + '\x00' + data data = self.handle + b'\x00' + data
p = Packet(constants.REQ, constants.WORK_DATA, data) p = Packet(constants.REQ, constants.WORK_DATA, data)
self.connection.sendPacket(p) self.connection.sendPacket(p)
def sendWorkWarning(self, data=''): def sendWorkWarning(self, data=b''):
"""Send a WORK_WARNING packet to the client. """Send a WORK_WARNING packet to the client.
:arg str data: The data to be sent to the client (optional). :arg bytes data: The data to be sent to the client (optional).
""" """
data = self.handle + '\x00' + data data = self.handle + b'\x00' + data
p = Packet(constants.REQ, constants.WORK_WARNING, data) p = Packet(constants.REQ, constants.WORK_WARNING, data)
self.connection.sendPacket(p) self.connection.sendPacket(p)
@ -1870,18 +1889,19 @@ class WorkerJob(BaseJob):
:arg numeric denominator: The denominator of the fraction complete. :arg numeric denominator: The denominator of the fraction complete.
""" """
data = (self.handle + '\x00' + data = (self.handle + b'\x00' +
str(numerator) + '\x00' + str(denominator)) str(numerator).encode('utf8') + b'\x00' +
str(denominator).encode('utf8'))
p = Packet(constants.REQ, constants.WORK_STATUS, data) p = Packet(constants.REQ, constants.WORK_STATUS, data)
self.connection.sendPacket(p) self.connection.sendPacket(p)
def sendWorkComplete(self, data=''): def sendWorkComplete(self, data=b''):
"""Send a WORK_COMPLETE packet to the client. """Send a WORK_COMPLETE packet to the client.
:arg str data: The data to be sent to the client (optional). :arg bytes data: The data to be sent to the client (optional).
""" """
data = self.handle + '\x00' + data data = self.handle + b'\x00' + data
p = Packet(constants.REQ, constants.WORK_COMPLETE, data) p = Packet(constants.REQ, constants.WORK_COMPLETE, data)
self.connection.sendPacket(p) self.connection.sendPacket(p)
@ -1891,13 +1911,14 @@ class WorkerJob(BaseJob):
p = Packet(constants.REQ, constants.WORK_FAIL, self.handle) p = Packet(constants.REQ, constants.WORK_FAIL, self.handle)
self.connection.sendPacket(p) self.connection.sendPacket(p)
def sendWorkException(self, data=''): def sendWorkException(self, data=b''):
"""Send a WORK_EXCEPTION packet to the client. """Send a WORK_EXCEPTION packet to the client.
:arg str data: The exception data to be sent to the client (optional). :arg bytes data: The exception data to be sent to the client
(optional).
""" """
data = self.handle + '\x00' + data data = self.handle + b'\x00' + data
p = Packet(constants.REQ, constants.WORK_EXCEPTION, data) p = Packet(constants.REQ, constants.WORK_EXCEPTION, data)
self.connection.sendPacket(p) self.connection.sendPacket(p)
@ -1912,7 +1933,7 @@ class ServerAdminRequest(AdminRequest):
self.connection = connection self.connection = connection
def isComplete(self, data): def isComplete(self, data):
if data[-1] == '\n': if data[-1:] == b'\n':
self.command = data.strip() self.command = data.strip()
return True return True
return False return False
@ -1946,7 +1967,7 @@ class Server(BaseClientServer):
"""A simple gearman server implementation for testing """A simple gearman server implementation for testing
(not for production use). (not for production use).
:arg str port: The TCP port on which to listen. :arg int port: The TCP port on which to listen.
""" """
def __init__(self, port=4730): def __init__(self, port=4730):
@ -2005,7 +2026,7 @@ class Server(BaseClientServer):
if fd == self.connect_wake_read: if fd == self.connect_wake_read:
self.log.debug("Accept woken by pipe") self.log.debug("Accept woken by pipe")
while True: while True:
if os.read(self.connect_wake_read, 1) == '\n': if os.read(self.connect_wake_read, 1) == b'\n':
break break
return return
if event & select.POLLIN: if event & select.POLLIN:
@ -2016,12 +2037,12 @@ class Server(BaseClientServer):
self.connections_condition.acquire() self.connections_condition.acquire()
self.active_connections.append(conn) self.active_connections.append(conn)
self.connections_condition.notifyAll() self.connections_condition.notifyAll()
os.write(self.wake_write, '1\n') os.write(self.wake_write, b'1\n')
self.connections_condition.release() self.connections_condition.release()
def _shutdown(self): def _shutdown(self):
super(Server, self)._shutdown() super(Server, self)._shutdown()
os.write(self.connect_wake_write, '1\n') os.write(self.connect_wake_write, b'1\n')
def _cleanup(self): def _cleanup(self):
super(Server, self)._cleanup() super(Server, self)._cleanup()
@ -2037,9 +2058,9 @@ class Server(BaseClientServer):
self.connections_condition.release() self.connections_condition.release()
def handleAdminRequest(self, request): def handleAdminRequest(self, request):
if request.command.startswith('cancel job'): if request.command.startswith(b'cancel job'):
self.handleCancelJob(request) self.handleCancelJob(request)
elif request.command.startswith('status'): elif request.command.startswith(b'status'):
self.handleStatus(request) self.handleStatus(request)
def handleCancelJob(self, request): def handleCancelJob(self, request):
@ -2051,9 +2072,9 @@ class Server(BaseClientServer):
if handle == job.handle: if handle == job.handle:
self.queue.remove(job) self.queue.remove(job)
del self.jobs[handle] del self.jobs[handle]
request.connection.conn.send("OK\n") request.connection.conn.send(b'OK\n')
return return
request.connection.conn.send("ERR UNKNOWN_JOB\n") request.connection.conn.send(b'ERR UNKNOWN_JOB\n')
def handleStatus(self, request): def handleStatus(self, request):
functions = {} functions = {}
@ -2070,13 +2091,13 @@ class Server(BaseClientServer):
for function in connection.functions: for function in connection.functions:
functions[function][2] += 1 functions[function][2] += 1
for name, values in functions.items(): for name, values in functions.items():
request.connection.conn.send("%s\t%s\t%s\t%s\n" % request.connection.conn.send(("%s\t%s\t%s\t%s\n" %
(name, values[0], values[1], (name, values[0], values[1],
values[2])) values[2])).encode('utf8'))
request.connection.conn.send(".\n") request.connection.conn.send(b'.\n')
def wakeConnections(self): def wakeConnections(self):
p = Packet(constants.RES, constants.NOOP, '') p = Packet(constants.RES, constants.NOOP, b'')
for connection in self.active_connections: for connection in self.active_connections:
if connection.state == 'SLEEP': if connection.state == 'SLEEP':
connection.sendPacket(p) connection.sendPacket(p)
@ -2089,8 +2110,8 @@ class Server(BaseClientServer):
unique = None unique = None
arguments = packet.getArgument(2, True) arguments = packet.getArgument(2, True)
packet.connection.max_handle += 1 packet.connection.max_handle += 1
handle = 'H:%s:%s' % (packet.connection.host, handle = ('H:%s:%s' % (packet.connection.host,
str(packet.connection.max_handle)) packet.connection.max_handle)).encode('utf8')
job = Job(name, arguments, unique) job = Job(name, arguments, unique)
job.handle = handle job.handle = handle
job.connection = packet.connection job.connection = packet.connection
@ -2119,14 +2140,13 @@ class Server(BaseClientServer):
def sendJobAssignUniq(self, connection, job): def sendJobAssignUniq(self, connection, job):
unique = job.unique unique = job.unique
if not unique: if not unique:
unique = '' unique = b''
data = '%s\x00%s\x00%s\x00%s' % (job.handle, job.name, data = b'\x00'.join((job.handle, job.name, unique, job.arguments))
unique, job.arguments)
p = Packet(constants.RES, constants.JOB_ASSIGN_UNIQ, data) p = Packet(constants.RES, constants.JOB_ASSIGN_UNIQ, data)
connection.sendPacket(p) connection.sendPacket(p)
def sendNoJob(self, connection): def sendNoJob(self, connection):
p = Packet(constants.RES, constants.NO_JOB, "") p = Packet(constants.RES, constants.NO_JOB, b'')
connection.sendPacket(p) connection.sendPacket(p)
def handlePreSleep(self, packet): def handlePreSleep(self, packet):
@ -2194,8 +2214,8 @@ class Server(BaseClientServer):
known = 0 known = 0
running = 0 running = 0
numerator = '' numerator = b''
denominator = '' denominator = b''
job = self.jobs.get(handle) job = self.jobs.get(handle)
if job: if job:
known = 1 known = 1
@ -2204,10 +2224,10 @@ class Server(BaseClientServer):
numerator = job.numerator numerator = job.numerator
denominator = job.denominator denominator = job.denominator
data = (handle + '\x00' + data = (handle + b'\x00' +
str(known) + '\x00' + str(known).encode('utf8') + b'\x00' +
str(running) + '\x00' + str(running).encode('utf8') + b'\x00' +
str(numerator) + '\x00' + numerator + b'\x00' +
str(denominator)) denominator)
p = Packet(constants.RES, constants.STATUS_RES, data) p = Packet(constants.RES, constants.STATUS_RES, data)
packet.connection.sendPacket(p) packet.connection.sendPacket(p)

View File

@ -79,5 +79,5 @@ for i, name in types.items():
globals()[name] = i globals()[name] = i
__doc__ += '\n.. py:data:: %s\n' % name __doc__ += '\n.. py:data:: %s\n' % name
REQ = '\x00REQ' REQ = b'\x00REQ'
RES = '\x00RES' RES = b'\x00RES'