Skip to content

Commit

Permalink
merge scott maxwell\'s python 3 patches into master and fix tests
Browse files Browse the repository at this point in the history
  • Loading branch information
mcdonc committed Nov 23, 2013
2 parents 09af9e1 + dd7d2e1 commit 98c5676
Show file tree
Hide file tree
Showing 86 changed files with 3,121 additions and 1,206 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Expand Up @@ -13,3 +13,5 @@ dist/
nosetests.xml
supervisor/coverage.xml
tmp/
env*/
.idea/
8 changes: 8 additions & 0 deletions CHANGES.txt
@@ -1,6 +1,14 @@
3.1a1 (Next Release)
--------------------

Python 3 related
~~~~~~~~~~~~~~~~

- The ``supervisor`` package is no longer a namespace package.

Other
~~~~~

- Stopping a process in the backoff state now changes it to the stopped
state. Previously, an attempt to stop a process in backoff would be
ignored. Patch by Pascal Varet.
Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Expand Up @@ -6,7 +6,7 @@ exclude=medusa
where=supervisor
nocapture=1
cover-package=supervisor
with-coverage=1
#with-coverage=1
cover-erase=1

[bdist_rpm]
Expand Down
19 changes: 8 additions & 11 deletions setup.py
Expand Up @@ -15,19 +15,17 @@
import os
import sys

if sys.version_info[:2] < (2, 4) or sys.version_info[0] > 2:
msg = ("Supervisor requires Python 2.4 or later but does not work on "
"any version of Python 3. You are using version %s. Please "
"install using a supported version." % sys.version)
if sys.version_info[:2] < (2, 5):
msg = ("Supervisor requires Python 2.5 or later. You are using version %s. "
"Please install using a supported version." % sys.version)
sys.stderr.write(msg)
sys.exit(1)

requires = ['meld3 >= 0.6.5']

if sys.version_info[:2] < (2, 5):
# for meld3 (it's a distutils package)
requires.append('elementtree')

tests_require = []
if sys.version_info[:2] < (3, 3):
tests_require.append('mock')

from setuptools import setup, find_packages
here = os.path.abspath(os.path.dirname(__file__))
try:
Expand Down Expand Up @@ -68,10 +66,9 @@
packages = find_packages(),
install_requires = requires,
extras_require = {'iterparse':['cElementTree >= 1.0.2']},
tests_require = ['mock >= 0.5.0'],
tests_require = tests_require,
include_package_data = True,
zip_safe = False,
namespace_packages = ['supervisor'],
test_suite = "supervisor.tests",
entry_points = {
'console_scripts': [
Expand Down
9 changes: 8 additions & 1 deletion supervisor/__init__.py
@@ -1 +1,8 @@
__import__('pkg_resources').declare_namespace(__name__)
#__import__('pkg_resources').declare_namespace(__name__)

def read_file(filename, mode='r'):
f = open(filename, mode)
content = f.read()
f.close()
return content

7 changes: 6 additions & 1 deletion supervisor/childutils.py
@@ -1,6 +1,11 @@
import sys
import time
import xmlrpclib
from supervisor.py3compat import *
if PY3:
import xmlrpc.client as xmlrpclib
else:
#noinspection PyUnresolvedReferences
import xmlrpclib
from supervisor.xmlrpc import SupervisorTransport
from supervisor.events import ProcessCommunicationEvent
from supervisor.dispatchers import PEventListenerDispatcher
Expand Down
3 changes: 2 additions & 1 deletion supervisor/confecho.py
@@ -1,6 +1,7 @@
import pkg_resources
import sys
from supervisor.py3compat import *

def main(out=sys.stdout):
config = pkg_resources.resource_string(__name__, 'skel/sample.conf')
out.write(config)
out.write(as_string(config))
43 changes: 23 additions & 20 deletions supervisor/datatypes.py
Expand Up @@ -3,9 +3,14 @@
import pwd
import signal
import sys
import socket
import supervisor.medusa.text_socket as socket
import shlex
import urlparse
from supervisor.py3compat import *
if PY3:
import urllib.parse as urlparse
else:
#noinspection PyUnresolvedReferences
import urlparse
from supervisor.loggers import getLevelNumByDescription

# I dont know why we bother, this doesn't run on Windows, but just
Expand Down Expand Up @@ -63,7 +68,7 @@ def list_of_ints(arg):
return []
else:
try:
return map(int, arg.split(","))
return list(map(int, arg.split(",")))
except:
raise ValueError("not a valid list of ints: " + repr(arg))

Expand All @@ -81,7 +86,7 @@ def dict_of_key_value_pairs(arg):
""" parse KEY=val,KEY2=val2 into {'KEY':'val', 'KEY2':'val2'}
Quotes can be used to allow commas in the value
"""
lexer = shlex.shlex(arg)
lexer = shlex.shlex(str(arg))
lexer.wordchars += '/.+-():'

tokens = list(lexer)
Expand Down Expand Up @@ -139,7 +144,6 @@ def __call__(self, value):
def inet_address(s):
# returns (host, port) tuple
host = ''
port = None
if ":" in s:
host, s = s.split(":", 1)
if not s:
Expand Down Expand Up @@ -209,7 +213,7 @@ def __init__(self, host, port):
self.url = 'tcp://%s:%d' % (self.host, self.port)

def addr(self):
return (self.host, self.port)
return self.host, self.port

def create_and_bind(self):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
Expand All @@ -227,7 +231,7 @@ class UnixStreamSocketConfig(SocketConfig):

def __init__(self, path, **kwargs):
self.path = path
self.url = 'unix://%s' % (path)
self.url = 'unix://%s' % path
self.mode = kwargs.get('mode', None)
self.owner = kwargs.get('owner', None)

Expand Down Expand Up @@ -258,17 +262,19 @@ def _chmod(self):
if self.mode is not None:
try:
os.chmod(self.path, self.mode)
except Exception, e:
except Exception:
e = sys.exc_info()[1]
raise ValueError("Could not change permissions of socket "
+ "file: %s" % (e))
+ "file: %s" % e)

def _chown(self):
if self.owner is not None:
try:
os.chown(self.path, self.owner[0], self.owner[1])
except Exception, e:
except Exception:
e = sys.exc_info()[1]
raise ValueError("Could not change ownership of socket file: "
+ "%s" % (e))
+ "%s" % e)

def colon_separated_user_group(arg):
""" Find a user ID and group ID from a string like 'user:group'. Returns
Expand Down Expand Up @@ -385,7 +391,7 @@ def __call__(self, v):

byte_size = SuffixMultiplier({'kb': 1024,
'mb': 1024*1024,
'gb': 1024*1024*1024L,})
'gb': 1024*1024*long(1024),})

def url(value):
# earlier Python 2.6 urlparse (2.6.4 and under) can't parse unix:// URLs,
Expand All @@ -397,16 +403,13 @@ def url(value):
raise ValueError("value %s is not a URL" % value)

def signal_number(value):
result = None
try:
result = int(value)
except (ValueError, TypeError):
result = getattr(signal, 'SIG'+value, None)
try:
result = int(result)
return result
return int(value)
except (ValueError, TypeError):
raise ValueError('value %s is not a signal name/number' % value)
try:
return int(getattr(signal, 'SIG'+value, None))
except (ValueError, TypeError):
raise ValueError('value %s is not a signal name/number' % value)

class RestartWhenExitUnexpected:
pass
Expand Down
30 changes: 15 additions & 15 deletions supervisor/dispatchers.py
@@ -1,4 +1,5 @@
import warnings
import sys
import errno
from supervisor.medusa.asyncore_25 import compact_traceback

Expand All @@ -21,6 +22,12 @@ class PDispatcher:

closed = False # True if close() has been called

def __init__(self, process, channel, fd):
self.process = process # process which "owns" this dispatcher
self.channel = channel # 'stderr' or 'stdout'
self.fd = fd
self.closed = False # True if close() has been called

def __repr__(self):
return '<%s at %s for %s (%s)>' % (self.__class__.__name__,
id(self),
Expand Down Expand Up @@ -72,8 +79,6 @@ class POutputDispatcher(PDispatcher):
config.
"""

