<commit_before>#!/usr/bin/env python2.7

import re
import os
import glob
import pickle
import platform
import signal
import sys
import difflib
from StringIO import StringIO
from subprocess import Popen, PIPE
from multiprocessing import Pool, cpu_count
import time

#
# testLogFile
#

testLogFile = open("testlog.txt", "w")

#
# testRoot
#

testBuildFlags = []
testRoot = os.path.dirname(os.path.abspath(__file__))
runTestRoot = testRoot

#
# getClayPlatform, fileForPlatform
#

def getClayPlatform():
    if sys.platform in ["win32", "cygwin"]:
        return "windows"
    if sys.platform == "darwin":
        return "macosx"
    if sys.platform.startswith("freebsd"):
        return "freebsd"
    if sys.platform.startswith("linux"):
        return "linux"

def getClayPlatformFamily():
    if sys.platform in ["win32", "cygwin"]:
        return "windows"
    else:
        return "unix"

def getClayArchitecture():
    if platform.machine() in ["i386", "x86_64", "x86-64", "amd64", "AMD64", "x64"]:
        return "x86"
    else:
        return "unknown"

# XXX this needs to determine the bitness of clay executables, not of python
def getClayBits():
    if platform.architecture()[0] == "64bit":
        return "64"
    if platform.architecture()[0] == "32bit":
        return "32"

clayPlatform = getClayPlatform()
clayPlatformFamily = getClayPlatformFamily()
clayArchitecture = getClayArchitecture()
clayBits = getClayBits()

def fileForPlatform(folder, name, ext):
    platformNames = [
        "%s.%s.%s.%s.%s" % (name, clayPlatform, clayArchitecture, clayBits, ext),
        "%s.%s.%s.%s.%s" % (name, clayPlatformFamily, clayArchitecture, clayBits, ext),
        "%s.%s.%s.%s" % (name, clayPlatform, clayArchitecture, ext),
        "%s.%s.%s.%s" % (name, clayPlatform, clayBits, ext),
        "%s.%s.%s.%s" % (name, clayPlatformFamily, clayArchitecture, ext),
        "%s.%s.%s.%s" % (name, clayPlatformFamily, clayBits, ext),
        "%s.%s.%s.%s" % (name, clayArchitecture, clayBits, ext),
        "%s.%s.%s" % (name, clayPlatform, ext),
        "%s.%s.%s" % (name, clayPlatformFamily, ext),
        "%s.%s.%s" % (name, clayArchitecture, ext),
        "%s.%s.%s" % (name, clayBits, ext),
    ]
    for platformName in platformNames:
        fullName = os.path.join(folder, platformName)
        if os.path.isfile(fullName):
            return fullName

    return os.path.join(folder, "%s.%s" % (name, ext))

#
# getCompilerPath
#

def getCompilerPath() :
    buildPath = ["..", "build", "compiler", "src"]
    if sys.platform == "win32" :
        compiler = os.path.join(testRoot, *(buildPath + ["clay.exe"]))
        compiler2 = os.path.join(testRoot, "..", "clay.exe") # for binary distributions
    else :
        compiler = os.path.join(testRoot, *(buildPath + ["clay"]))
        compiler2 = os.path.join(testRoot, "..", "clay") # for binary distributions

    if not os.path.exists(compiler) :
        compiler = compiler2
        if not os.path.exists(compiler) :
            print "could not find the clay compiler"
            sys.exit(-1)
    return compiler

compiler = getCompilerPath()

#
# TestCase
#

class TestCase(object):
    allCases = []
    def __init__(self, folder, testfile, base = None):
        entries = os.listdir(folder)
        self.testfile = os.path.basename(testfile)
        self.path = folder
        if os.path.isfile(testfile):
            self.loadTest(testfile)

        runscript = fileForPlatform(folder, "run", "py")
        if os.path.isfile(runscript):
            self.runscript = runscript
        else:
            self.runscript = None

        buildflags = fileForPlatform(folder, "buildflags", "txt")
        if os.path.isfile(buildflags):
            self.buildflags = open(buildflags).read().split()
        else:
            self.buildflags = []

        for entry in entries:
            fullpath = os.path.join(folder, entry)
            if not os.path.isdir(fullpath):
                continue
            findTestCase(fullpath, self)

    def loadTest(self, testfile):
        TestCase.allCases.append(self)
        self.testfile = testfile

    def cmdline(self, clay) :
        return [clay, "-I" + self.path, "-o", "test.exe"] + testBuildFlags + self.buildflags + [self.testfile]

    def pre_build(self) :
        pass

    def post_build(self) :
        pass

    def post_run(self) :
        [os.unlink(f) for f in glob.glob("temp*")]
        [os.unlink(f) for f in glob.glob("*.data")]

    def match(self, resultout, resulterr, returncode) :
        compilererrfile = fileForPlatform(".", "compilererr", "txt")
        if os.path.isfile(compilererrfile):
            errpattern = open(compilererrfile).read()
            errpattern = errpattern.replace('\r', '').strip()

            if returncode != "compiler error":
                print >>self.testLogBuffer, "compiler did not fail"
                print >>self.testLogBuffer, "expected error pattern"
                print >>self.testLogBuffer, "----------------------"
                print >>self.testLogBuffer, errpattern
                return "compiler did not fail"
            if re.search(errpattern, resulterr):
                return "ok"
            else:
                print >>self.testLogBuffer, "unexpected compiler error"
                print >>self.testLogBuffer, "expected error pattern"
                print >>self.testLogBuffer, "----------------------"
                print >>self.testLogBuffer, errpattern
                print >>self.testLogBuffer, "---------------------"
                print >>self.testLogBuffer, "actual compiler error"
                print >>self.testLogBuffer, "---------------------"
                print >>self.testLogBuffer, resulterr
                return "unexpected compiler error"

        else:
            if returncode == "compiler error":
                print >>self.testLogBuffer, "compiler error"
                print >>self.testLogBuffer, "--------------"
                print >>self.testLogBuffer, resulterr
                return "compiler error"
            outfile = fileForPlatform(".", "out", "txt")
            errfile = fileForPlatform(".", "err", "txt")
            if not os.path.isfile(outfile) :
                print >>self.testLogBuffer, "out.txt missing"
                return "out.txt missing"
            refout = open(outfile).read()
            referr = ""
            if os.path.isfile(errfile):
                referr = open(errfile).read()
            resultout = resultout.replace('\r', '')
            refout    = refout.replace('\r', '')
            resulterr = resulterr.replace('\r', '')
            referr    = referr.replace('\r', '')
            if resultout == refout and resulterr == referr:
                return "ok"
            elif resultout != refout and resulterr != referr:
                print >>self.testLogBuffer, "out.txt and err.txt mismatch"
                print >>self.testLogBuffer, "diff from out.txt"
                print >>self.testLogBuffer, "-----------------"
                for line in difflib.unified_diff(
                    refout.splitlines(True), resultout.splitlines(True),
                    fromfile="out.txt", tofile="stdout"
                ):
                    print >>self.testLogBuffer, line,
                print >>self.testLogBuffer, "----------------"
                print >>self.testLogBuffer, "diff from err.txt"
                print >>self.testLogBuffer, "-----------------"
                for line in difflib.unified_diff(
                    referr.splitlines(True), resulterr.splitlines(True),
                    fromfile="err.txt", tofile="stderr"
                ):
                    print >>self.testLogBuffer, line,
                return "out.txt and err.txt mismatch"
            elif resultout != refout:
                print >>self.testLogBuffer, "out.txt mismatch"
                print >>self.testLogBuffer, "diff from out.txt"
                print >>self.testLogBuffer, "-----------------"
                for line in difflib.unified_diff(
                    refout.splitlines(True), resultout.splitlines(True),
                    fromfile="out.txt", tofile="stdout"
                ):
                    print >>self.testLogBuffer, line,
                return "out.txt mismatch"
            elif resulterr != referr:
                print >>self.testLogBuffer, "err.txt mismatch"
                print >>self.testLogBuffer, "diff from err.txt"
                print >>self.testLogBuffer, "-----------------"
                for line in difflib.unified_diff(
                    referr.splitlines(True), resulterr.splitlines(True),
                    fromfile="err.txt", tofile="stderr"
                ):
                    print >>self.testLogBuffer, line,
                return "err.txt mismatch"

    def run(self):
        self.testLogBuffer = StringIO()
        print >>self.testLogBuffer
        print >>self.testLogBuffer, "====================="
        print >>self.testLogBuffer, self.name()
        print >>self.testLogBuffer, "====================="
        os.chdir(self.path)
        self.pre_build()
        self.post_build()
        resultout, resulterr, returncode = self.runtest()
        self.post_run()
        r = self.match(resultout, resulterr, returncode)
        log = self.testLogBuffer.getvalue()
        self.testLogBuffer.close()

        return (r, log)

    def name(self):
        return os.path.relpath(self.path, testRoot)

    def runtest(self):
        outfilename = "test.exe"
        outfilename = os.path.join(".", outfilename)
        process = Popen(self.cmdline(compiler), stdout=PIPE, stderr=PIPE)
        compilerout, compilererr = process.communicate()
        if process.returncode != 0 :
            return "", "%s\n%s" % (compilerout, compilererr), "compiler error"
        if self.runscript is None:
            commandline = [outfilename]
        else:
            commandline = [sys.executable, self.runscript, outfilename] + testBuildFlags

        process = Popen(commandline, stdout=PIPE, stderr=PIPE)
        resultout, resulterr = process.communicate()
        self.removefile(outfilename)
        return resultout, resulterr, process.returncode

    def removefile(self, filename) :
        # on windows, sometimes, deleting a file
        # immediately after executing it
        # results in a 'access denied' error.
        # so we wait and try again a few times.
        attempts = 1
        while (attempts <= 3) and os.path.exists(filename) :
            try :
                os.unlink(filename)
            except OSError :
                time.sleep(1)
            attempts += 1

class TestModuleCase(TestCase):
    def match(self, resultout, resulterr, returncode) :
        if returncode == 0:
            return "ok"
        elif returncode == "compiler error":
            print >>self.testLogBuffer, "compiler error"
            print >>self.testLogBuffer, "--------------"
            print >>self.testLogBuffer, resulterr
            return "compiler error"
        else:
            print >>self.testLogBuffer, "fail"
            print >>self.testLogBuffer, "----"
            print >>self.testLogBuffer, resultout
            return "fail"

class TestDisabledCase(TestCase):
    def runtest(self):
        return "disabled", "", None
    def match(self, resultout, resulterr, returncode) :
        return "disabled"

#
# runtests
#

def findTestCase(folder, base = None):
    testPath = fileForPlatform(folder, "test", "clay")
    mainPath = fileForPlatform(folder, "main", "clay")
    testDisabledPath = fileForPlatform(folder, "test-disabled", "clay")
    mainDisabledPath = fileForPlatform(folder, "main-disabled", "clay")
    if os.path.isfile(testPath):
        TestModuleCase(folder, testPath, base)
    elif os.path.isfile(testDisabledPath):
        TestDisabledCase(folder, testDisabledPath, base)
    elif os.path.isfile(mainDisabledPath):
        TestDisabledCase(folder, mainDisabledPath, base)
    else:
        TestCase(folder, mainPath, base)

def findTestCases():
    findTestCase(runTestRoot)
    return TestCase.allCases

def initWorker():
    signal.signal(signal.SIGINT, signal.SIG_IGN)

def runTest(t):
    return t.run()

def runTests() :
    testcases = findTestCases()
    pool = Pool(processes = cpu_count(), initializer=initWorker)
    results = pool.imap(runTest, testcases)
    succeeded = []
    failed = []
    disabled = []
    try:
        for test in testcases:
            res, log = results.next()
            if res != "ok" and res != "disabled":
                print >>testLogFile, log,
            testLogFile.flush()
            print "TEST %s: %s" % (test.name(), res)
            if res == "disabled":
                disabled.append(test.name())
            elif res != "ok":
                failed.append(test.name())
            else:
                succeeded.append(test.name())
    except KeyboardInterrupt:
        print "\nInterrupted!"
        pool.terminate()

    print "\nPASSED %d TESTS" % len(succeeded)
    if len(disabled) != 0:
        print "(%d tests disabled)" % len(disabled)
    if len(failed) != 0:
        print "\nFAILED %d TESTS" % len(failed)
        print "Failed tests:\n ",
        print "\n  ".join(failed)
    testLogFile.flush()
    print "Test log written to testlog.txt"

def usage(argv0):
    print "Usage: %s [buildflags... --] [root] [root...]" % argv0
    print "  Runs the Clay test suite. If any root paths are given, only tests"
    print "  in those subdirectories (paths relative to the test/ directory) will"
    print "  be run. Build flags can be passed to the compiler followed by '--'."

def main() :
    global testRoot
    global runTestRoot
    if len(sys.argv) > 1 :
        if sys.argv[1] == "--help" or sys.argv[1] == "/?":
            usage(sys.argv[0])
            return

        try:
            buildFlagSeparator = sys.argv.index("--")
            testBuildFlags = sys.argv[1:buildFlagSeparator]
            runTestRoot = os.path.join(testRoot, *sys.argv[buildFlagSeparator+1:])
        except ValueError:
            testBuildFlags = []
            runTestRoot = os.path.join(testRoot, *sys.argv[1:])
    else:
        testBuildFlags = []
        runTestRoot = testRoot
    startTime = time.time()
    runTests()
    endTime = time.time()
    print ""
    print "time taken = %f seconds" % (endTime - startTime)

if __name__ == "__main__":
    main()
<commit_msg>oops, runtests wasn't honoring build flags<commit_after>#!/usr/bin/env python2.7

import re
import os
import glob
import pickle
import platform
import signal
import sys
import difflib
from StringIO import StringIO
from subprocess import Popen, PIPE
from multiprocessing import Pool, cpu_count
import time

#
# testLogFile
#

testLogFile = open("testlog.txt", "w")

#
# testRoot
#

testBuildFlags = []
testRoot = os.path.dirname(os.path.abspath(__file__))
runTestRoot = testRoot

#
# getClayPlatform, fileForPlatform
#

def getClayPlatform():
    if sys.platform in ["win32", "cygwin"]:
        return "windows"
    if sys.platform == "darwin":
        return "macosx"
    if sys.platform.startswith("freebsd"):
        return "freebsd"
    if sys.platform.startswith("linux"):
        return "linux"

def getClayPlatformFamily():
    if sys.platform in ["win32", "cygwin"]:
        return "windows"
    else:
        return "unix"

def getClayArchitecture():
    if platform.machine() in ["i386", "x86_64", "x86-64", "amd64", "AMD64", "x64"]:
        return "x86"
    else:
        return "unknown"

# XXX this needs to determine the bitness of clay executables, not of python
def getClayBits():
    if platform.architecture()[0] == "64bit":
        return "64"
    if platform.architecture()[0] == "32bit":
        return "32"

clayPlatform = getClayPlatform()
clayPlatformFamily = getClayPlatformFamily()
clayArchitecture = getClayArchitecture()
clayBits = getClayBits()

def fileForPlatform(folder, name, ext):
    platformNames = [
        "%s.%s.%s.%s.%s" % (name, clayPlatform, clayArchitecture, clayBits, ext),
        "%s.%s.%s.%s.%s" % (name, clayPlatformFamily, clayArchitecture, clayBits, ext),
        "%s.%s.%s.%s" % (name, clayPlatform, clayArchitecture, ext),
        "%s.%s.%s.%s" % (name, clayPlatform, clayBits, ext),
        "%s.%s.%s.%s" % (name, clayPlatformFamily, clayArchitecture, ext),
        "%s.%s.%s.%s" % (name, clayPlatformFamily, clayBits, ext),
        "%s.%s.%s.%s" % (name, clayArchitecture, clayBits, ext),
        "%s.%s.%s" % (name, clayPlatform, ext),
        "%s.%s.%s" % (name, clayPlatformFamily, ext),
        "%s.%s.%s" % (name, clayArchitecture, ext),
        "%s.%s.%s" % (name, clayBits, ext),
    ]
    for platformName in platformNames:
        fullName = os.path.join(folder, platformName)
        if os.path.isfile(fullName):
            return fullName

    return os.path.join(folder, "%s.%s" % (name, ext))

#
# getCompilerPath
#

def getCompilerPath() :
    buildPath = ["..", "build", "compiler", "src"]
    if sys.platform == "win32" :
        compiler = os.path.join(testRoot, *(buildPath + ["clay.exe"]))
        compiler2 = os.path.join(testRoot, "..", "clay.exe") # for binary distributions
    else :
        compiler = os.path.join(testRoot, *(buildPath + ["clay"]))
        compiler2 = os.path.join(testRoot, "..", "clay") # for binary distributions

    if not os.path.exists(compiler) :
        compiler = compiler2
        if not os.path.exists(compiler) :
            print "could not find the clay compiler"
            sys.exit(-1)
    return compiler

compiler = getCompilerPath()

#
# TestCase
#

