Commit 211a89f0 authored by Stefan Behnel's avatar Stefan Behnel

merged trunk changes

parents 138f21b3 a927b5a7
syntax: glob
*.pyc
*.swp
Cython/Compiler/Lexicon.pickle
BUILD/
.coverage
*~
*.orig
*.rej
...@@ -3,15 +3,17 @@ ...@@ -3,15 +3,17 @@
import os import os
import re import re
import time import time
import codecs
from StringIO import StringIO from StringIO import StringIO
import Version import Version
from Code import CCodeWriter from Code import CCodeWriter
from Cython import Utils
# need one-characters subsitutions (for now) so offsets aren't off # need one-characters subsitutions (for now) so offsets aren't off
special_chars = [('<', '\xF0', '&lt;'), special_chars = [(u'<', u'\xF0', u'&lt;'),
('>', '\xF1', '&gt;'), (u'>', u'\xF1', u'&gt;'),
('&', '\xF2', '&amp;')] (u'&', u'\xF2', u'&amp;')]
class AnnotationCCodeWriter(CCodeWriter): class AnnotationCCodeWriter(CCodeWriter):
...@@ -46,9 +48,9 @@ class AnnotationCCodeWriter(CCodeWriter): ...@@ -46,9 +48,9 @@ class AnnotationCCodeWriter(CCodeWriter):
def annotate(self, pos, item): def annotate(self, pos, item):
self.annotations.append((pos, item)) self.annotations.append((pos, item))
def save_annotation(self, filename): def save_annotation(self, source_filename, target_filename):
self.mark_pos(None) self.mark_pos(None)
f = open(filename) f = Utils.open_source_file(source_filename)
lines = f.readlines() lines = f.readlines()
for k in range(len(lines)): for k in range(len(lines)):
line = lines[k] line = lines[k]
...@@ -58,12 +60,12 @@ class AnnotationCCodeWriter(CCodeWriter): ...@@ -58,12 +60,12 @@ class AnnotationCCodeWriter(CCodeWriter):
f.close() f.close()
all = [] all = []
for pos, item in self.annotations: for pos, item in self.annotations:
if pos[0] == filename: if pos[0] == source_filename:
start = item.start() start = item.start()
size, end = item.end() size, end = item.end()
if size: if size:
all.append((pos, start)) all.append((pos, start))
all.append(((filename, pos[1], pos[2]+size), end)) all.append(((source_filename, pos[1], pos[2]+size), end))
else: else:
all.append((pos, start+end)) all.append((pos, start+end))
...@@ -76,10 +78,12 @@ class AnnotationCCodeWriter(CCodeWriter): ...@@ -76,10 +78,12 @@ class AnnotationCCodeWriter(CCodeWriter):
line = lines[line_no] line = lines[line_no]
lines[line_no] = line[:col] + item + line[col:] lines[line_no] = line[:col] + item + line[col:]
f = open("%s.html" % filename, "w") html_filename = os.path.splitext(target_filename)[0] + ".html"
f.write('<html>\n') f = codecs.open(html_filename, "w", encoding="UTF-8")
f.write(""" f.write(u'<html>\n')
f.write(u"""
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css"> <style type="text/css">
body { font-family: courier; font-size: 12; } body { font-family: courier; font-size: 12; }
...@@ -112,16 +116,16 @@ function toggleDiv(id) { ...@@ -112,16 +116,16 @@ function toggleDiv(id) {
</script> </script>
</head> </head>
""") """)
f.write('<body>\n') f.write(u'<body>\n')
f.write('<p>Generated by Cython %s on %s\n' % (Version.version, time.asctime())) f.write(u'<p>Generated by Cython %s on %s\n' % (Version.version, time.asctime()))
c_file = os.path.basename(filename)[:-3] + 'c' c_file = Utils.encode_filename(os.path.basename(target_filename))
f.write('<p>Raw output: <a href="%s">%s</a>\n' % (c_file, c_file)) f.write(u'<p>Raw output: <a href="%s">%s</a>\n' % (c_file, c_file))
k = 0 k = 0
py_c_api = re.compile('(Py[A-Z][a-z]+_[A-Z][a-z][A-Za-z_]+)') py_c_api = re.compile(u'(Py[A-Z][a-z]+_[A-Z][a-z][A-Za-z_]+)')
pyx_api = re.compile('(__Pyx[A-Za-z_]+)\(') pyx_api = re.compile(u'(__Pyx[A-Za-z_]+)\(')
py_marco_api = re.compile('(Py[A-Za-z]*_[A-Z][A-Z_]+)') py_marco_api = re.compile(u'(Py[A-Za-z]*_[A-Z][A-Z_]+)')
error_goto = re.compile(r'((; *if .*)? \{__pyx_filename = .*goto __pyx_L\w+;\})') error_goto = re.compile(ur'((; *if .*)? \{__pyx_filename = .*goto __pyx_L\w+;\})')
for line in lines: for line in lines:
...@@ -131,33 +135,33 @@ function toggleDiv(id) { ...@@ -131,33 +135,33 @@ function toggleDiv(id) {
except KeyError: except KeyError:
code = '' code = ''
code, c_api_calls = py_c_api.subn(r"<span class='py_api'>\1</span>", code) code, c_api_calls = py_c_api.subn(ur"<span class='py_api'>\1</span>", code)
code, pyx_api_calls = pyx_api.subn(r"<span class='pyx_api'>\1</span>(", code) code, pyx_api_calls = pyx_api.subn(ur"<span class='pyx_api'>\1</span>(", code)
code, macro_api_calls = py_marco_api.subn(r"<span class='py_macro_api'>\1</span>", code) code, macro_api_calls = py_marco_api.subn(ur"<span class='py_macro_api'>\1</span>", code)
code, error_goto_calls = error_goto.subn(r"<span class='error_goto'>\1</span>", code) code, error_goto_calls = error_goto.subn(ur"<span class='error_goto'>\1</span>", code)
code = code.replace("<span class='error_goto'>;", ";<span class='error_goto'>") code = code.replace(u"<span class='error_goto'>;", u";<span class='error_goto'>")
color = "FFFF%02x" % int(255/(1+(5*c_api_calls+2*pyx_api_calls+macro_api_calls)/10.0)) color = u"FFFF%02x" % int(255/(1+(5*c_api_calls+2*pyx_api_calls+macro_api_calls)/10.0))
f.write("<pre class='line' style='background-color: #%s' onclick='toggleDiv(\"line%s\")'>" % (color, k)) f.write(u"<pre class='line' style='background-color: #%s' onclick='toggleDiv(\"line%s\")'>" % (color, k))
f.write(" %d: " % k) f.write(u" %d: " % k)
for c, cc, html in special_chars: for c, cc, html in special_chars:
line = line.replace(cc, html) line = line.replace(cc, html)
f.write(line.rstrip()) f.write(line.rstrip())
f.write('</pre>\n') f.write(u'</pre>\n')
f.write("<pre id='line%s' class='code' style='background-color: #%s'>%s</pre>" % (k, color, code)) f.write(u"<pre id='line%s' class='code' style='background-color: #%s'>%s</pre>" % (k, color, code))
f.write('</body></html>\n') f.write(u'</body></html>\n')
f.close() f.close()
# TODO: make this cleaner # TODO: make this cleaner
def escape(raw_string): def escape(raw_string):
raw_string = raw_string.replace("\'", r"&#146;") raw_string = raw_string.replace(u"\'", ur"&#146;")
raw_string = raw_string.replace('\"', r'&quot;') raw_string = raw_string.replace(u'\"', ur'&quot;')
raw_string = raw_string.replace('\n', r'<br>\n') raw_string = raw_string.replace(u'\n', ur'<br>\n')
raw_string = raw_string.replace('\t', r'\t') raw_string = raw_string.replace(u'\t', ur'\t')
return raw_string return raw_string
...@@ -170,7 +174,7 @@ class AnnotationItem: ...@@ -170,7 +174,7 @@ class AnnotationItem:
self.size = size self.size = size
def start(self): def start(self):
return "<span class='tag %s' title='%s'>%s" % (self.style, self.text, self.tag) return u"<span class='tag %s' title='%s'>%s" % (self.style, self.text, self.tag)
def end(self): def end(self):
return self.size, "</span>" return self.size, u"</span>"
...@@ -2741,7 +2741,7 @@ def unop_node(pos, operator, operand): ...@@ -2741,7 +2741,7 @@ def unop_node(pos, operator, operand):
# Construct unnop node of appropriate class for # Construct unnop node of appropriate class for
# given operator. # given operator.
if isinstance(operand, IntNode) and operator == '-': if isinstance(operand, IntNode) and operator == '-':
return IntNode(pos = operand.pos, value = -int(operand.value)) return IntNode(pos = operand.pos, value = str(-int(operand.value, 0)))
elif isinstance(operand, UnopNode) and operand.operator == operator: elif isinstance(operand, UnopNode) and operand.operator == operator:
warning(pos, "Python has no increment/decrement operator: %s%sx = %s(%sx) = x" % ((operator,)*4), 5) warning(pos, "Python has no increment/decrement operator: %s%sx = %s(%sx) = x" % ((operator,)*4), 5)
return unop_node_classes[operator](pos, return unop_node_classes[operator](pos,
...@@ -4128,7 +4128,7 @@ static void __Pyx_CppExn2PyErr() { ...@@ -4128,7 +4128,7 @@ static void __Pyx_CppExn2PyErr() {
append_utility_code = [ append_utility_code = [
""" """
static inline PyObject* __Pyx_PyObject_Append(PyObject* L, PyObject* x) { static INLINE PyObject* __Pyx_PyObject_Append(PyObject* L, PyObject* x) {
if (likely(PyList_CheckExact(L))) { if (likely(PyList_CheckExact(L))) {
if (PyList_Append(L, x) < 0) return NULL; if (PyList_Append(L, x) < 0) return NULL;
Py_INCREF(Py_None); Py_INCREF(Py_None);
......
...@@ -138,16 +138,7 @@ class Context: ...@@ -138,16 +138,7 @@ class Context:
return scope return scope
def parse(self, source_filename, type_names, pxd, full_module_name): def parse(self, source_filename, type_names, pxd, full_module_name):
try: name = Utils.encode_filename(source_filename)
name = source_filename
if not isinstance(source_filename, unicode):
filename_encoding = sys.getfilesystemencoding()
if filename_encoding is None:
filename_encoding = sys.getdefaultencoding()
name = source_filename.decode(filename_encoding)
except UnicodeDecodeError:
pass
# Parse the given source file and return a parse tree. # Parse the given source file and return a parse tree.
try: try:
f = Utils.open_source_file(source_filename, "rU") f = Utils.open_source_file(source_filename, "rU")
...@@ -183,6 +174,7 @@ class Context: ...@@ -183,6 +174,7 @@ class Context:
full_module_name = re.sub(r'[^\w.]', '_', full_module_name) full_module_name = re.sub(r'[^\w.]', '_', full_module_name)
source = os.path.join(cwd, source) source = os.path.join(cwd, source)
result.main_source_file = source
if options.use_listing_file: if options.use_listing_file:
result.listing_file = replace_suffix(source, ".lis") result.listing_file = replace_suffix(source, ".lis")
...@@ -295,6 +287,7 @@ class CompilationResult: ...@@ -295,6 +287,7 @@ class CompilationResult:
self.listing_file = None self.listing_file = None
self.object_file = None self.object_file = None
self.extension_file = None self.extension_file = None
self.main_source_file = None
def compile(source, options = None, c_compile = 0, c_link = 0, def compile(source, options = None, c_compile = 0, c_link = 0,
...@@ -360,6 +353,7 @@ default_options = dict( ...@@ -360,6 +353,7 @@ default_options = dict(
obj_only = 1, obj_only = 1,
cplus = 0, cplus = 0,
output_file = None, output_file = None,
annotate = False,
generate_pxi = 0, generate_pxi = 0,
transforms = Transform.TransformSet(), transforms = Transform.TransformSet(),
working_path = "") working_path = "")
......
...@@ -209,7 +209,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -209,7 +209,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
def generate_c_code(self, env, options, result): def generate_c_code(self, env, options, result):
modules = self.referenced_modules modules = self.referenced_modules
if Options.annotate: if Options.annotate or options.annotate:
code = Annotate.AnnotationCCodeWriter(StringIO()) code = Annotate.AnnotationCCodeWriter(StringIO())
else: else:
code = Code.CCodeWriter(StringIO()) code = Code.CCodeWriter(StringIO())
...@@ -238,16 +238,15 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -238,16 +238,15 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
self.generate_declarations_for_modules(env, modules, code.h) self.generate_declarations_for_modules(env, modules, code.h)
f = open_new_file(result.c_file) f = open_new_file(result.c_file)
f.write(code.h.f.getvalue()) f.write(code.h.f.getvalue())
f.write("\n") f.write("\n")
f.write(code.f.getvalue()) f.write(code.f.getvalue())
f.close() f.close()
result.c_file_generated = 1 result.c_file_generated = 1
if Options.annotate: if Options.annotate or options.annotate:
self.annotate(code) self.annotate(code)
code.save_annotation(result.c_file[:-1] + "pyx") # change? code.save_annotation(result.main_source_file, result.c_file)
def find_referenced_modules(self, env, module_list, modules_seen): def find_referenced_modules(self, env, module_list, modules_seen):
if env not in modules_seen: if env not in modules_seen:
...@@ -709,7 +708,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -709,7 +708,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
self.generate_ass_subscript_function(scope, code) self.generate_ass_subscript_function(scope, code)
if scope.defines_any(["__setslice__", "__delslice__"]): if scope.defines_any(["__setslice__", "__delslice__"]):
self.generate_ass_slice_function(scope, code) self.generate_ass_slice_function(scope, code)
if scope.defines_any(["__getattr__"]): if scope.defines_any(["__getattr__","__getattribute__"]):
self.generate_getattro_function(scope, code) self.generate_getattro_function(scope, code)
if scope.defines_any(["__setattr__", "__delattr__"]): if scope.defines_any(["__setattr__", "__delattr__"]):
self.generate_setattro_function(scope, code) self.generate_setattro_function(scope, code)
...@@ -1073,23 +1072,43 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -1073,23 +1072,43 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
"}") "}")
def generate_getattro_function(self, scope, code): def generate_getattro_function(self, scope, code):
# First try to get the attribute using PyObject_GenericGetAttr. # First try to get the attribute using __getattribute__, if defined, or
# If that raises an AttributeError, call the user's __getattr__ # PyObject_GenericGetAttr.
# method. #
entry = scope.lookup_here("__getattr__") # If that raises an AttributeError, call the __getattr__ if defined.
#
# In both cases, defined can be in this class, or any base class.
def lookup_here_or_base(n,type=None):
# Recursive lookup
if type is None:
type = scope.parent_type
r = type.scope.lookup_here(n)
if r is None and \
type.base_type is not None:
return lookup_here_or_base(n,type.base_type)
else:
return r
getattr_entry = lookup_here_or_base("__getattr__")
getattribute_entry = lookup_here_or_base("__getattribute__")
code.putln("") code.putln("")
code.putln( code.putln(
"static PyObject *%s(PyObject *o, PyObject *n) {" "static PyObject *%s(PyObject *o, PyObject *n) {"
% scope.mangle_internal("tp_getattro")) % scope.mangle_internal("tp_getattro"))
if getattribute_entry is not None:
code.putln(
"PyObject *v = %s(o, n);" %
getattribute_entry.func_cname)
else:
code.putln( code.putln(
"PyObject *v = PyObject_GenericGetAttr(o, n);") "PyObject *v = PyObject_GenericGetAttr(o, n);")
if getattr_entry is not None:
code.putln( code.putln(
"if (!v && PyErr_ExceptionMatches(PyExc_AttributeError)) {") "if (!v && PyErr_ExceptionMatches(PyExc_AttributeError)) {")
code.putln( code.putln(
"PyErr_Clear();") "PyErr_Clear();")
code.putln( code.putln(
"v = %s(o, n);" % "v = %s(o, n);" %
entry.func_cname) getattr_entry.func_cname)
code.putln( code.putln(
"}") "}")
code.putln( code.putln(
......
...@@ -617,7 +617,7 @@ slot_table = ( ...@@ -617,7 +617,7 @@ slot_table = (
MethodSlot(callfunc, "tp_call", "__call__"), MethodSlot(callfunc, "tp_call", "__call__"),
MethodSlot(reprfunc, "tp_str", "__str__"), MethodSlot(reprfunc, "tp_str", "__str__"),
SyntheticSlot("tp_getattro", ["__getattr__"], "0"), #"PyObject_GenericGetAttr"), SyntheticSlot("tp_getattro", ["__getattr__","__getattribute__"], "0"), #"PyObject_GenericGetAttr"),
SyntheticSlot("tp_setattro", ["__setattr__", "__delattr__"], "0"), #"PyObject_GenericSetAttr"), SyntheticSlot("tp_setattro", ["__setattr__", "__delattr__"], "0"), #"PyObject_GenericSetAttr"),
SuiteSlot(PyBufferProcs, "PyBufferProcs", "tp_as_buffer"), SuiteSlot(PyBufferProcs, "PyBufferProcs", "tp_as_buffer"),
......
...@@ -28,13 +28,25 @@ def castrate_file(path, st): ...@@ -28,13 +28,25 @@ def castrate_file(path, st):
f.seek(0, 0) f.seek(0, 0)
f.truncate() f.truncate()
f.write( f.write(
"#error Do not use this file, it is the result of a failed Pyrex compilation.\n") "#error Do not use this file, it is the result of a failed Cython compilation.\n")
f.close() f.close()
if st: if st:
os.utime(path, (st.st_atime, st.st_mtime)) os.utime(path, (st.st_atime, st.st_mtime))
# support for source file encoding detection and unicode decoding # support for source file encoding detection and unicode decoding
def encode_filename(filename):
if isinstance(filename, unicode):
return filename
try:
filename_encoding = sys.getfilesystemencoding()
if filename_encoding is None:
filename_encoding = sys.getdefaultencoding()
filename = filename.decode(filename_encoding)
except UnicodeDecodeError:
pass
return filename
_match_file_encoding = re.compile(u"coding[:=]\s*([-\w.]+)").search _match_file_encoding = re.compile(u"coding[:=]\s*([-\w.]+)").search
def detect_file_encoding(source_filename): def detect_file_encoding(source_filename):
......
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
import os, sys, re, shutil, unittest, doctest import os, sys, re, shutil, unittest, doctest
from Cython.Compiler.Version import version
from Cython.Compiler.Main import \ from Cython.Compiler.Main import \
CompilationOptions, \ CompilationOptions, \
default_options as pyrex_default_options, \ default_options as pyrex_default_options, \
...@@ -36,14 +37,17 @@ class ErrorWriter(object): ...@@ -36,14 +37,17 @@ class ErrorWriter(object):
return errors return errors
class TestBuilder(object): class TestBuilder(object):
def __init__(self, rootdir, workdir, selectors): def __init__(self, rootdir, workdir, selectors, annotate):
self.rootdir = rootdir self.rootdir = rootdir
self.workdir = workdir self.workdir = workdir
self.selectors = selectors self.selectors = selectors
self.annotate = annotate
def build_suite(self): def build_suite(self):
suite = unittest.TestSuite() suite = unittest.TestSuite()
for filename in os.listdir(self.rootdir): filenames = os.listdir(self.rootdir)
filenames.sort()
for filename in filenames:
path = os.path.join(self.rootdir, filename) path = os.path.join(self.rootdir, filename)
if os.path.isdir(path) and filename in TEST_DIRS: if os.path.isdir(path) and filename in TEST_DIRS:
suite.addTest( suite.addTest(
...@@ -53,7 +57,9 @@ class TestBuilder(object): ...@@ -53,7 +57,9 @@ class TestBuilder(object):
def handle_directory(self, path, context): def handle_directory(self, path, context):
expect_errors = (context == 'errors') expect_errors = (context == 'errors')
suite = unittest.TestSuite() suite = unittest.TestSuite()
for filename in os.listdir(path): filenames = os.listdir(path)
filenames.sort()
for filename in filenames:
if not filename.endswith(".pyx"): if not filename.endswith(".pyx"):
continue continue
module = filename[:-4] module = filename[:-4]
...@@ -62,32 +68,46 @@ class TestBuilder(object): ...@@ -62,32 +68,46 @@ class TestBuilder(object):
if match(fqmodule) ]: if match(fqmodule) ]:
continue continue
if context in TEST_RUN_DIRS: if context in TEST_RUN_DIRS:
test = CythonRunTestCase(path, self.workdir, module) test = CythonRunTestCase(
path, self.workdir, module, self.annotate)
else: else:
test = CythonCompileTestCase( test = CythonCompileTestCase(
path, self.workdir, module, expect_errors) path, self.workdir, module, expect_errors, self.annotate)
suite.addTest(test) suite.addTest(test)
return suite return suite
class CythonCompileTestCase(unittest.TestCase): class CythonCompileTestCase(unittest.TestCase):
def __init__(self, directory, workdir, module, expect_errors=False): def __init__(self, directory, workdir, module,
expect_errors=False, annotate=False):
self.directory = directory self.directory = directory
self.workdir = workdir self.workdir = workdir
self.module = module self.module = module
self.expect_errors = expect_errors self.expect_errors = expect_errors
self.annotate = annotate
unittest.TestCase.__init__(self) unittest.TestCase.__init__(self)
def shortDescription(self): def shortDescription(self):
return "compiling " + self.module return "compiling " + self.module
def setUp(self): def tearDown(self):
if os.path.exists(self.workdir): if os.path.exists(self.workdir):
shutil.rmtree(self.workdir, ignore_errors=True) for rmfile in os.listdir(self.workdir):
if self.annotate and rmfile.endswith(".html"):
continue
try:
rmfile = os.path.join(self.workdir, rmfile)
if os.path.isdir(rmfile):
shutil.rmtree(rmfile, ignore_errors=True)
else:
os.remove(rmfile)
except IOError:
pass
else:
os.makedirs(self.workdir) os.makedirs(self.workdir)
def runTest(self): def runTest(self):
self.compile(self.directory, self.module, self.workdir, self.compile(self.directory, self.module, self.workdir,
self.directory, self.expect_errors) self.directory, self.expect_errors, self.annotate)
def split_source_and_output(self, directory, module, workdir): def split_source_and_output(self, directory, module, workdir):
source_and_output = open(os.path.join(directory, module + '.pyx'), 'rU') source_and_output = open(os.path.join(directory, module + '.pyx'), 'rU')
...@@ -106,7 +126,7 @@ class CythonCompileTestCase(unittest.TestCase): ...@@ -106,7 +126,7 @@ class CythonCompileTestCase(unittest.TestCase):
else: else:
return geterrors() return geterrors()
def run_cython(self, directory, module, targetdir, incdir): def run_cython(self, directory, module, targetdir, incdir, annotate):
include_dirs = INCLUDE_DIRS[:] include_dirs = INCLUDE_DIRS[:]
if incdir: if incdir:
include_dirs.append(incdir) include_dirs.append(incdir)
...@@ -116,6 +136,7 @@ class CythonCompileTestCase(unittest.TestCase): ...@@ -116,6 +136,7 @@ class CythonCompileTestCase(unittest.TestCase):
pyrex_default_options, pyrex_default_options,
include_path = include_dirs, include_path = include_dirs,
output_file = target, output_file = target,
annotate = annotate,
use_listing_file = False, cplus = False, generate_pxi = False) use_listing_file = False, cplus = False, generate_pxi = False)
cython_compile(source, options=options, cython_compile(source, options=options,
full_module_name=module) full_module_name=module)
...@@ -142,7 +163,8 @@ class CythonCompileTestCase(unittest.TestCase): ...@@ -142,7 +163,8 @@ class CythonCompileTestCase(unittest.TestCase):
finally: finally:
os.chdir(cwd) os.chdir(cwd)
def compile(self, directory, module, workdir, incdir, expect_errors): def compile(self, directory, module, workdir, incdir,
expect_errors, annotate):
expected_errors = errors = () expected_errors = errors = ()
if expect_errors: if expect_errors:
expected_errors = self.split_source_and_output( expected_errors = self.split_source_and_output(
...@@ -152,7 +174,7 @@ class CythonCompileTestCase(unittest.TestCase): ...@@ -152,7 +174,7 @@ class CythonCompileTestCase(unittest.TestCase):
old_stderr = sys.stderr old_stderr = sys.stderr
try: try:
sys.stderr = ErrorWriter() sys.stderr = ErrorWriter()
self.run_cython(directory, module, workdir, incdir) self.run_cython(directory, module, workdir, incdir, annotate)
errors = sys.stderr.geterrors() errors = sys.stderr.geterrors()
finally: finally:
sys.stderr = old_stderr sys.stderr = old_stderr
...@@ -183,17 +205,26 @@ class CythonRunTestCase(CythonCompileTestCase): ...@@ -183,17 +205,26 @@ class CythonRunTestCase(CythonCompileTestCase):
result.startTest(self) result.startTest(self)
result.addError(self, sys.exc_info()) result.addError(self, sys.exc_info())
result.stopTest(self) result.stopTest(self)
try:
self.tearDown()
except Exception:
pass
if __name__ == '__main__': if __name__ == '__main__':
# RUN ALL TESTS! # RUN ALL TESTS!
ROOTDIR = os.path.join(os.getcwd(), os.path.dirname(sys.argv[0]), 'tests') ROOTDIR = os.path.join(os.getcwd(), os.path.dirname(sys.argv[0]), 'tests')
WORKDIR = os.path.join(os.getcwd(), 'BUILD') WORKDIR = os.path.join(os.getcwd(), 'BUILD')
if not os.path.exists(WORKDIR): if os.path.exists(WORKDIR):
shutil.rmtree(WORKDIR, ignore_errors=True)
os.makedirs(WORKDIR) os.makedirs(WORKDIR)
if not sys.path or sys.path[0] != WORKDIR: if not sys.path or sys.path[0] != WORKDIR:
sys.path.insert(0, WORKDIR) sys.path.insert(0, WORKDIR)
print "Running tests against Cython %s" % version
print "Python", sys.version
print
try: try:
sys.argv.remove("-C") sys.argv.remove("-C")
except ValueError: except ValueError:
...@@ -202,12 +233,19 @@ if __name__ == '__main__': ...@@ -202,12 +233,19 @@ if __name__ == '__main__':
import coverage import coverage
coverage.erase() coverage.erase()
try:
sys.argv.remove("-a")
except ValueError:
annotate_source = False
else:
annotate_source = True
import re import re
selectors = [ re.compile(r, re.I).search for r in sys.argv[1:] ] selectors = [ re.compile(r, re.I).search for r in sys.argv[1:] ]
if not selectors: if not selectors:
selectors = [ lambda x:True ] selectors = [ lambda x:True ]
tests = TestBuilder(ROOTDIR, WORKDIR, selectors) tests = TestBuilder(ROOTDIR, WORKDIR, selectors, annotate_source)
test_suite = tests.build_suite() test_suite = tests.build_suite()
if coverage is not None: if coverage is not None:
......
__doc__ = """
__getattribute__ and __getattr__ special methods for a single class.
>>> a = just_getattribute()
>>> a.bar
'bar'
>>> a.invalid
Traceback (most recent call last):
AttributeError
>>> a = just_getattr()
>>> a.foo
10
>>> a.bar
'bar'
>>> a.invalid
Traceback (most recent call last):
AttributeError
>>> a = both()
>>> a.foo
10
>>> a.bar
'bar'
>>> a.invalid
Traceback (most recent call last):
AttributeError
"""
cdef class just_getattribute:
def __getattribute__(self,n):
if n == 'bar':
return n
else:
raise AttributeError
cdef class just_getattr:
cdef readonly int foo
def __init__(self):
self.foo = 10
def __getattr__(self,n):
if n == 'bar':
return n
else:
raise AttributeError
cdef class both:
cdef readonly int foo
def __init__(self):
self.foo = 10
def __getattribute__(self,n):
if n == 'foo':
return self.foo
else:
raise AttributeError
def __getattr__(self,n):
if n == 'bar':
return n
else:
raise AttributeError
__doc__ = """
__getattribute__ and __getattr__ special methods and subclasses.
getattr does not override members.
>>> a = getattr_boring()
>>> a.boring_member
10
>>> a.resolved_by
'getattr_boring'
getattribute does.
>>> a = getattribute_boring()
>>> a.boring_member
Traceback (most recent call last):
AttributeError
>>> a.resolved_by
'getattribute_boring'
Is inherited.
>>> a = boring_boring_getattribute()
>>> a.boring_getattribute_member
Traceback (most recent call last):
AttributeError
>>> a.boring_boring_getattribute_member
Traceback (most recent call last):
AttributeError
>>> a.resolved_by
'_getattribute'
__getattribute__ is always tried first, then __getattr__, regardless of where
in the inheritance hiarchy they came from.
>>> a = getattribute_boring_boring_getattr()
>>> a.foo
Traceback (most recent call last):
AttributeError
>>> a.resolved_by
'getattribute_boring_boring_getattr'
>>> a.getattribute_boring_boring_getattr
True
>>> a._getattr
True
>>> a = getattr_boring_boring_getattribute()
>>> a.foo
Traceback (most recent call last):
AttributeError
>>> a.resolved_by
'_getattribute'
>>> a.getattr_boring_boring_getattribute
True
>>> a._getattribute
True
"""
cdef class boring:
cdef readonly int boring_member
def __init__(self):
self.boring_member = 10
cdef class getattr_boring(boring):
def __getattr__(self,n):
if n == 'resolved_by':
return 'getattr_boring'
elif n == 'getattr_boring':
return True
else:
raise AttributeError
cdef class getattribute_boring(boring):
def __getattribute__(self,n):
if n == 'resolved_by':
return 'getattribute_boring'
elif n == 'getattribute_boring':
return True
else:
raise AttributeError
cdef class _getattr:
def __getattr__(self,n):
if n == 'resolved_by':
return '_getattr'
elif n == '_getattr':
return True
else:
raise AttributeError
cdef class _getattribute(boring):
def __getattribute__(self,n):
if n == 'resolved_by':
return '_getattribute'
elif n == '_getattribute':
return True
else:
raise AttributeError
cdef class boring_getattribute(_getattribute):
cdef readonly int boring_getattribute_member
cdef class boring_boring_getattribute(boring_getattribute):
cdef readonly int boring_boring_getattribute_member
cdef class boring_getattr(_getattr):
cdef readonly int boring_getattr_member
cdef class boring_boring_getattr(boring_getattr):
cdef readonly int boring_boring_getattr_member
cdef class getattribute_boring_boring_getattr(boring_boring_getattr):
def __getattribute__(self,n):
if n == 'resolved_by':
return 'getattribute_boring_boring_getattr'
elif n == 'getattribute_boring_boring_getattr':
return True
else:
raise AttributeError
cdef class getattr_boring_boring_getattribute(boring_boring_getattribute):
def __getattr__(self,n):
if n == 'resolved_by':
return 'getattr_boring_boring_getattribute'
elif n == 'getattr_boring_boring_getattribute':
return True
else:
raise AttributeError
__doc__ = """ __doc__ = """
>>> c() >>> c()
120 120
>>> i0() == -1
True
>>> i1() == 42 >>> i1() == 42
True True
>>> i2() == 0x42 >>> i2() == 0x42
True True
>>> i3() == 042 >>> i3() == 042
True True
>>> i4() == -0x42
True
>>> l() >>> l()
666 666
>>> f() >>> f()
...@@ -27,9 +31,11 @@ DEF TUPLE = (1, 2, "buckle my shoe") ...@@ -27,9 +31,11 @@ DEF TUPLE = (1, 2, "buckle my shoe")
DEF TRUE_FALSE = (True, False) DEF TRUE_FALSE = (True, False)
DEF CHAR = c'x' DEF CHAR = c'x'
DEF INT0 = -1
DEF INT1 = 42 DEF INT1 = 42
DEF INT2 = 0x42 DEF INT2 = 0x42
DEF INT3 = 042 DEF INT3 = 042
DEF INT4 = -0x42
DEF LONG = 666L DEF LONG = 666L
DEF FLOAT = 12.5 DEF FLOAT = 12.5
DEF STR = "spam" DEF STR = "spam"
...@@ -43,6 +49,11 @@ def c(): ...@@ -43,6 +49,11 @@ def c():
c = CHAR c = CHAR
return c return c
def i0():
cdef int i
i = INT0
return i
def i1(): def i1():
cdef int i cdef int i
i = INT1 i = INT1
...@@ -58,6 +69,11 @@ def i3(): ...@@ -58,6 +69,11 @@ def i3():
i = INT3 i = INT3
return i return i
def i4():
cdef int i
i = INT4
return i
def l(): def l():
cdef long l cdef long l
l = LONG l = LONG
......
__doc__ = """ __doc__ = """
>>> test(Exception('hi')) >>> test(Exception('hi'))
Raising: Exception('hi',) Raising: Exception('hi',)
Caught: <type 'exceptions.Exception'> Exception('hi',) Caught: Exception('hi',)
""" """
import sys import sys, types
def test(obj): def test(obj):
print "Raising:", repr(obj) print "Raising: %s%r" % (obj.__class__.__name__, obj.args)
try: try:
raise obj raise obj
except: except:
info = sys.exc_info() info = sys.exc_info()
print "Caught: %r %r" % (info[0], info[1]) if sys.version_info >= (2,5):
assert isinstance(info[0], type)
else:
assert isinstance(info[0], types.ClassType)
print "Caught: %s%r" % (info[1].__class__.__name__, info[1].args)
...@@ -10,10 +10,10 @@ __doc__ = """ ...@@ -10,10 +10,10 @@ __doc__ = """
>>> type(sys.maxint * 2 + 1) is long >>> type(sys.maxint * 2 + 1) is long
True True
>>> test(sys.maxint + 1) >>> test(sys.maxint + 1) == sys.maxint + 1
2147483648L True
>>> test(sys.maxint * 2 + 1) >>> test(sys.maxint * 2 + 1) == sys.maxint * 2 + 1
4294967295L True
>>> test(256 ** unsigned_long_size() - 1) > 0 >>> test(256 ** unsigned_long_size() - 1) > 0
True True
......
...@@ -5,9 +5,9 @@ __doc__ = """ ...@@ -5,9 +5,9 @@ __doc__ = """
3 3
>>> test( (1,2,3) ) >>> test( (1,2,3) )
3 3
>>> testnonsense() >>> testnonsense() # doctest: +ELLIPSIS
Traceback (most recent call last): Traceback (most recent call last):
TypeError: 'int' object is not iterable TypeError: ...
""" """
def test1(t): def test1(t):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment