Commit 28a969c2 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge pull request #913 from kmod/sqlalchemy

Get more of the sqlalchemy tests working
parents 4f250790 83379f19
...@@ -600,6 +600,14 @@ public: ...@@ -600,6 +600,14 @@ public:
this->insert(I, E); this->insert(I, E);
} }
// Pyston addition:
// Frees all dynamically-allocated memory, but leaves the DenseMap in a valid state.
void freeAllMemory() {
this->destroyAll();
operator delete(Buckets);
init(0);
}
~DenseMap() { ~DenseMap() {
this->destroyAll(); this->destroyAll();
operator delete(Buckets); operator delete(Buckets);
......
...@@ -81,6 +81,12 @@ public: ...@@ -81,6 +81,12 @@ public:
TheMap.clear(); TheMap.clear();
} }
// Pyston addition:
// Frees all dynamically-allocated memory, but leaves the DenseSet in a valid state.
void freeAllMemory() {
TheMap.freeAllMemory();
}
/// Return 1 if the specified key is in the set, 0 otherwise. /// Return 1 if the specified key is in the set, 0 otherwise.
size_type count(const ValueT &V) const { size_type count(const ValueT &V) const {
return TheMap.count(V); return TheMap.count(V);
......
...@@ -161,6 +161,7 @@ public: ...@@ -161,6 +161,7 @@ public:
PyThread_release_lock(self->lock_lock); PyThread_release_lock(self->lock_lock);
PyThread_free_lock(self->lock_lock); PyThread_free_lock(self->lock_lock);
self->lock_lock = NULL;
} }
} }
......
...@@ -1055,13 +1055,15 @@ static PyObject* instance_index(PyObject* self) noexcept { ...@@ -1055,13 +1055,15 @@ static PyObject* instance_index(PyObject* self) noexcept {
return res; return res;
} }
static void instance_dealloc(Box* _inst) { static void instance_dealloc(Box* _inst) noexcept {
RELEASE_ASSERT(_inst->cls == instance_cls, ""); RELEASE_ASSERT(_inst->cls == instance_cls, "");
BoxedInstance* inst = static_cast<BoxedInstance*>(_inst); BoxedInstance* inst = static_cast<BoxedInstance*>(_inst);
// Note that trying to call __del__ as a finalizer does not fallback to // Note that trying to call __del__ as a finalizer does not fallback to
// __getattr__ unlike other attributes (like __index__). This is CPython's behavior. // __getattr__ unlike other attributes (like __index__). This is CPython's behavior.
static BoxedString* del_str = internStringImmortal("__del__"); static BoxedString* del_str = internStringImmortal("__del__");
// TODO: any exceptions here should get caught + printed, instead of causing a std::terminate:
Box* func = instanceGetattributeSimple(inst, del_str); Box* func = instanceGetattributeSimple(inst, del_str);
if (func) if (func)
runtimeCall(func, ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL); runtimeCall(func, ArgPassSpec(0), NULL, NULL, NULL, NULL, NULL);
......
...@@ -771,7 +771,7 @@ static Box* dict_repr(PyObject* self) noexcept { ...@@ -771,7 +771,7 @@ static Box* dict_repr(PyObject* self) noexcept {
void BoxedDict::dealloc(Box* b) noexcept { void BoxedDict::dealloc(Box* b) noexcept {
assert(PyDict_Check(b)); assert(PyDict_Check(b));
static_cast<BoxedDict*>(b)->d.~DictMap(); static_cast<BoxedDict*>(b)->d.freeAllMemory();
} }
void setupDict() { void setupDict() {
......
...@@ -2479,7 +2479,7 @@ extern "C" bool nonzero(Box* obj) { ...@@ -2479,7 +2479,7 @@ extern "C" bool nonzero(Box* obj) {
|| obj->cls == instancemethod_cls || obj->cls == module_cls || obj->cls == capifunc_cls || obj->cls == instancemethod_cls || obj->cls == module_cls || obj->cls == capifunc_cls
|| obj->cls == builtin_function_or_method_cls || obj->cls == method_cls || obj->cls == frame_cls || obj->cls == builtin_function_or_method_cls || obj->cls == method_cls || obj->cls == frame_cls
|| obj->cls == generator_cls || obj->cls == capi_getset_cls || obj->cls == pyston_getset_cls || obj->cls == generator_cls || obj->cls == capi_getset_cls || obj->cls == pyston_getset_cls
|| obj->cls == wrapperdescr_cls, || obj->cls == wrapperdescr_cls || obj->cls == wrapperobject_cls,
"%s.__nonzero__", getTypeName(obj)); // TODO "%s.__nonzero__", getTypeName(obj)); // TODO
if (rewriter.get()) { if (rewriter.get()) {
...@@ -2817,7 +2817,8 @@ Box* callattrInternal(Box* obj, BoxedString* attr, LookupScope scope, CallRewrit ...@@ -2817,7 +2817,8 @@ Box* callattrInternal(Box* obj, BoxedString* attr, LookupScope scope, CallRewrit
if (rewrite_args) { if (rewrite_args) {
GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, rewrite_args->obj, Location::any()); GetattrRewriteArgs grewrite_args(rewrite_args->rewriter, rewrite_args->obj, Location::any());
val = getattrInternalEx<S>(obj, attr, &grewrite_args, scope == CLASS_ONLY, true, &bind_obj, &r_bind_obj); val = getattrInternalEx<S>(obj, attr, &grewrite_args, scope == CLASS_ONLY, true, &bind_obj, &r_bind_obj);
if (!grewrite_args.out_success) { // TODO: maybe callattrs should have return conventions as well.
if (!grewrite_args.out_success || grewrite_args.out_return_convention == GetattrRewriteArgs::NOEXC_POSSIBLE) {
rewrite_args = NULL; rewrite_args = NULL;
} else if (val) { } else if (val) {
r_val = grewrite_args.out_rtn; r_val = grewrite_args.out_rtn;
...@@ -2859,6 +2860,10 @@ Box* callattrInternal(Box* obj, BoxedString* attr, LookupScope scope, CallRewrit ...@@ -2859,6 +2860,10 @@ Box* callattrInternal(Box* obj, BoxedString* attr, LookupScope scope, CallRewrit
class Helper { class Helper {
public: public:
static Box* call(Box* val, ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3, void** extra_args) { static Box* call(Box* val, ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3, void** extra_args) {
if (!val) {
assert(S == CAPI);
return NULL;
}
Box** args = (Box**)extra_args[0]; Box** args = (Box**)extra_args[0];
const std::vector<BoxedString*>* keyword_names = (const std::vector<BoxedString*>*)extra_args[1]; const std::vector<BoxedString*>* keyword_names = (const std::vector<BoxedString*>*)extra_args[1];
return runtimeCallInternal<S>(val, NULL, argspec, arg1, arg2, arg3, args, keyword_names); return runtimeCallInternal<S>(val, NULL, argspec, arg1, arg2, arg3, args, keyword_names);
......
...@@ -641,7 +641,7 @@ extern "C" PyObject* PyFrozenSet_New(PyObject* iterable) noexcept { ...@@ -641,7 +641,7 @@ extern "C" PyObject* PyFrozenSet_New(PyObject* iterable) noexcept {
void BoxedSet::dealloc(Box* b) noexcept { void BoxedSet::dealloc(Box* b) noexcept {
assert(PyAnySet_Check(b)); assert(PyAnySet_Check(b));
static_cast<BoxedSet*>(b)->s.~Set(); static_cast<BoxedSet*>(b)->s.freeAllMemory();
} }
using namespace pyston::set; using namespace pyston::set;
......
...@@ -1770,8 +1770,9 @@ extern "C" Box* sliceNew(Box* cls, Box* start, Box* stop, Box** args) { ...@@ -1770,8 +1770,9 @@ extern "C" Box* sliceNew(Box* cls, Box* start, Box* stop, Box** args) {
} }
static Box* instancemethodCall(BoxedInstanceMethod* self, Box* args, Box* kwargs) { static Box* instancemethodCall(BoxedInstanceMethod* self, Box* args, Box* kwargs) {
RELEASE_ASSERT(self->cls == instancemethod_cls, ""); // Not the most effficient, but it works:
Py_FatalError("unimplemented"); return runtimeCallInternal<CXX>(self, NULL, ArgPassSpec(0, 0, true, true), args, kwargs, NULL, NULL, NULL);
// TODO add a tpp_call
} }
Box* instancemethodGet(BoxedInstanceMethod* self, Box* obj, Box* type) { Box* instancemethodGet(BoxedInstanceMethod* self, Box* obj, Box* type) {
......
# run_args: -x import gc
import os import os
import sys import sys
import subprocess import subprocess
import traceback import traceback
ENV_NAME = "sqlalchemy_test_env_" + os.path.basename(sys.executable) ENV_NAME = os.path.abspath("sqlalchemy_test_env_" + os.path.basename(sys.executable))
if not os.path.exists(ENV_NAME) or os.stat(sys.executable).st_mtime > os.stat(ENV_NAME + "/bin/python").st_mtime: if not os.path.exists(ENV_NAME) or os.stat(sys.executable).st_mtime > os.stat(ENV_NAME + "/bin/python").st_mtime:
print "Creating virtualenv to install testing dependencies..." print "Creating virtualenv to install testing dependencies..."
...@@ -28,7 +27,7 @@ if not os.path.exists(ENV_NAME) or os.stat(sys.executable).st_mtime > os.stat(EN ...@@ -28,7 +27,7 @@ if not os.path.exists(ENV_NAME) or os.stat(sys.executable).st_mtime > os.stat(EN
# subprocess.check_call([os.path.abspath("sqlalchemy_test_env/bin/python"), "-c", "import py; print type(py); print py.builtin"]) # subprocess.check_call([os.path.abspath("sqlalchemy_test_env/bin/python"), "-c", "import py; print type(py); print py.builtin"])
SQLALCHEMY_DIR = os.path.dirname(__file__) + "/../lib/sqlalchemy" SQLALCHEMY_DIR = os.path.abspath(os.path.dirname(__file__) + "/../lib/sqlalchemy")
TEST_DIR = SQLALCHEMY_DIR + "/test" TEST_DIR = SQLALCHEMY_DIR + "/test"
python_exe = os.path.abspath(ENV_NAME + "/bin/python") python_exe = os.path.abspath(ENV_NAME + "/bin/python")
...@@ -37,29 +36,56 @@ sys.path.insert(0, SQLALCHEMY_DIR) ...@@ -37,29 +36,56 @@ sys.path.insert(0, SQLALCHEMY_DIR)
sys.path.append(ENV_NAME + "/site-packages") sys.path.append(ENV_NAME + "/site-packages")
sys.path.append(ENV_NAME + "/lib/python2.7/site-packages") sys.path.append(ENV_NAME + "/lib/python2.7/site-packages")
os.chdir(SQLALCHEMY_DIR)
# make sure this is importable: # make sure this is importable:
import mock import mock
# sqlalchemy has a bad implementation of is_cpython (in compat.py): it's "not pypy and not is jython".
# Monkey-patch in a properly-detected value (it uses this to gate some "requires a predictable gc" tests
# we fail):
import platform
import sqlalchemy.util.compat
sqlalchemy.util.compat.cpython = sqlalchemy.util.cpython = (platform.python_implementation() == "CPython")
import sqlalchemy.testing import sqlalchemy.testing
class Requirements(object): import sqlalchemy.testing.plugin.pytestplugin
def __getattr__(self, n): class Options(object):
def inner(f): pass
if n == "predictable_gc": options = Options()
def f2(*args, **kw): options.__dict__.update({'noassert': False, 'verbose': 1, 'color': 'auto', 'collectonly': False, 'pyargs': False, 'pastebin': None, 'genscript': None, 'include_tag': None, 'plugins': [], 'dbs': None, 'log_debug': None, 'markexpr': '', 'help': False, 'capture': 'fd', 'low_connections': False, 'requirements': None, 'reportchars': 'fxX', 'reversetop': False, 'assertmode': 'rewrite', 'backend_only': False, 'markers': False, 'strict': False, 'usepdb': False, 'inifilename': None, 'version': False, 'log_info': None, 'dropfirst': False, 'maxfail': 25, 'traceconfig': False, 'junitprefix': None, 'force_write_profiles': False, 'durations': None, 'db': None, 'confcutdir': None, 'doctestmodules': False, 'showfixtures': False, 'fulltrace': False, 'file_or_dir': ['/mnt/kmod/pyston/test/lib/sqlalchemy'], 'basetemp': None, 'report': None, 'ignore': None, 'exclude_tag': None, 'resultlog': None, 'doctestglob': 'test*.txt', 'dburi': None, 'exitfirst': False, 'showlocals': False, 'keyword': '', 'doctest_ignore_import_errors': False, 'write_profiles': False, 'runxfail': False, 'quiet': 0, 'cdecimal': False, 'xmlpath': None, 'tbstyle': 'native', 'debug': False, 'nomagic': False})
return class SkipTest(Exception):
return f2 pass
else: sqlalchemy.testing.plugin.plugin_base.set_skip_test(SkipTest)
return f sqlalchemy.testing.plugin.plugin_base.pre_begin(options)
inner.not_ = lambda: inner sqlalchemy.testing.plugin.plugin_base.read_config()
return inner sqlalchemy.testing.plugin.pytestplugin.pytest_sessionstart(None)
sqlalchemy.testing.config.requirements = sqlalchemy.testing.requires = Requirements()
import glob import glob
test_files = glob.glob(TEST_DIR + "/test*.py") + glob.glob(TEST_DIR + "/*/test*.py") test_files = glob.glob(TEST_DIR + "/test*.py") + glob.glob(TEST_DIR + "/*/test*.py")
# These are the ones that pass on CPython (ie that we've stubbed enough of their testing # These are the ones that pass on CPython (ie that we've stubbed enough of their testing
# infrastructure to run): # infrastructure to run):
MODULES_TO_TEST = ['test.engine.test_parseconnect', 'test.ext.test_compiler', 'test.dialect.test_pyodbc', 'test.dialect.test_sybase', 'test.dialect.test_mxodbc', 'test.sql.test_inspect', 'test.sql.test_operators', 'test.sql.test_ddlemit', 'test.sql.test_cte', 'test.base.test_dependency', 'test.base.test_except', 'test.base.test_inspect', 'test.base.test_events', 'test.orm.test_inspect', 'test.orm.test_descriptor'] MODULES_TO_TEST = [
'test.base.test_dependency',
'test.base.test_events',
'test.base.test_except',
'test.base.test_inspect',
'test.dialect.test_mxodbc',
'test.dialect.test_pyodbc',
'test.dialect.test_sybase',
'test.engine.test_parseconnect',
'test.ext.test_compiler',
'test.orm.test_descriptor',
'test.orm.test_inspect',
'test.orm.test_query',
'test.sql.test_cte',
'test.sql.test_ddlemit',
'test.sql.test_inspect',
'test.sql.test_operators',
]
passed = [] passed = []
failed = [] failed = []
...@@ -70,28 +96,36 @@ for fn in test_files: ...@@ -70,28 +96,36 @@ for fn in test_files:
mname = fn[len(SQLALCHEMY_DIR) + 1:-3].replace('/', '.') mname = fn[len(SQLALCHEMY_DIR) + 1:-3].replace('/', '.')
if mname not in MODULES_TO_TEST: if mname not in MODULES_TO_TEST:
continue continue
print print '=' * 50
print mname print mname
try: try:
m = __import__(mname, fromlist=["__all__"]) m = __import__(mname, fromlist=["__all__"])
for nname in dir(m): for clsname in dir(m):
n = getattr(m, nname) cls = getattr(m, clsname)
if not nname.endswith("Test") or not isinstance(n, type): if not clsname.endswith("Test") or not isinstance(cls, type):
continue continue
print "Running", n print "Running", cls
n = n() if hasattr(cls, "setup_class"):
cls.setup_class()
n = cls()
for t in dir(n): for t in dir(n):
if not t.startswith("test_"): if not t.startswith("test_"):
continue continue
if nname == "SubclassGrowthTest" and t == "test_subclass": if clsname == "SubclassGrowthTest" and t == "test_subclass":
# This test should be marked as requiring predictable_pc # This test should be marked as requiring predictable_pc
continue continue
print "Running", t print "Running", t
n.setup() n.setup()
try:
getattr(n, t)() getattr(n, t)()
except SkipTest:
pass
n.teardown() n.teardown()
if hasattr(cls, "teardown_class"):
cls.teardown_class()
gc.collect()
except Exception: except Exception:
print mname, "FAILED" print mname, "FAILED"
traceback.print_exc() traceback.print_exc()
......
...@@ -43,3 +43,5 @@ def f(m): ...@@ -43,3 +43,5 @@ def f(m):
f(C.foo) f(C.foo)
f(C().foo) f(C().foo)
C().foo.__call__()
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