class TestCase(object):
    allCases = []
    def __init__(self, folder, testfile, base = None):
        entries = os.listdir(folder)
        self.testfile = os.path.basename(testfile)
        self.path = folder
        if os.path.isfile(testfile):
            self.loadTest(testfile)

        runscript = fileForPlatform(folder, "run", "py")
        if os.path.isfile(runscript):
            self.runscript = runscript
        else:
            self.runscript = None

        buildflags = fileForPlatform(folder, "buildflags", "txt")
        if os.path.isfile(buildflags):
            self.buildflags = open(buildflags).read().split()
        else:
            self.buildflags = []

        for entry in entries:
            fullpath = os.path.join(folder, entry)
            if not os.path.isdir(fullpath):
                continue
            findTestCase(fullpath, self)

    def loadTest(self, testfile):
        TestCase.allCases.append(self)
        self.testfile = testfile

    def cmdline(self, clay) :
        r = [clay, "-I" + self.path, "-o", "test.exe"] + testBuildFlags + self.buildflags + [self.testfile]
        return r

    def pre_build(self) :
        pass

    def post_build(self) :
        pass

    def post_run(self) :
        [os.unlink(f) for f in glob.glob("temp*")]
        [os.unlink(f) for f in glob.glob("*.data")]

    def match(self, resultout, resulterr, returncode) :
        compilererrfile = fileForPlatform(".", "compilererr", "txt")
        if os.path.isfile(compilererrfile):
            errpattern = open(compilererrfile).read()
            errpattern = errpattern.replace('\r', '').strip()

            if returncode != "compiler error":
                print >>self.testLogBuffer, "compiler did not fail"
                print >>self.testLogBuffer, "expected error pattern"
                print >>self.testLogBuffer, "----------------------"
                print >>self.testLogBuffer, errpattern
                return "compiler did not fail"
            if re.search(errpattern, resulterr):
                return "ok"
            else:
                print >>self.testLogBuffer, "unexpected compiler error"
                print >>self.testLogBuffer, "expected error pattern"
                print >>self.testLogBuffer, "----------------------"
                print >>self.testLogBuffer, errpattern
                print >>self.testLogBuffer, "---------------------"
                print >>self.testLogBuffer, "actual compiler error"
                print >>self.testLogBuffer, "---------------------"
                print >>self.testLogBuffer, resulterr
                return "unexpected compiler error"

        else:
            if returncode == "compiler error":
                print >>self.testLogBuffer, "compiler error"
                print >>self.testLogBuffer, "--------------"
                print >>self.testLogBuffer, resulterr
                return "compiler error"
            outfile = fileForPlatform(".", "out", "txt")
            errfile = fileForPlatform(".", "err", "txt")
            if not os.path.isfile(outfile) :
                print >>self.testLogBuffer, "out.txt missing"
                return "out.txt missing"
            refout = open(outfile).read()
            referr = ""
            if os.path.isfile(errfile):
                referr = open(errfile).read()
            resultout = resultout.replace('\r', '')
            refout    = refout.replace('\r', '')
            resulterr = resulterr.replace('\r', '')
            referr    = referr.replace('\r', '')
            if resultout == refout and resulterr == referr:
                return "ok"
            elif resultout != refout and resulterr != referr:
                print >>self.testLogBuffer, "out.txt and err.txt mismatch"
                print >>self.testLogBuffer, "diff from out.txt"
                print >>self.testLogBuffer, "-----------------"
                for line in difflib.unified_diff(
                    refout.splitlines(True), resultout.splitlines(True),
                    fromfile="out.txt", tofile="stdout"
                ):
                    print >>self.testLogBuffer, line,
                print >>self.testLogBuffer, "----------------"
                print >>self.testLogBuffer, "diff from err.txt"
                print >>self.testLogBuffer, "-----------------"
                for line in difflib.unified_diff(
                    referr.splitlines(True), resulterr.splitlines(True),
                    fromfile="err.txt", tofile="stderr"
                ):
                    print >>self.testLogBuffer, line,
                return "out.txt and err.txt mismatch"
            elif resultout != refout:
                print >>self.testLogBuffer, "out.txt mismatch"
                print >>self.testLogBuffer, "diff from out.txt"
                print >>self.testLogBuffer, "-----------------"
                for line in difflib.unified_diff(
                    refout.splitlines(True), resultout.splitlines(True),
                    fromfile="out.txt", tofile="stdout"
                ):
                    print >>self.testLogBuffer, line,
                return "out.txt mismatch"
            elif resulterr != referr:
                print >>self.testLogBuffer, "err.txt mismatch"
                print >>self.testLogBuffer, "diff from err.txt"
                print >>self.testLogBuffer, "-----------------"
                for line in difflib.unified_diff(
                    referr.splitlines(True), resulterr.splitlines(True),
                    fromfile="err.txt", tofile="stderr"
                ):
                    print >>self.testLogBuffer, line,
                return "err.txt mismatch"

    def run(self):
        self.testLogBuffer = StringIO()
        print >>self.testLogBuffer
        print >>self.testLogBuffer, "====================="
        print >>self.testLogBuffer, self.name()
        print >>self.testLogBuffer, "====================="
        os.chdir(self.path)
        self.pre_build()
        self.post_build()
        resultout, resulterr, returncode = self.runtest()
        self.post_run()
        r = self.match(resultout, resulterr, returncode)
        log = self.testLogBuffer.getvalue()
        self.testLogBuffer.close()

        return (r, log)

    def name(self):
        return os.path.relpath(self.path, testRoot)

    def runtest(self):
        outfilename = "test.exe"
        outfilename = os.path.join(".", outfilename)
        process = Popen(self.cmdline(compiler), stdout=PIPE, stderr=PIPE)
        compilerout, compilererr = process.communicate()
        if process.returncode != 0 :
            return "", "%s\n%s" % (compilerout, compilererr), "compiler error"
        if self.runscript is None:
            commandline = [outfilename]
        else:
            commandline = [sys.executable, self.runscript, outfilename] + testBuildFlags

        process = Popen(commandline, stdout=PIPE, stderr=PIPE)
        resultout, resulterr = process.communicate()
        self.removefile(outfilename)
        return resultout, resulterr, process.returncode

    def removefile(self, filename) :
        # on windows, sometimes, deleting a file
        # immediately after executing it
        # results in a 'access denied' error.
        # so we wait and try again a few times.
        attempts = 1
        while (attempts <= 3) and os.path.exists(filename) :
            try :
                os.unlink(filename)
            except OSError :
                time.sleep(1)
            attempts += 1

class TestModuleCase(TestCase):
    def match(self, resultout, resulterr, returncode) :
        if returncode == 0:
            return "ok"
        elif returncode == "compiler error":
            print >>self.testLogBuffer, "compiler error"
            print >>self.testLogBuffer, "--------------"
            print >>self.testLogBuffer, resulterr
            return "compiler error"
        else:
            print >>self.testLogBuffer, "fail"
            print >>self.testLogBuffer, "----"
            print >>self.testLogBuffer, resultout
            return "fail"

class TestDisabledCase(TestCase):
    def runtest(self):
        return "disabled", "", None
    def match(self, resultout, resulterr, returncode) :
        return "disabled"

#
# runtests
#

def findTestCase(folder, base = None):
    testPath = fileForPlatform(folder, "test", "clay")
    mainPath = fileForPlatform(folder, "main", "clay")
    testDisabledPath = fileForPlatform(folder, "test-disabled", "clay")
    mainDisabledPath = fileForPlatform(folder, "main-disabled", "clay")
    if os.path.isfile(testPath):
        TestModuleCase(folder, testPath, base)
    elif os.path.isfile(testDisabledPath):
        TestDisabledCase(folder, testDisabledPath, base)
    elif os.path.isfile(mainDisabledPath):
        TestDisabledCase(folder, mainDisabledPath, base)
    else:
        TestCase(folder, mainPath, base)

def findTestCases():
    findTestCase(runTestRoot)
    return TestCase.allCases

def initWorker():
    signal.signal(signal.SIGINT, signal.SIG_IGN)

def runTest(t):
    return t.run()

def runTests() :
    testcases = findTestCases()
    pool = Pool(processes = cpu_count(), initializer=initWorker)
    results = pool.imap(runTest, testcases)
    succeeded = []
    failed = []
    disabled = []
    try:
        for test in testcases:
            res, log = results.next()
            if res != "ok" and res != "disabled":
                print >>testLogFile, log,
            testLogFile.flush()
            print "TEST %s: %s" % (test.name(), res)
            if res == "disabled":
                disabled.append(test.name())
            elif res != "ok":
                failed.append(test.name())
            else:
                succeeded.append(test.name())
    except KeyboardInterrupt:
        print "\nInterrupted!"
        pool.terminate()

    print "\nPASSED %d TESTS" % len(succeeded)
    if len(disabled) != 0:
        print "(%d tests disabled)" % len(disabled)
    if len(failed) != 0:
        print "\nFAILED %d TESTS" % len(failed)
        print "Failed tests:\n ",
        print "\n  ".join(failed)
    testLogFile.flush()
    print "Test log written to testlog.txt"

def usage(argv0):
    print "Usage: %s [buildflags... --] [root] [root...]" % argv0
    print "  Runs the Clay test suite. If any root paths are given, only tests"
    print "  in those subdirectories (paths relative to the test/ directory) will"
    print "  be run. Build flags can be passed to the compiler followed by '--'."

def main() :
    global testLogFile
    global testBuildFlags
    global testRoot
    global runTestRoot

    if len(sys.argv) > 1 :
        if sys.argv[1] == "--help" or sys.argv[1] == "/?":
            usage(sys.argv[0])
            return

        try:
            buildFlagSeparator = sys.argv.index("--")
            testBuildFlags = sys.argv[1:buildFlagSeparator]
            runTestRoot = os.path.join(testRoot, *sys.argv[buildFlagSeparator+1:])
        except ValueError:
            testBuildFlags = []
            runTestRoot = os.path.join(testRoot, *sys.argv[1:])
    else:
        testBuildFlags = []
        runTestRoot = testRoot
    startTime = time.time()
    runTests()
    endTime = time.time()
    print ""
    print "time taken = %f seconds" % (endTime - startTime)

if __name__ == "__main__":
    main()
<|endoftext|>