process = None # process which "owns" this dispatcher
channel = None # 'stderr' or 'stdout'
capturemode = False # are we capturing process event data
mainlog = None # the process' "normal" logger
capturelog = None # the logger while we're in capturemode
Expand Down Expand Up @@ -264,8 +269,6 @@ def handle_read_event(self):
class PEventListenerDispatcher(PDispatcher):
""" An output dispatcher that monitors and changes a process'
listener_state """
process = None # process which "owns" this dispatcher
channel = None # 'stderr' or 'stdout'
childlog = None # the logger
state_buffer = '' # data waiting to be reviewed for state changes

Expand All @@ -275,15 +278,13 @@ class PEventListenerDispatcher(PDispatcher):
RESULT_TOKEN_START_LEN = len(RESULT_TOKEN_START)

def __init__(self, process, channel, fd):
self.process = process
PDispatcher.__init__(self, process, channel, fd)
# the initial state of our listener is ACKNOWLEDGED; this is a
# "busy" state that implies we're awaiting a READY_FOR_EVENTS_TOKEN
self.process.listener_state = EventListenerStates.ACKNOWLEDGED
self.process.event = None
self.result = ''
self.resultlen = None
self.channel = channel
self.fd = fd

logfile = getattr(process.config, '%s_logfile' % channel)

Expand Down Expand Up @@ -411,11 +412,13 @@ def handle_listener_state_change(self):
return

else:
#noinspection PyTypeChecker
needed = self.resultlen - len(self.result)

if needed:
self.result += self.state_buffer[:needed]
self.state_buffer = self.state_buffer[needed:]
#noinspection PyTypeChecker
needed = self.resultlen - len(self.result)

if not needed:
Expand Down Expand Up @@ -451,14 +454,9 @@ def handle_result(self, result):

class PInputDispatcher(PDispatcher):
""" Input (stdin) dispatcher """
process = None # process which "owns" this dispatcher
channel = None # 'stdin'
input_buffer = '' # data waiting to be sent to the child process

def __init__(self, process, channel, fd):
self.process = process
self.channel = channel
self.fd = fd
PDispatcher.__init__(self, process, channel, fd)
self.input_buffer = ''

def writable(self):
Expand All @@ -479,7 +477,8 @@ def handle_write_event(self):
if self.input_buffer:
try:
self.flush()
except OSError, why:
except OSError:
why = sys.exc_info()[1]
if why.args[0] == errno.EPIPE:
self.input_buffer = ''
self.close()
Expand Down Expand Up @@ -509,13 +508,14 @@ def stripEscapes(s):
result = result + s[i:n]
i = n
show = 0
i = i + 1
i += 1
return result

class RejectEvent(Exception):
""" The exception type expected by a dispatcher when a handler wants
to reject an event """

#noinspection PyUnusedLocal
def default_handler(event, response):
if response != 'OK':
raise RejectEvent(response)
7 changes: 3 additions & 4 deletions supervisor/events.py
Expand Up @@ -19,6 +19,7 @@ class Event:

class ProcessLogEvent(Event):
""" Abstract """
channel = None
def __init__(self, process, pid, data):
self.process = process
self.pid = pid
Expand Down Expand Up @@ -108,10 +109,8 @@ def __str__(self):
groupname = ''
if self.process.group is not None:
groupname = self.process.group.config.name
L = []
L.append(('processname', self.process.config.name))
L.append(('groupname', groupname))
L.append(('from_state', getProcessStateDescription(self.from_state)))
L = [('processname', self.process.config.name), ('groupname', groupname),
('from_state', getProcessStateDescription(self.from_state))]
L.extend(self.extra_values)
s = ' '.join( [ '%s:%s' % (name, val) for (name, val) in L ] )
return s
Expand Down

0 comments on commit 98c5676

Please sign in to comment.