Skip to content

Commit

Permalink
improve run-deprecations script
Browse files Browse the repository at this point in the history
Rewrote in Twisted, which lets us read/scan/print all log lines in
realtime. The output is now correctly interleaved (as well as
maintaining the stdout-vs-stderr of each message). The renamed
--warnings= logfile records all relevant lines from *both* stdout and
stderr (i.e. any that includes "DeprecationWarning"), which handles a
change (perhaps in recent Twisteds?) that emits these warnings on stdout
instead of stderr.
  • Loading branch information
warner committed Apr 6, 2016
1 parent d5e1b21 commit 9d20de3
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 52 deletions.
120 changes: 70 additions & 50 deletions misc/build_helpers/run-deprecations.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import sys, os, subprocess
import sys, os, io
from twisted.internet import reactor, protocol, task, defer
from twisted.python.procutils import which
from twisted.python import usage

Expand All @@ -8,62 +9,81 @@

class Options(usage.Options):
optParameters = [
["stderr", None, None, "file to write stderr into at end of test run"],
["warnings", None, None, "file to write warnings into at end of test run"],
]

def parseArgs(self, command, *args):
self["command"] = command
self["args"] = list(args)

description = """Run as:
PYTHONWARNINGS=default::DeprecationWarning python run-deprecations.py [--stderr=STDERRFILE] COMMAND ARGS..
PYTHONWARNINGS=default::DeprecationWarning python run-deprecations.py [--warnings=STDERRFILE] COMMAND ARGS..
"""

config = Options()
config.parseOptions()


command = config["command"]
if "/" in command:
# don't search
exe = command
else:
executables = which(command)
if not executables:
raise ValueError("unable to find '%s' in PATH (%s)" %
(command, os.environ.get("PATH")))
exe = executables[0]

pw = os.environ.get("PYTHONWARNINGS")
DDW = "default::DeprecationWarning"
if pw != DDW:
print "note: $PYTHONWARNINGS is '%s', not the expected %s" % (pw, DDW)

print "note: stderr is being captured, and will be emitted at the end"
sys.stdout.flush()

# stdout goes directly to the parent, so test progress can be watched in real
# time. But subprocess.Popen() doesn't give us any good way of seeing it
p = subprocess.Popen([exe] + config["args"], stderr=subprocess.PIPE)
stderr = p.communicate()[1]
rc = p.returncode
count = 0

if config["stderr"]:
with open(config["stderr"], "wb") as f:
print >>f, stderr,

if stderr:
print >>sys.stderr, "--"
print >>sys.stderr, "Captured stderr follows:"
for line in stderr.splitlines():
class RunPP(protocol.ProcessProtocol):
def outReceived(self, data):
self.stdout.write(data)
sys.stdout.write(data)
def errReceived(self, data):
self.stderr.write(data)
sys.stderr.write(data)
def processEnded(self, reason):
signal = reason.value.signal
rc = reason.value.exitCode
self.d.callback((signal, rc))

@defer.inlineCallbacks
def run_command(main):
config = Options()
config.parseOptions()

command = config["command"]
if "/" in command:
# don't search
exe = command
else:
executables = which(command)
if not executables:
raise ValueError("unable to find '%s' in PATH (%s)" %
(command, os.environ.get("PATH")))
exe = executables[0]

pw = os.environ.get("PYTHONWARNINGS")
DDW = "default::DeprecationWarning"
if pw != DDW:
print "note: $PYTHONWARNINGS is '%s', not the expected %s" % (pw, DDW)
sys.stdout.flush()

pp = RunPP()
pp.d = defer.Deferred()
pp.stdout = io.BytesIO()
pp.stderr = io.BytesIO()
reactor.spawnProcess(pp, exe, [exe] + config["args"], env=None)
(signal, rc) = yield pp.d

warnings = []

pp.stdout.seek(0)
for line in pp.stdout.readlines():
if "DeprecationWarning" in line:
count += 1
print >>sys.stderr, line
print >>sys.stderr, "--"

if count:
print "ERROR: %d deprecation warnings found" % count
sys.exit(1)
print "no deprecation warnings"
sys.exit(rc)
warnings.append(line) # includes newline

pp.stderr.seek(0)
for line in pp.stderr.readlines():
if "DeprecationWarning" in line:
warnings.append(line)

if warnings:
if config["warnings"]:
with open(config["warnings"], "wb") as f:
print >>f, "".join(warnings)
print "ERROR: %d deprecation warnings found" % len(warnings)
sys.exit(1)

print "no deprecation warnings"
if signal:
sys.exit(signal)
sys.exit(rc)


task.react(run_command)
4 changes: 2 additions & 2 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ passenv = USERPROFILE HOMEDRIVE HOMEPATH
setenv =
PYTHONWARNINGS=default::DeprecationWarning
commands =
python misc/build_helpers/run-deprecations.py --stderr=_trial_temp/stderr.log trial --rterrors {posargs:allmydata}
python misc/build_helpers/run-deprecations.py --warnings=_trial_temp/deprecation-warnings.log trial --rterrors {posargs:allmydata}

[testenv:upcoming-deprecations]
basepython=python2.7
Expand All @@ -29,7 +29,7 @@ deps =
git+https://github.com/twisted/twisted
git+https://github.com/warner/foolscap
commands =
python misc/build_helpers/run-deprecations.py --stderr=_trial_temp/stderr.log trial --rterrors {posargs:allmydata}
python misc/build_helpers/run-deprecations.py --warnings=_trial_temp/deprecation-warnings.log trial --rterrors {posargs:allmydata}

[testenv:checkmemory]
commands =
Expand Down

0 comments on commit 9d20de3

Please sign in to comment.