<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Search the address space for byte patterns or pointer values.
"""
import struct

import gdb
import pwndbg.arch
import pwndbg.memory
import pwndbg.typeinfo
import pwndbg.vmmap

def search(searchfor):
    value = searchfor
    size  = None

    if searchfor.isdigit():
        searchfor = int(searchfor)
    elif searchfor.startswith('0x') \
    and all(c in 'xABCDEFabcdef0123456789' for c in searchfor):
        searchfor = int(searchfor, 16)

    if isinstance(searchfor, (long, int)):
        if pwndbg.arch.ptrsize == 4:
            searchfor = struct.pack('I', searchfor)
        elif pwndbg.arch.ptrsize == 8:
            searchfor = struct.pack('L', searchfor)

    i = gdb.selected_inferior()

    maps = pwndbg.vmmap.get()
    hits = []
    for vmmap in maps:
        start = vmmap.vaddr
        end   = start + vmmap.memsz
        while True:
            # No point in searching if we can't read the memory
            if not pwndbg.memory.peek(start):
                break

            start = i.search_memory(start, end - start, searchfor)

            if start is None:
                break

            # For some reason, search_memory will return a positive hit
            # when it's unable to read memory.
            if not pwndbg.memory.peek(start):
                break

            yield start
            start += len(searchfor)
<commit_msg>Add support for character search<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Search the address space for byte patterns or pointer values.
"""
import struct

import gdb
import pwndbg.arch
import pwndbg.memory
import pwndbg.typeinfo
import pwndbg.vmmap

def search(searchfor, searchtype=None):
    value = searchfor
    size  = None

    if searchtype != 'c' and searchtype != 'xc':
        if searchfor.isdigit():
            searchfor = int(searchfor)
        elif searchfor.startswith('0x') \
        and all(c in 'xABCDEFabcdef0123456789' for c in searchfor):
            searchfor = int(searchfor, 16)

        if isinstance(searchfor, (long, int)):
            if pwndbg.arch.ptrsize == 4:
                searchfor = struct.pack('I', searchfor)
            elif pwndbg.arch.ptrsize == 8:
                searchfor = struct.pack('L', searchfor)

    elif searchtype == 'xc':
        if '\\x' in searchfor:
            searchfor = bytes.fromhex(''.join(searchfor.split('\\x')))
        elif 'x' in searchfor:
            searchfor = bytes.fromhex(''.join(searchfor.split('x')))
        else:
            searchfor = bytes.fromhex(''.join(searchfor[i:i+2]
                                          for i in range(0, len(searchfor), 2)))

    i = gdb.selected_inferior()

    maps = pwndbg.vmmap.get()
    hits = []
    for vmmap in maps:
        start = vmmap.vaddr
        end   = start + vmmap.memsz
        while True:
            # No point in searching if we can't read the memory
            if not pwndbg.memory.peek(start):
                break

            start = i.search_memory(start, end - start, searchfor)

            if start is None:
                break

            # For some reason, search_memory will return a positive hit
            # when it's unable to read memory.
            if not pwndbg.memory.peek(start):
                break

            yield start
            start += len(searchfor)
<|endoftext|>


<commit_before>from __future__ import absolute_import

from bitfield.types import Bit, BitHandler

class BitQueryLookupWrapper(object):
    def __init__(self, alias, column, bit):
        self.table_alias = alias
        self.column = column
        self.bit = bit

    def as_sql(self, qn, connection=None):
        """
        Create the proper SQL fragment. This inserts something like
        "(T0.flags & value) != 0".

        This will be called by Where.as_sql()
        """
        if self.bit:
            return ("(%s.%s | %d)" % (qn(self.table_alias), qn(self.column), self.bit.mask), [])
        return ("(%s.%s & %d)" % (qn(self.table_alias), qn(self.column), self.bit.mask), [])

try:
    # Django 1.7+
    from django.db.models.lookups import Exact

    class BitQueryLookupWrapper(Exact):  # NOQA
        def process_lhs(self, qn, connection, lhs=None):
            lhs_sql, params = super(BitQueryLookupWrapper, self).process_lhs(qn, connection, lhs)
            if self.rhs:
                lhs_sql = lhs_sql + ' & %s'
            else:
                lhs_sql = lhs_sql + ' | %s'
            params.append(self.get_db_prep_lookup(self.rhs, connection)[1])
            return lhs_sql, params

        def get_db_prep_lookup(self, value, connection, prepared=False):
            v = value.mask if isinstance(value, (BitHandler, Bit)) else value
            return super(BitQueryLookupWrapper, self).get_db_prep_lookup(v, connection)

        def get_prep_lookup(self):
            return self.rhs

except ImportError:
    pass

class BitQuerySaveWrapper(BitQueryLookupWrapper):
    def as_sql(self, qn, connection):
        """
        Create the proper SQL fragment. This inserts something like
        "(T0.flags & value) != 0".

        This will be called by Where.as_sql()
        """
        engine = connection.settings_dict['ENGINE'].rsplit('.', -1)[-1]
        if engine.startswith('postgres'):
            XOR_OPERATOR = '#'
        elif engine.startswith('sqlite'):
            raise NotImplementedError
        else:
            XOR_OPERATOR = '^'

        if self.bit:
            return ("%s.%s | %d" % (qn(self.table_alias), qn(self.column), self.bit.mask), [])
        return (
            "%s.%s %s %d" % (qn(self.table_alias), qn(self.column), XOR_OPERATOR, self.bit.mask), []
        )
<commit_msg>Correct BitField query behavior<commit_after>from __future__ import absolute_import

from bitfield.types import Bit, BitHandler

class BitQueryLookupWrapper(object):
    def __init__(self, alias, column, bit):
        self.table_alias = alias
        self.column = column
        self.bit = bit

    def as_sql(self, qn, connection=None):
        """
        Create the proper SQL fragment. This inserts something like
        "(T0.flags & value) != 0".

        This will be called by Where.as_sql()
        """
        if self.bit:
            return ("(%s.%s | %d)" % (qn(self.table_alias), qn(self.column), self.bit.mask), [])
        return ("(%s.%s & %d)" % (qn(self.table_alias), qn(self.column), self.bit.mask), [])

try:
    # Django 1.7+
    from django.db.models.lookups import Exact

    class BitQueryLookupWrapper(Exact):  # NOQA
        def process_lhs(self, qn, connection, lhs=None):
            lhs_sql, params = super(BitQueryLookupWrapper, self).process_lhs(
                qn, connection, lhs)
            lhs_sql = lhs_sql + ' | %s'
            params.extend(self.process_rhs(qn, connection)[1])
            return lhs_sql, params

        def get_db_prep_lookup(self, value, connection, prepared=False):
            v = value.mask if isinstance(value, (BitHandler, Bit)) else value
            return super(BitQueryLookupWrapper, self).get_db_prep_lookup(v, connection)

        def get_prep_lookup(self):
            return self.rhs

except ImportError:
    pass

class BitQuerySaveWrapper(BitQueryLookupWrapper):
    def as_sql(self, qn, connection):
        """
        Create the proper SQL fragment. This inserts something like
        "(T0.flags & value) != 0".

        This will be called by Where.as_sql()
        """
        if self.bit:
            return ("%s.%s | %d" % (qn(self.table_alias), qn(self.column), self.bit.mask), [])
        return (
            "%s.%s & ~%d" % (qn(self.table_alias), qn(self.column), self.bit.mask), []
        )
<|endoftext|>


<commit_before>from __future__ import division, unicode_literals
import os
from mpcontribs.rest.rester import MPContribsRester
from mpcontribs.io.archieml.mpfile import MPFile
from pandas import DataFrame

class SWFRester(MPContribsRester):
    """SWF-specific convenience functions to interact with MPContribs REST interface"""
    mpfile = MPFile.from_file(os.path.join(
        os.path.dirname(__file__), '..', 'mpfile_init.txt'
    ))
    swf_query = ('doi', mpfile.hdata.general['doi'])

    def get_contributions(self):
        data = []
        columns = [
            'formula', 'contribution',
            'Fe', 'Co', 'V',
            'IP_Energy_product'
        ]

        docs = self.query_contributions(
            criteria=self.swf_query,
            projection={
                '_id': 1, 'mp_cat_id': 1,
                'content.compositions.Fe': 1,
                'content.compositions.Co': 1,
                'content.compositions.V': 1,
                'content.IP_Energy_product': 1}
        )
        if not docs:
            raise Exception('No contributions found for SWF Explorer!')

        for doc in docs:
            mpfile = MPFile.from_contribution(doc)
            formula = mpfile.ids[0]
            contrib = mpfile.hdata[formula]
            cid_url = '/'.join([
                self.preamble.rsplit('/', 1)[0], 'explorer', 'materials', doc['_id']
            ])
            row = [
                formula, cid_url,
                contrib['compositions']['Fe'],
                contrib['compositions']['Co'],
                contrib['compositions']['V'],
                contrib['IP_Energy_product']
            ]
            data.append((formula, row))
        return DataFrame.from_items(data, orient='index', columns=columns)

    def get_provenance(self):
        provenance_keys = ['title', 'doi', 'reference', 'authors', 'contributor']
        projection = {'_id': 1, 'mp_cat_id': 1}
        for key in provenance_keys:
            projection['content.' + key] = 1
        docs = self.query_contributions(criteria=self.swf_query, projection=projection)
        if not docs:
            raise Exception('No contributions found for SWF Explorer!')

        mpfile = MPFile.from_contribution(docs[0])
        formula = mpfile.ids[0]
        return mpfile.hdata[formula]

<commit_msg>swf: fix query tuple<commit_after>from __future__ import division, unicode_literals
import os
from mpcontribs.rest.rester import MPContribsRester
from mpcontribs.io.archieml.mpfile import MPFile
from pandas import DataFrame

class SWFRester(MPContribsRester):
    """SWF-specific convenience functions to interact with MPContribs REST interface"""
    mpfile = MPFile.from_file(os.path.join(
        os.path.dirname(__file__), '..', 'mpfile_init.txt'
    ))
    swf_query = tuple({'content.doi': mpfile.hdata.general['doi']}.iteritems())

    def get_contributions(self):
        data = []
        columns = [
            'formula', 'contribution',
            'Fe', 'Co', 'V',
            'IP_Energy_product'
        ]

        docs = self.query_contributions(
            criteria=self.swf_query,
            projection={
                '_id': 1, 'mp_cat_id': 1,
                'content.compositions.Fe': 1,
                'content.compositions.Co': 1,
                'content.compositions.V': 1,
                'content.IP_Energy_product': 1}
        )
        if not docs:
            raise Exception('No contributions found for SWF Explorer!')

        for doc in docs:
            mpfile = MPFile.from_contribution(doc)
            formula = mpfile.ids[0]
            contrib = mpfile.hdata[formula]
            cid_url = '/'.join([
                self.preamble.rsplit('/', 1)[0], 'explorer', 'materials', doc['_id']
            ])
            row = [
                formula, cid_url,
                contrib['compositions']['Fe'],
                contrib['compositions']['Co'],
                contrib['compositions']['V'],
                contrib['IP_Energy_product']
            ]
            data.append((formula, row))
        return DataFrame.from_items(data, orient='index', columns=columns)

    def get_provenance(self):
        provenance_keys = ['title', 'doi', 'reference', 'authors', 'contributor']
        projection = {'_id': 1, 'mp_cat_id': 1}
        for key in provenance_keys:
            projection['content.' + key] = 1
        docs = self.query_contributions(criteria=self.swf_query, projection=projection)
        if not docs:
            raise Exception('No contributions found for SWF Explorer!')

        mpfile = MPFile.from_contribution(docs[0])
        formula = mpfile.ids[0]
        return mpfile.hdata[formula]

<|endoftext|>


<commit_before>import django.views.static
from django.conf import settings
from django.urls import include, path
from django.contrib import admin
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
from django.views.generic import TemplateView

admin.autodiscover()

urlpatterns = [
    path('', TemplateView.as_view(template_name='base.html')),
    path('admin/', admin.site.urls),
    {%- if cookiecutter.use_djangocms == 'y' %}
    path('', include('cms.urls')),
    {%- endif %}
]

if settings.DEBUG:
    import debug_toolbar
    urlpatterns = [
        path('media/<path:path>/', django.views.static.serve,
            {'document_root': settings.MEDIA_ROOT, 'show_indexes': True}),
        path('__debug__/', include(debug_toolbar.urls)),
    ] + staticfiles_urlpatterns() + urlpatterns
<commit_msg>Fix under-indentation in URLConf<commit_after>import django.views.static
from django.conf import settings
from django.urls import include, path
from django.contrib import admin
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
from django.views.generic import TemplateView

admin.autodiscover()

urlpatterns = [
    path('', TemplateView.as_view(template_name='base.html')),
    path('admin/', admin.site.urls),
    {%- if cookiecutter.use_djangocms == 'y' %}
    path('', include('cms.urls')),
    {%- endif %}
]

if settings.DEBUG:
    import debug_toolbar
    urlpatterns = [
        path('media/<path:path>/', django.views.static.serve, {
            'document_root': settings.MEDIA_ROOT, 'show_indexes': True
        }),
        path('__debug__/', include(debug_toolbar.urls)),
    ] + staticfiles_urlpatterns() + urlpatterns
<|endoftext|>


<commit_before>"""
The Flow module lets you connect to processes or network services using a
unified API. It is primarily designed for synchronous communication flows.

It is based around the central :class:`Flow` class which uses a ``Channel``
to connect to a process. The :class:`Flow` class then uses the primitives
exposed by the ``Channel`` to provide a high level API for reading/receiving
and writing/sending data.

Examples:
    >>> from pwny import *
    >>> f = Flow.connect_tcp('ced.pwned.systems', 80)
    >>> f.writelines([
    ...     b'GET / HTTP/1.0',
    ...     b'Host: ced.pwned.systems',
    ...     b'',
    ... ])
    >>> line = f.readline().strip()
    >>> print(line == b'HTTP/1.0 200 OK')
    True
    >>> f.until(b'\\r\\n\\r\\n')
    >>> f.read_eof(echo=True)
    ... lots of html ...

    >>> from pwny import *
    >>> f = Flow.execute('cat')
    >>> f.writeline(b'hello')
    >>> f.readline(echo=True)
"""

import subprocess
import sys
import socket

__all__ = [
    'ProcessChannel',
    'SocketChannel',
    'TCPClientSocketChannel',
    'Flow',
]

class ProcessChannel(object):
    """ProcessChannel(executable, argument..., redirect_stderr=False)

    This channel type allows controlling processes. It uses python's
    ``subprocess.Popen`` class to execute a process and allows you to
    communicate with it.

    Args:
        executable(str): The executable to start.
        argument...(list of str): The arguments to pass to the executable.
        redirect_stderr(bool): Whether to also capture the output of stderr.
    """

    def __init__(self, executable, *arguments, **kwargs):
        if kwargs.get('redirect_stderr'):
            stderr = subprocess.STDOUT
        else:
            stderr = None

        self._process = subprocess.Popen(
            (executable,) + tuple(arguments),
            bufsize=0,
            stdin=subprocess.PIPE,
            stdout=subprocess.PIPE,
            stderr=stderr,
        )

    def read(self, n):
        """
        Read *n* bytes from the subprocess' output channel.

        Args:
            n(int): The number of bytes to read.

        Returns:
            bytes: *n* bytes of output.

        Raises:
            EOFError: If the process exited.
        """

        d = b''
        while n:
            try:
                block = self._process.stdout.read(n)
            except ValueError:
                block = None
            if not block:
                self._process.poll()
                raise EOFError('Process ended')
            d += block
            n -= len(block)
        return d

    def write(self, data):
        """
        Write *n* bytes to the subprocess' input channel.

        Args:
            data(bytes): The data to write.

        Raises:
            EOFError: If the process exited.
        """

        self._process.poll()
        if self._process.returncode is not None:
            raise EOFError('Process ended')
        self._process.stdin.write(data)

    def close(self):
        """
        Wait for the subprocess to exit.
        """

        self._process.communicate()

    def kill(self):
        """
        Terminate the subprocess.
        """

        self._process.kill()

class SocketChannel(object):
    """
    This channel type allows controlling sockets.

    Args:
        socket(socket.socket): The (already connected) socket to control.
    """

    def __init__(self, sock):
        self._socket = sock

    def read(self, n):
        """
        Receive *n* bytes from the socket.

        Args:
            n(int): The number of bytes to read.

        Returns:
            bytes: *n* bytes read from the socket.

        Raises:
            EOFError: If the socket was closed.
        """

        d = b''
        while n:
            try:
                block = self._socket.recv(n)
            except socket.error:
                block = None
            if not block:
                raise EOFError('Socket closed')
            d += block
            n -= len(block)
        return d

    def write(self, data):
        """
        Send *n* bytes to socket.

        Args:
            data(bytes): The data to send.

        Raises:
            EOFError: If the socket was closed.
        """

        while data:
            try:
                n = self._socket.send(data)
            except socket.error:
                n = None
            if not n:
                raise EOFError('Socket closed')
            data = data[n:]

    def close(self):
        """
        Close the socket gracefully.
        """

        self._socket.close()

    def kill(self):
        """
        Shut down the socket immediately.
        """

        self._socket.shutdown(socket.SHUT_RDWR)
        self._socket.close()

class TCPClientSocketChannel(SocketChannel):
    """
    Convenience subclass of :class:`SocketChannel` that allows you to connect
    to a TCP hostname / port pair easily.

    Args:
        host(str): The hostname or IP address to connect to.
        port(int): The port number to connect to.
    """

    def __init__(self, host, port):
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect((host, port))
        super(TCPClientSocketChannel, self).__init__(s)

class Flow(object):
    """
    The core class of *Flow*. Takes a channel and exposes synchronous
    utility functions for communications.

    Usually, you'll use the convenience classmethods :meth:`connect_tcp`
    or :meth:`execute` instead of manually creating the constructor
    directly.

    Args:
        channel(``Channel``): A channel.
        echo(bool): Whether or not to echo all input / output.
    """

    def __init__(self, channel, echo=False):
        self.channel = channel
        self.echo = echo

    def read(self, n, echo=None):
        """
        Read *n* bytes from the channel.

        Args:
            n(int): The number of bytes to read from the channel.
            echo(bool): Whether to write the read data to stdout.

        Returns:
            bytes: *n* bytes of data.

        Raises:
            EOFError: If the channel was closed.
        """

        d = self.channel.read(n)
        if echo or (echo is None and self.echo):
            sys.stdout.write(d.decode('latin1'))
        return d

    def read_eof(self, echo=None):
        """
        Read until the channel is closed.

        Args:
            echo(bool): Whether to write the read data to stdout.

        Returns:
            bytes: The read data.
        """

        d = b''
        while True:
            try:
                d += self.read(1, echo)
            except EOFError:
                return d

    def read_until(self, s, echo=None):
        """
        Read until a certain string is encountered..

        Args:
            s(bytes): The string to wait for.
            echo(bool): Whether to write the read data to stdout.

        Returns:
            bytes: The data up to and including *s*.

        Raises:
            EOFError: If the channel was closed.
        """

        s_len = len(s)
        buf = self.read(s_len, echo)

        while buf[-s_len:] != s:
            buf += self.read(1, echo)

        return buf

    until = read_until  #: Alias of :meth:`read_until`.

    def readlines(self, n, echo=None):
        """
        Read *n* lines from channel.

        Args:
            n(int): The number of lines to read.
            echo(bool): Whether to write the read data to stdout.

        Returns:
            list of bytes: *n* lines which include new line characters.

        Raises:
            EOFError: If the channel was closed before *n* lines were read.
        """

        return [
            self.until(b'\n', echo)
            for _ in range(n)
        ]

    def readline(self, echo=None):
        """
        Read 1 line from channel.

        Args:
            echo(bool): Whether to write the read data to stdout.

        Returns:
            bytes: The read line which includes new line character.

        Raises:
            EOFError: If the channel was closed before a line was read.
        """

        return self.readlines(1, echo)[0]

    def write(self, data, echo=None):
        """
        Write data to channel.

        Args:
            data(bytes): The data to write to the channel.
            echo(bool): Whether to echo the written data to stdout.

        Raises:
            EOFError: If the channel was closed before all data was sent.
        """

        if echo or (echo is None and self.echo):
            sys.stdout.write(data.decode('latin1'))
        self.channel.write(data)

    def writelines(self, lines, echo=None):
        """
        Write a list of byte sequences to the channel and terminate them
        with carriage return and line feed.

        Args:
            lines(list of bytes): The lines to send.
            echo(bool): Whether to echo the written data to stdout.

        Raises:
            EOFError: If the channel was closed before all data was sent.
        """

        self.write(b'\r\n'.join(lines + [b'']), echo)

    def writeline(self, line=b'', echo=None):
        """
        Write a byte sequences to the channel and terminate it with carriage
        return and line feed.

        Args:
            line(bytes): The line to send.
            echo(bool): Whether to echo the written data to stdout.

        Raises:
            EOFError: If the channel was closed before all data was sent.
        """

        self.writelines([line], echo)

    def close(self):
        """
        Gracefully close the channel.
        """

        self.channel.close()

    def kill(self):
        """
        Terminate the channel immediately.
        """

        self.channel.kill()

    @classmethod
    def execute(cls, executable, *arguments, **kwargs):
        """execute(executable, argument..., redirect_stderr=False, echo=False):

        Set up a :class:`ProcessChannel` and create a :class:`Flow` instance
        for it.

        Args:
            executable(str): The executable to start.
            argument...(list of str): The arguments to pass to the executable.
            redirect_stderr(bool): Whether to also capture the output of stderr.
            echo(bool): Whether to echo read/written data to stdout by default.

        Returns:
            :class:`Flow`: A Flow instance initialised with the process
                channel.
        """

        echo = kwargs.pop('echo', False)
        return cls(ProcessChannel(executable, *arguments, **kwargs), echo=echo)

    @classmethod
    def connect_tcp(cls, host, port, echo=False):
        """
        Set up a :class:`TCPClientSocketChannel` and create a :class:`Flow`
        instance for it.

        Args:
            host(str): The hostname or IP address to connect to.
            port(int): The port number to connect to.
            echo(bool): Whether to echo read/written data to stdout by default.

        Returns:
            :class:`Flow`: A Flow instance initialised with the TCP socket
                channel.
        """

        return cls(TCPClientSocketChannel(host, port), echo=echo)
<commit_msg>Add fileno() property to Flow channels.<commit_after>"""
The Flow module lets you connect to processes or network services using a
unified API. It is primarily designed for synchronous communication flows.

It is based around the central :class:`Flow` class which uses a ``Channel``
to connect to a process. The :class:`Flow` class then uses the primitives
exposed by the ``Channel`` to provide a high level API for reading/receiving
and writing/sending data.

Examples:
    >>> from pwny import *
    >>> f = Flow.connect_tcp('ced.pwned.systems', 80)
    >>> f.writelines([
    ...     b'GET / HTTP/1.0',
    ...     b'Host: ced.pwned.systems',
    ...     b'',
    ... ])
    >>> line = f.readline().strip()
    >>> print(line == b'HTTP/1.0 200 OK')
    True
    >>> f.until(b'\\r\\n\\r\\n')
    >>> f.read_eof(echo=True)
    ... lots of html ...

    >>> from pwny import *
    >>> f = Flow.execute('cat')
    >>> f.writeline(b'hello')
    >>> f.readline(echo=True)
"""

import subprocess
import sys
import socket

__all__ = [
    'ProcessChannel',
    'SocketChannel',
    'TCPClientSocketChannel',
    'Flow',
]

class ProcessChannel(object):
    """ProcessChannel(executable, argument..., redirect_stderr=False)

    This channel type allows controlling processes. It uses python's
    ``subprocess.Popen`` class to execute a process and allows you to
    communicate with it.

    Args:
        executable(str): The executable to start.
        argument...(list of str): The arguments to pass to the executable.
        redirect_stderr(bool): Whether to also capture the output of stderr.
    """

    def __init__(self, executable, *arguments, **kwargs):
        if kwargs.get('redirect_stderr'):
            stderr = subprocess.STDOUT
        else:
            stderr = None

        self._process = subprocess.Popen(
            (executable,) + tuple(arguments),
            bufsize=0,
            stdin=subprocess.PIPE,
            stdout=subprocess.PIPE,
            stderr=stderr,
        )

    def fileno(self):
        return self._process.stdout.fileno()

    def read(self, n):
        """
        Read *n* bytes from the subprocess' output channel.

        Args:
            n(int): The number of bytes to read.

        Returns:
            bytes: *n* bytes of output.

        Raises:
            EOFError: If the process exited.
        """

        d = b''
        while n:
            try:
                block = self._process.stdout.read(n)
            except ValueError:
                block = None
            if not block:
                self._process.poll()
                raise EOFError('Process ended')
            d += block
            n -= len(block)
        return d

    def write(self, data):
        """
        Write *n* bytes to the subprocess' input channel.

        Args:
            data(bytes): The data to write.

        Raises:
            EOFError: If the process exited.
        """

        self._process.poll()
        if self._process.returncode is not None:
            raise EOFError('Process ended')
        self._process.stdin.write(data)

    def close(self):
        """
        Wait for the subprocess to exit.
        """

        self._process.communicate()

    def kill(self):
        """
        Terminate the subprocess.
        """

        self._process.kill()

class SocketChannel(object):
    """
    This channel type allows controlling sockets.

    Args:
        socket(socket.socket): The (already connected) socket to control.
    """

    def __init__(self, sock):
        self._socket = sock

    def fileno(self):
        return self._socket.fileno()

    def read(self, n):
        """
        Receive *n* bytes from the socket.

        Args:
            n(int): The number of bytes to read.

        Returns:
            bytes: *n* bytes read from the socket.

        Raises:
            EOFError: If the socket was closed.
        """

        d = b''
        while n:
            try:
                block = self._socket.recv(n)
            except socket.error:
                block = None
            if not block:
                raise EOFError('Socket closed')
            d += block
            n -= len(block)
        return d

    def write(self, data):
        """
        Send *n* bytes to socket.

        Args:
            data(bytes): The data to send.

        Raises:
            EOFError: If the socket was closed.
        """

        while data:
            try:
                n = self._socket.send(data)
            except socket.error:
                n = None
            if not n:
                raise EOFError('Socket closed')
            data = data[n:]

    def close(self):
        """
        Close the socket gracefully.
        """

        self._socket.close()

    def kill(self):
        """
        Shut down the socket immediately.
        """

        self._socket.shutdown(socket.SHUT_RDWR)
        self._socket.close()

class TCPClientSocketChannel(SocketChannel):
    """
    Convenience subclass of :class:`SocketChannel` that allows you to connect
    to a TCP hostname / port pair easily.

    Args:
        host(str): The hostname or IP address to connect to.
        port(int): The port number to connect to.
    """

    def __init__(self, host, port):
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect((host, port))
        super(TCPClientSocketChannel, self).__init__(s)

class Flow(object):
    """
    The core class of *Flow*. Takes a channel and exposes synchronous
    utility functions for communications.

    Usually, you'll use the convenience classmethods :meth:`connect_tcp`
    or :meth:`execute` instead of manually creating the constructor
    directly.

    Args:
        channel(``Channel``): A channel.
        echo(bool): Whether or not to echo all input / output.
    """

    def __init__(self, channel, echo=False):
        self.channel = channel
        self.echo = echo

    def read(self, n, echo=None):
        """
        Read *n* bytes from the channel.

        Args:
            n(int): The number of bytes to read from the channel.
            echo(bool): Whether to write the read data to stdout.

        Returns:
            bytes: *n* bytes of data.

        Raises:
            EOFError: If the channel was closed.
        """

        d = self.channel.read(n)
        if echo or (echo is None and self.echo):
            sys.stdout.write(d.decode('latin1'))
        return d

    def read_eof(self, echo=None):
        """
        Read until the channel is closed.

        Args:
            echo(bool): Whether to write the read data to stdout.

        Returns:
            bytes: The read data.
        """

        d = b''
        while True:
            try:
                d += self.read(1, echo)
            except EOFError:
                return d

    def read_until(self, s, echo=None):
        """
        Read until a certain string is encountered..

        Args:
            s(bytes): The string to wait for.
            echo(bool): Whether to write the read data to stdout.

        Returns:
            bytes: The data up to and including *s*.

        Raises:
            EOFError: If the channel was closed.
        """

        s_len = len(s)
        buf = self.read(s_len, echo)

        while buf[-s_len:] != s:
            buf += self.read(1, echo)

        return buf

    until = read_until  #: Alias of :meth:`read_until`.

    def readlines(self, n, echo=None):
        """
        Read *n* lines from channel.

        Args:
            n(int): The number of lines to read.
            echo(bool): Whether to write the read data to stdout.

        Returns:
            list of bytes: *n* lines which include new line characters.

        Raises:
            EOFError: If the channel was closed before *n* lines were read.
        """

        return [
            self.until(b'\n', echo)
            for _ in range(n)
        ]

    def readline(self, echo=None):
        """
        Read 1 line from channel.

        Args:
            echo(bool): Whether to write the read data to stdout.

        Returns:
            bytes: The read line which includes new line character.

        Raises:
            EOFError: If the channel was closed before a line was read.
        """

        return self.readlines(1, echo)[0]

    def write(self, data, echo=None):
        """
        Write data to channel.

        Args:
            data(bytes): The data to write to the channel.
            echo(bool): Whether to echo the written data to stdout.

        Raises:
            EOFError: If the channel was closed before all data was sent.
        """

        if echo or (echo is None and self.echo):
            sys.stdout.write(data.decode('latin1'))
        self.channel.write(data)

    def writelines(self, lines, echo=None):
        """
        Write a list of byte sequences to the channel and terminate them
        with carriage return and line feed.

        Args:
            lines(list of bytes): The lines to send.
            echo(bool): Whether to echo the written data to stdout.

        Raises:
            EOFError: If the channel was closed before all data was sent.
        """

        self.write(b'\r\n'.join(lines + [b'']), echo)

    def writeline(self, line=b'', echo=None):
        """
        Write a byte sequences to the channel and terminate it with carriage
        return and line feed.

        Args:
            line(bytes): The line to send.
            echo(bool): Whether to echo the written data to stdout.

        Raises:
            EOFError: If the channel was closed before all data was sent.
        """

        self.writelines([line], echo)

    def close(self):
        """
        Gracefully close the channel.
        """

        self.channel.close()

    def kill(self):
        """
        Terminate the channel immediately.
        """

        self.channel.kill()

    @classmethod
    def execute(cls, executable, *arguments, **kwargs):
        """execute(executable, argument..., redirect_stderr=False, echo=False):

        Set up a :class:`ProcessChannel` and create a :class:`Flow` instance
        for it.

        Args:
            executable(str): The executable to start.
            argument...(list of str): The arguments to pass to the executable.
            redirect_stderr(bool): Whether to also capture the output of stderr.
            echo(bool): Whether to echo read/written data to stdout by default.

        Returns:
            :class:`Flow`: A Flow instance initialised with the process
                channel.
        """

        echo = kwargs.pop('echo', False)
        return cls(ProcessChannel(executable, *arguments, **kwargs), echo=echo)

    @classmethod
    def connect_tcp(cls, host, port, echo=False):
        """
        Set up a :class:`TCPClientSocketChannel` and create a :class:`Flow`
        instance for it.

        Args:
            host(str): The hostname or IP address to connect to.
            port(int): The port number to connect to.
            echo(bool): Whether to echo read/written data to stdout by default.

        Returns:
            :class:`Flow`: A Flow instance initialised with the TCP socket
                channel.
        """

        return cls(TCPClientSocketChannel(host, port), echo=echo)
<|endoftext|>


<commit_before>from framework import *

n = 7
print "%d arcs" % n

arcstyle = [PIESLICE, CHORD, ARC]

for j, style in enumerate(arcstyle):
	for i in xrange(n):
		rx = 50
		ry = 20
		y  = i*2*(ry+5) + 10 + ry
		x  = j*2*(rx+5) + 10 + rx

		k  = i+1
		canv.create_arc(x-rx, y-ry, x+rx, y+ry,
			start=k*5, extent=k*45, style=style,
			fill="#dddddd"
		)

thread.start_new_thread(test, (canv, __file__, True))
root.mainloop()
<commit_msg>random colors<commit_after>from framework import *
root.title("Arc geometry test ($Revision: 1.3 $)")

n = 7
arcstyle = [PIESLICE, CHORD, ARC]

for j, style in enumerate(arcstyle):
	for i in xrange(n):
		rx = 50
		ry = 20
		y  = i*2*(ry+5) + 10 + ry
		x  = j*2*(rx+5) + 10 + rx

		k  = i+1
		canv.create_arc(x-rx, y-ry, x+rx, y+ry,
			start	= k*5,
			extent	= k*45,
			style	= style,
			fill	= random_fill(),
			outline	= random_color(),
		)

thread.start_new_thread(test, (canv, __file__, True))
root.mainloop()
<|endoftext|>


<commit_before>#! /usr/bin/env python

"""
Support functions for all the tests.
"""

#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

def isExecutableOfToolAvailable(test, tool):
    for executable in {
        'dmd': ['dmd', 'gdmd'],
        'gdc': ['gdc'],
        'ldc': ['ldc2', 'ldc']}[tool]:
        if test.where_is(executable):
            return True
    return False

if __name__ == '__main__':
    import unittest
    import sys
    import os.path
    sys.path.append(os.path.abspath('../../../QMTest'))
    sys.path.append(os.path.abspath('../../../src/engine'))
    import TestSCons

    class VariousTests(unittest.TestCase):
        def setUp(self):
            self.test = TestSCons.TestSCons()
        def test_None_tool(self):
            self.assertRaises(KeyError, isExecutableOfToolAvailable, self.test, None)
        def test_dmd_tool(self):
            self.assertEqual(
                self.test.where_is('dmd') is not None or self.test.where_is('gdmd') is not None,
                isExecutableOfToolAvailable(self.test, 'dmd'))
        def test_gdc_tool(self):
            self.assertEqual(
                self.test.where_is('gdc') is not None,
                isExecutableOfToolAvailable(self.test, 'gdc'))
        def test_ldc_tool(self):
            self.assertEqual(
                self.test.where_is('ldc2') is not None or self.test.where_is('ldc') is not None,
                isExecutableOfToolAvailable(self.test, 'ldc'))

    unittest.main()
<commit_msg>Amend the executable search support function to use the default SCons path only.<commit_after>#! /usr/bin/env python

"""
Support functions for all the tests.
"""

#
# __COPYRIGHT__
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#

__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"

if __name__ == '__main__':
    import sys
    import os.path
    sys.path.append(os.path.abspath('../../../src/engine'))

from SCons.Environment import Base

path = Base()['ENV']['PATH']

def isExecutableOfToolAvailable(test, tool):
    for executable in {
        'dmd': ['dmd', 'gdmd'],
        'gdc': ['gdc'],
        'ldc': ['ldc2', 'ldc'],
    }[tool]:
        if test.where_is(executable, path):
            return True
    return False

if __name__ == '__main__':
    import unittest
    sys.path.append(os.path.abspath('../../../QMTest'))

    import TestSCons

    class VariousTests(unittest.TestCase):
        '''
        These tests are somewhat self referential in that
        isExecutableOfToolAvailable uses where_is to do most of it's
        work and we use the same function in the tests.
        '''
        def setUp(self):
            self.test = TestSCons.TestSCons()

        def tearDown(self):
            self.test = None

        def test_None_tool(self):
            self.assertRaises(KeyError, isExecutableOfToolAvailable, self.test, None)

        def test_dmd_tool(self):
            self.assertEqual(
                self.test.where_is('dmd', path) is not None or self.test.where_is('gdmd', path) is not None,
                isExecutableOfToolAvailable(self.test, 'dmd'))

        def test_gdc_tool(self):
            self.assertEqual(
                self.test.where_is('gdc', path) is not None,
                isExecutableOfToolAvailable(self.test, 'gdc'))

        def test_ldc_tool(self):
            self.assertEqual(
                self.test.where_is('ldc2', path) is not None or self.test.where_is('ldc', path) is not None,
                isExecutableOfToolAvailable(self.test, 'ldc'))

    unittest.main()
<|endoftext|>


<commit_before>from syn.five import STR, strf
from collections import Iterable
from syn.base_utils import hasmethod, message, nearest_base

#-------------------------------------------------------------------------------
# Base Class

class Type(object):
    '''A representation for various possible types syn supports.'''
    __slots__ = ()

    def check(self, value):
        raise NotImplementedError

    @classmethod
    def dispatch(cls, obj):
        if isinstance(obj, Type):
            return obj

        if obj is None:
            return AnyType()

        if isinstance(obj, type):
            if issubclass(obj, TypeExtension):
                return obj()
            return TypeType(obj)

        if isinstance(obj, tuple):
            # Treat a singleton tuple as its element
            if len(obj) == 1:
                return cls.dispatch(obj[0])
            return MultiType(obj)

        if isinstance(obj, Iterable) and not isinstance(obj, STR + (bytes,)):
            return ValuesType(obj)

        raise TypeError('Unable to dispatch appropriate type represetation'
                         ' for {}'.format(obj))

    def coerce(self, value):
        raise NotImplementedError

    def query(self, value):
        try:
            self.check(value)
            return True
        except TypeError:
            return False

    def query_exception(self, value):
        try:
            self.check(value)
            return True, None
        except TypeError as e:
            return False, e

    def validate(self, value):
        raise NotImplementedError

#-------------------------------------------------------------------------------
# Any Type

class AnyType(Type):
    def check(self, value):
        pass

    def coerce(self, value):
        return value

    def validate(self, value):
        pass

#-------------------------------------------------------------------------------
# Type Type

class TypeType(Type):
    __slots__ = ('type', 'call_coerce', 'call_validate')

    def __init__(self, typ):
        self.type = typ
        self.call_coerce = hasmethod(self.type, 'coerce')
        self.call_validate = hasmethod(self.type, 'validate')

    def check(self, value):
        if not isinstance(value, self.type):
            raise TypeError('Expected value of type {}; got: {}'
                            .format(self.type, value))

    def coerce(self, value):
        if self.query(value):
            return value

        try:
            if self.call_coerce:
                return self.type.coerce(value)
            return self.type(value)
        except Exception as e:
            raise TypeError('Cannot coerce {} to type {}: {}'
                            .format(value, self.type, message(e)))

    def validate(self, value):
        self.check(value)

        if self.call_validate:
            value.validate()

#-------------------------------------------------------------------------------
# Values Type

class ValuesType(Type):
    '''A set (or list) of values, any of which is valid.

    Think of this is a denotational definition of the type.
    '''
    __slots__ = ('values', 'indexed_values')

    def __init__(self, values):
        self.values = values

        self.indexed_values = values
        if not hasattr(values, '__getitem__'):
            self.indexed_values = list(values)

    def check(self, value):
        if value not in self.values:
            raise TypeError('Invalid value: {}'.format(value))

    def coerce(self, value):
        try:
            self.check(value)
        except TypeError as e:
            raise TypeError('Cannot coerce {}: {}'.format(value, message(e)))
        return value

    def validate(self, value):
        self.check(value)

#-------------------------------------------------------------------------------
# MultiType

class MultiType(Type):
    '''A tuple of type specifiers, any of which may be valid.
    '''
    __slots__ = ('types', 'typestr', 'typelist', 'typemap', 'is_typelist')

    def __init__(self, types):
        self.is_typelist = False
        if all(isinstance(typ, type) for typ in types):
            self.is_typelist = True
            self.typelist = types

        self.typestr = ', '.join(map(strf, types))
        self.types = [Type.dispatch(typ) for typ in types]
        self.typemap = dict(zip(types, self.types))

    def check(self, value):
        if self.is_typelist:
            if isinstance(value, self.typelist):
                return self.typemap[nearest_base(type(value), self.typelist)]

        else:
            for typ in self.types:
                try:
                    typ.check(value)
                    return typ
                except TypeError:
                    pass

        raise TypeError("Value '{}' is not any valid type: {}"
                        .format(value, self.typestr))

    def coerce(self, value):
        for typ in self.types:
            try:
                return typ.coerce(value)
            except TypeError:
                pass

        raise TypeError('Cannot coerce {} to any valid type: {}'
                        .format(value, self.typestr))

    def validate(self, value):
        typ = self.check(value)
        typ.validate(value)

#-------------------------------------------------------------------------------
# TypeExtension

class TypeExtension(Type):
    '''For extending the type system.
    '''

    def validate(self, value):
        self.check(value)

#-------------------------------------------------------------------------------
# __all__

__all__ = ('Type', 'AnyType', 'TypeType', 'ValuesType', 'MultiType',
           'TypeExtension')

#-------------------------------------------------------------------------------
<commit_msg>comments<commit_after>from syn.five import STR, strf
from collections import Iterable
from syn.base_utils import hasmethod, message, nearest_base

#-------------------------------------------------------------------------------
# Base Class

class Type(object):
    '''A representation for various possible types syn supports.'''
    __slots__ = ()

    def check(self, value):
        raise NotImplementedError

    @classmethod
    def dispatch(cls, obj):
        if isinstance(obj, Type):
            return obj

        if obj is None:
            return AnyType()

        if isinstance(obj, type):
            if issubclass(obj, TypeExtension):
                return obj()
            return TypeType(obj)

        if isinstance(obj, tuple):
            # Treat a singleton tuple as its element
            if len(obj) == 1:
                return cls.dispatch(obj[0])
            return MultiType(obj)

        # Exclude bytes b/c it is more closely related to string than list
        if isinstance(obj, Iterable) and not isinstance(obj, STR + (bytes,)):
            return ValuesType(obj)

        raise TypeError('Unable to dispatch appropriate type represetation'
                         ' for {}'.format(obj))

    def coerce(self, value):
        raise NotImplementedError

    def query(self, value):
        try:
            self.check(value)
            return True
        except TypeError:
            return False

    def query_exception(self, value):
        try:
            self.check(value)
            return True, None
        except TypeError as e:
            return False, e

    def validate(self, value):
        raise NotImplementedError

#-------------------------------------------------------------------------------
# Any Type

class AnyType(Type):
    def check(self, value):
        pass

    def coerce(self, value):
        return value

    def validate(self, value):
        pass

#-------------------------------------------------------------------------------
# Type Type

class TypeType(Type):
    __slots__ = ('type', 'call_coerce', 'call_validate')

    def __init__(self, typ):
        self.type = typ
        self.call_coerce = hasmethod(self.type, 'coerce')
        self.call_validate = hasmethod(self.type, 'validate')

    def check(self, value):
        if not isinstance(value, self.type):
            raise TypeError('Expected value of type {}; got: {}'
                            .format(self.type, value))

    def coerce(self, value):
        if self.query(value):
            return value

        try:
            if self.call_coerce:
                return self.type.coerce(value)
            return self.type(value)
        except Exception as e:
            raise TypeError('Cannot coerce {} to type {}: {}'
                            .format(value, self.type, message(e)))

    def validate(self, value):
        self.check(value)

        if self.call_validate:
            value.validate()

#-------------------------------------------------------------------------------
# Values Type

class ValuesType(Type):
    '''A set (or list) of values, any of which is valid.

    Think of this is a denotational definition of the type.
    '''
    __slots__ = ('values', 'indexed_values')

    def __init__(self, values):
        self.values = values

        self.indexed_values = values
        if not hasattr(values, '__getitem__'):
            self.indexed_values = list(values)

    def check(self, value):
        if value not in self.values:
            raise TypeError('Invalid value: {}'.format(value))

    def coerce(self, value):
        try:
            self.check(value)
        except TypeError as e:
            raise TypeError('Cannot coerce {}: {}'.format(value, message(e)))
        return value

    def validate(self, value):
        self.check(value)

#-------------------------------------------------------------------------------
# MultiType

class MultiType(Type):
    '''A tuple of type specifiers, any of which may be valid.
    '''
    __slots__ = ('types', 'typestr', 'typelist', 'typemap', 'is_typelist')

    def __init__(self, types):
        self.is_typelist = False
        if all(isinstance(typ, type) for typ in types):
            self.is_typelist = True
            self.typelist = types

        self.typestr = ', '.join(map(strf, types))
        self.types = [Type.dispatch(typ) for typ in types]
        self.typemap = dict(zip(types, self.types))

    def check(self, value):
        if self.is_typelist:
            if isinstance(value, self.typelist):
                return self.typemap[nearest_base(type(value), self.typelist)]

        else:
            for typ in self.types:
                try:
                    typ.check(value)
                    return typ
                except TypeError:
                    pass

        raise TypeError("Value '{}' is not any valid type: {}"
                        .format(value, self.typestr))

    def coerce(self, value):
        for typ in self.types:
            try:
                return typ.coerce(value)
            except TypeError:
                pass

        raise TypeError('Cannot coerce {} to any valid type: {}'
                        .format(value, self.typestr))

    def validate(self, value):
        typ = self.check(value)
        typ.validate(value)

#-------------------------------------------------------------------------------
# TypeExtension

class TypeExtension(Type):
    '''For extending the type system.
    '''

    def validate(self, value):
        self.check(value)

#-------------------------------------------------------------------------------
# __all__

__all__ = ('Type', 'AnyType', 'TypeType', 'ValuesType', 'MultiType',
           'TypeExtension')

#-------------------------------------------------------------------------------
<|endoftext|>