Commit a53ab1a8 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Merge pull request #465 from kmod/virtualenv

bcrypt support
parents 7b71c6f8 578f9b6a
......@@ -207,7 +207,7 @@ add_test(NAME analysis_unittest COMMAND analysis_unittest)
add_test(NAME pyston_defaults COMMAND ${PYTHON_EXE} ${CMAKE_SOURCE_DIR}/tools/tester.py -R ./pyston -j${TEST_THREADS} -a=-S -k ${CMAKE_SOURCE_DIR}/test/tests)
# we pass -I to cpython tests and skip failing ones b/c they are slooow otherwise
add_test(NAME pyston_defaults_cpython_tests COMMAND ${PYTHON_EXE} ${CMAKE_SOURCE_DIR}/tools/tester.py -R ./pyston -j${TEST_THREADS} -a=-S -k --exit-code-only --skip-failing -t30 ${CMAKE_SOURCE_DIR}/test/cpython)
add_test(NAME pyston_defaults_integration_tests COMMAND ${PYTHON_EXE} ${CMAKE_SOURCE_DIR}/tools/tester.py -R ./pyston -j${TEST_THREADS} -a=-S -k --exit-code-only --skip-failing -t120 ${CMAKE_SOURCE_DIR}/test/integration)
add_test(NAME pyston_defaults_integration_tests COMMAND ${PYTHON_EXE} ${CMAKE_SOURCE_DIR}/tools/tester.py -R ./pyston -j${TEST_THREADS} -a=-S -k --exit-code-only --skip-failing -t180 ${CMAKE_SOURCE_DIR}/test/integration)
add_test(NAME pyston_max_compilation_tier COMMAND ${PYTHON_EXE} ${CMAKE_SOURCE_DIR}/tools/tester.py -R ./pyston -j${TEST_THREADS} -a=-O -a=-S -k ${CMAKE_SOURCE_DIR}/test/tests)
add_test(NAME pyston_old_parser COMMAND ${PYTHON_EXE} ${CMAKE_SOURCE_DIR}/tools/tester.py -a=-x -R ./pyston -j1 -a=-n -a=-S -k ${CMAKE_SOURCE_DIR}/test/tests)
......
......@@ -366,6 +366,7 @@ STDOBJECT_SRCS := \
memoryobject.c \
iterobject.c \
bufferobject.c \
cobject.c \
$(EXTRA_STDOBJECT_SRCS)
STDPYTHON_SRCS := \
......@@ -494,7 +495,7 @@ check:
$(PYTHON) $(TOOLS_DIR)/tester.py -R pyston_dbg -j$(TEST_THREADS) -k -a=-S $(TESTS_DIR) $(ARGS)
@# we pass -I to cpython tests & skip failing ones because they are sloooow otherwise
$(PYTHON) $(TOOLS_DIR)/tester.py -R pyston_dbg -j$(TEST_THREADS) -k -a=-S --exit-code-only --skip-failing -t30 $(TEST_DIR)/cpython $(ARGS)
$(PYTHON) $(TOOLS_DIR)/tester.py -R pyston_dbg -j$(TEST_THREADS) -k -a=-S --exit-code-only --skip-failing -t120 $(TEST_DIR)/integration $(ARGS)
$(PYTHON) $(TOOLS_DIR)/tester.py -R pyston_dbg -j$(TEST_THREADS) -k -a=-S --exit-code-only --skip-failing -t180 $(TEST_DIR)/integration $(ARGS)
$(PYTHON) $(TOOLS_DIR)/tester.py -R pyston_dbg -j$(TEST_THREADS) -k -a=-n -a=-x -a=-S $(TESTS_DIR) $(ARGS)
@# skip -O for dbg
......@@ -511,7 +512,7 @@ check:
$(PYTHON) $(TOOLS_DIR)/tester.py -R pyston_release -j$(TEST_THREADS) -k -a=-S $(TESTS_DIR) $(ARGS)
@# we pass -I to cpython tests and skip failing ones because they are sloooow otherwise
$(PYTHON) $(TOOLS_DIR)/tester.py -R pyston_release -j$(TEST_THREADS) -k -a=-S --exit-code-only --skip-failing $(TEST_DIR)/cpython $(ARGS)
$(PYTHON) $(TOOLS_DIR)/tester.py -R pyston_release -j$(TEST_THREADS) -k -a=-S --exit-code-only --skip-failing -t60 $(TEST_DIR)/integration $(ARGS)
$(PYTHON) $(TOOLS_DIR)/tester.py -R pyston_release -j$(TEST_THREADS) -k -a=-S --exit-code-only --skip-failing -t120 $(TEST_DIR)/integration $(ARGS)
@# skip -n for dbg
$(PYTHON) $(TOOLS_DIR)/tester.py -R pyston_release -j$(TEST_THREADS) -k -a=-O -a=-x -a=-S $(TESTS_DIR) $(ARGS)
......@@ -956,7 +957,7 @@ check$1 test$1: $(PYTHON_EXE_DEPS) pyston$1 ext_pyston
$(PYTHON) $(TOOLS_DIR)/tester.py -R pyston$1 -j$(TEST_THREADS) -a=-S -k $(TESTS_DIR) $(ARGS)
@# we pass -I to cpython tests and skip failing ones because they are sloooow otherwise
$(PYTHON) $(TOOLS_DIR)/tester.py -R pyston$1 -j$(TEST_THREADS) -a=-S -k --exit-code-only --skip-failing -t30 $(TEST_DIR)/cpython $(ARGS)
$(PYTHON) $(TOOLS_DIR)/tester.py -R pyston$1 -j$(TEST_THREADS) -k -a=-S --exit-code-only --skip-failing -t120 $(TEST_DIR)/integration $(ARGS)
$(PYTHON) $(TOOLS_DIR)/tester.py -R pyston$1 -j$(TEST_THREADS) -k -a=-S --exit-code-only --skip-failing -t180 $(TEST_DIR)/integration $(ARGS)
$(PYTHON) $(TOOLS_DIR)/tester.py -a=-x -R pyston$1 -j$(TEST_THREADS) -a=-n -a=-S -k $(TESTS_DIR) $(ARGS)
$(PYTHON) $(TOOLS_DIR)/tester.py -R pyston$1 -j$(TEST_THREADS) -a=-O -a=-S -k $(TESTS_DIR) $(ARGS)
......
......@@ -76,6 +76,7 @@ file(GLOB_RECURSE STDOBJECT_SRCS Objects
bytearrayobject.c
bytes_methods.c
capsule.c
cobject.c
exceptions.c
iterobject.c
memoryobject.c
......
......@@ -75,6 +75,7 @@
#include "methodobject.h"
#include "moduleobject.h"
#include "classobject.h"
#include "cobject.h"
#include "fileobject.h"
#include "pycapsule.h"
#include "traceback.h"
......
// This file is originally from CPython 2.7, with modifications for Pyston
/*
CObjects are marked Pending Deprecation as of Python 2.7.
The full schedule for 2.x is as follows:
- CObjects are marked Pending Deprecation in Python 2.7.
- CObjects will be marked Deprecated in Python 2.8
(if there is one).
- CObjects will be removed in Python 2.9 (if there is one).
Additionally, for the Python 3.x series:
- CObjects were marked Deprecated in Python 3.1.
- CObjects will be removed in Python 3.2.
You should switch all use of CObjects to capsules. Capsules
have a safer and more consistent API. For more information,
see Include/pycapsule.h, or read the "Capsules" topic in
the "Python/C API Reference Manual".
Python 2.7 no longer uses CObjects itself; all objects which
were formerly CObjects are now capsules. Note that this change
does not by itself break binary compatibility with extensions
built for previous versions of Python--PyCObject_AsVoidPtr()
has been changed to also understand capsules.
*/
/* original file header comment follows: */
/* C objects to be exported from one extension module to another.
C objects are used for communication between extension modules.
They provide a way for an extension module to export a C interface
to other extension modules, so that extension modules can use the
Python import mechanism to link to one another.
*/
#ifndef Py_COBJECT_H
#define Py_COBJECT_H
#ifdef __cplusplus
extern "C" {
#endif
PyAPI_DATA(PyTypeObject) PyCObject_Type;
#define PyCObject_Check(op) (Py_TYPE(op) == &PyCObject_Type)
/* Create a PyCObject from a pointer to a C object and an optional
destructor function. If the second argument is non-null, then it
will be called with the first argument if and when the PyCObject is
destroyed.
*/
PyAPI_FUNC(PyObject *) PyCObject_FromVoidPtr(
void *cobj, void (*destruct)(void*)) PYSTON_NOEXCEPT;
/* Create a PyCObject from a pointer to a C object, a description object,
and an optional destructor function. If the third argument is non-null,
then it will be called with the first and second arguments if and when
the PyCObject is destroyed.
*/
PyAPI_FUNC(PyObject *) PyCObject_FromVoidPtrAndDesc(
void *cobj, void *desc, void (*destruct)(void*,void*)) PYSTON_NOEXCEPT;
/* Retrieve a pointer to a C object from a PyCObject. */
PyAPI_FUNC(void *) PyCObject_AsVoidPtr(PyObject *) PYSTON_NOEXCEPT;
/* Retrieve a pointer to a description object from a PyCObject. */
PyAPI_FUNC(void *) PyCObject_GetDesc(PyObject *) PYSTON_NOEXCEPT;
/* Import a pointer to a C object from a module using a PyCObject. */
PyAPI_FUNC(void *) PyCObject_Import(char *module_name, char *cobject_name) PYSTON_NOEXCEPT;
/* Modify a C object. Fails (==0) if object has a destructor. */
PyAPI_FUNC(int) PyCObject_SetVoidPtr(PyObject *self, void *cobj) PYSTON_NOEXCEPT;
typedef struct {
PyObject_HEAD
void *cobject;
void *desc;
void (*destructor)(void *);
} PyCObject;
#ifdef __cplusplus
}
#endif
#endif /* !Py_COBJECT_H */
......@@ -553,7 +553,7 @@ PyAPI_FUNC(int) PyNumber_CoerceEx(PyObject **, PyObject **) PYSTON_NOEXCEPT;
PyAPI_FUNC(void) PyObject_ClearWeakRefs(PyObject *) PYSTON_NOEXCEPT;
/* A slot function whose address we need to compare */
extern int _PyObject_SlotCompare(PyObject *, PyObject *);
extern int _PyObject_SlotCompare(PyObject *, PyObject *) PYSTON_NOEXCEPT;
/* Same as PyObject_Generic{Get,Set}Attr, but passing the attributes
dict as the last parameter. */
PyAPI_FUNC(PyObject *)
......
......@@ -312,13 +312,13 @@ extern PyGC_Head *_PyGC_generation0;
(PyObject_IS_GC(obj) && \
(!PyTuple_CheckExact(obj) || _PyObject_GC_IS_TRACKED(obj)))
#endif
PyAPI_FUNC(PyObject *) _PyObject_GC_Malloc(size_t) PYSTON_NOEXCEPT;
PyAPI_FUNC(PyObject *) _PyObject_GC_New(PyTypeObject *) PYSTON_NOEXCEPT;
PyAPI_FUNC(PyVarObject *) _PyObject_GC_NewVar(PyTypeObject *, Py_ssize_t) PYSTON_NOEXCEPT;
PyAPI_FUNC(void) PyObject_GC_Track(void *) PYSTON_NOEXCEPT;
PyAPI_FUNC(void) PyObject_GC_UnTrack(void *) PYSTON_NOEXCEPT;
PyAPI_FUNC(void) PyObject_GC_Del(void *) PYSTON_NOEXCEPT;
#endif
#define PyType_IS_GC(t) ((t),1)
#define _PyObject_GC_TRACK(o) ((void)(o))
#define _PyObject_GC_UNTRACK(o) ((void)(o))
......
......@@ -36,13 +36,16 @@ PyAPI_DATA(int) Py_HashRandomizationFlag;
// Pyston change: make Py_FatalError a macro so that it can access linenumber info, similar to assert:
//PyAPI_FUNC(void) Py_FatalError(const char *message) __attribute__((__noreturn__)) PYSTON_NOEXCEPT;
PyAPI_FUNC(void) _Py_FatalError(const char *fmt, const char *function, const char *message)
__attribute__((__noreturn__));
#define _PYSTON_STRINGIFY(N) #N
#define PYSTON_STRINGIFY(N) _PYSTON_STRINGIFY(N)
// Defer the real work of Py_FatalError to a function, since some users expect it to be a real function,
// ie can be used as an expression (a do-while(0) loop would fail that).
#define Py_FatalError(message) \
do { \
fprintf(stderr, __FILE__ ":" PYSTON_STRINGIFY(__LINE__) ": %s: Fatal Python error: %s\n", __PRETTY_FUNCTION__, message); \
abort(); \
} while (0)
_Py_FatalError(__FILE__ \
":" PYSTON_STRINGIFY(__LINE__) ": %s: Fatal Python error: %s\n", \
__PRETTY_FUNCTION__, message)
#ifdef __cplusplus
}
......
......@@ -371,6 +371,7 @@ class CCompiler:
cc_args[:0] = ['-g']
if before:
cc_args[:0] = before
cc_args = cc_args + ["-Werror=implicit-function-declaration"]
return cc_args
def _fix_compile_args(self, output_dir, macros, include_dirs):
......
// This file is originally from CPython 2.7, with modifications for Pyston
/* Wrap void* pointers to be passed between C modules */
#include "Python.h"
/* Declarations for objects of type PyCObject */
typedef void (*destructor1)(void *);
typedef void (*destructor2)(void *, void*);
static int cobject_deprecation_warning(void)
{
return PyErr_WarnPy3k("CObject type is not supported in 3.x. "
"Please use capsule objects instead.", 1);
}
PyObject *
PyCObject_FromVoidPtr(void *cobj, void (*destr)(void *))
{
PyCObject *self;
if (cobject_deprecation_warning()) {
return NULL;
}
self = PyObject_NEW(PyCObject, &PyCObject_Type);
if (self == NULL)
return NULL;
self->cobject=cobj;
self->destructor=destr;
self->desc=NULL;
return (PyObject *)self;
}
PyObject *
PyCObject_FromVoidPtrAndDesc(void *cobj, void *desc,
void (*destr)(void *, void *))
{
PyCObject *self;
if (cobject_deprecation_warning()) {
return NULL;
}
if (!desc) {
PyErr_SetString(PyExc_TypeError,
"PyCObject_FromVoidPtrAndDesc called with null"
" description");
return NULL;
}
self = PyObject_NEW(PyCObject, &PyCObject_Type);
if (self == NULL)
return NULL;
self->cobject = cobj;
self->destructor = (destructor1)destr;
self->desc = desc;
return (PyObject *)self;
}
void *
PyCObject_AsVoidPtr(PyObject *self)
{
if (self) {
if (PyCapsule_CheckExact(self)) {
const char *name = PyCapsule_GetName(self);
return (void *)PyCapsule_GetPointer(self, name);
}
if (self->ob_type == &PyCObject_Type)
return ((PyCObject *)self)->cobject;
PyErr_SetString(PyExc_TypeError,
"PyCObject_AsVoidPtr with non-C-object");
}
if (!PyErr_Occurred())
PyErr_SetString(PyExc_TypeError,
"PyCObject_AsVoidPtr called with null pointer");
return NULL;
}
void *
PyCObject_GetDesc(PyObject *self)
{
if (self) {
if (self->ob_type == &PyCObject_Type)
return ((PyCObject *)self)->desc;
PyErr_SetString(PyExc_TypeError,
"PyCObject_GetDesc with non-C-object");
}
if (!PyErr_Occurred())
PyErr_SetString(PyExc_TypeError,
"PyCObject_GetDesc called with null pointer");
return NULL;
}
void *
PyCObject_Import(char *module_name, char *name)
{
PyObject *m, *c;
void *r = NULL;
if ((m = PyImport_ImportModule(module_name))) {
if ((c = PyObject_GetAttrString(m,name))) {
r = PyCObject_AsVoidPtr(c);
Py_DECREF(c);
}
Py_DECREF(m);
}
return r;
}
int
PyCObject_SetVoidPtr(PyObject *self, void *cobj)
{
PyCObject* cself = (PyCObject*)self;
if (cself == NULL || !PyCObject_Check(cself) ||
cself->destructor != NULL) {
PyErr_SetString(PyExc_TypeError,
"Invalid call to PyCObject_SetVoidPtr");
return 0;
}
cself->cobject = cobj;
return 1;
}
static void
PyCObject_dealloc(PyCObject *self)
{
if (self->destructor) {
if(self->desc)
((destructor2)(self->destructor))(self->cobject, self->desc);
else
(self->destructor)(self->cobject);
}
PyObject_DEL(self);
}
PyDoc_STRVAR(PyCObject_Type__doc__,
"C objects to be exported from one extension module to another\n\
\n\
C objects are used for communication between extension modules. They\n\
provide a way for an extension module to export a C interface to other\n\
extension modules, so that extension modules can use the Python import\n\
mechanism to link to one another.");
PyTypeObject PyCObject_Type = {
PyVarObject_HEAD_INIT(/* Pyston change: &PyType_Type */ NULL, 0)
"PyCObject", /*tp_name*/
sizeof(PyCObject), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
(destructor)PyCObject_dealloc, /*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash*/
0, /*tp_call*/
0, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
0, /*tp_flags*/
PyCObject_Type__doc__ /*tp_doc*/
};
......@@ -27,6 +27,31 @@
namespace pyston {
static PyObject* type_error(const char* msg, PyObject* obj) noexcept {
PyErr_Format(PyExc_TypeError, msg, Py_TYPE(obj)->tp_name);
return NULL;
}
static PyObject* null_error(void) noexcept {
if (!PyErr_Occurred())
PyErr_SetString(PyExc_SystemError, "null argument to internal routine");
return NULL;
}
extern "C" int PyObject_Cmp(PyObject* o1, PyObject* o2, int* result) noexcept {
int r;
if (o1 == NULL || o2 == NULL) {
null_error();
return -1;
}
r = PyObject_Compare(o1, o2);
if (PyErr_Occurred())
return -1;
*result = r;
return 0;
}
extern "C" Py_ssize_t _PyObject_LengthHint(PyObject* o, Py_ssize_t defaultvalue) noexcept {
static PyObject* hintstrobj = NULL;
PyObject* ro, *hintmeth;
......@@ -227,17 +252,6 @@ extern "C" void PyBuffer_Release(Py_buffer* view) noexcept {
view->obj = NULL;
}
static PyObject* type_error(const char* msg, PyObject* obj) noexcept {
PyErr_Format(PyExc_TypeError, msg, Py_TYPE(obj)->tp_name);
return NULL;
}
static PyObject* null_error(void) noexcept {
if (!PyErr_Occurred())
PyErr_SetString(PyExc_SystemError, "null argument to internal routine");
return NULL;
}
static PyObject* objargs_mktuple(va_list va) noexcept {
int i, n = 0;
va_list countva;
......@@ -1516,9 +1530,28 @@ extern "C" int PyNumber_Coerce(PyObject**, PyObject**) noexcept {
return -1;
}
extern "C" int PyNumber_CoerceEx(PyObject**, PyObject**) noexcept {
fatalOrError(PyExc_NotImplementedError, "unimplemented");
return -1;
extern "C" int PyNumber_CoerceEx(PyObject** pv, PyObject** pw) noexcept {
PyObject* v = *pv;
PyObject* w = *pw;
int res;
/* Shortcut only for old-style types */
if (v->cls == w->cls && !PyType_HasFeature(v->cls, Py_TPFLAGS_CHECKTYPES)) {
Py_INCREF(v);
Py_INCREF(w);
return 0;
}
if (v->cls->tp_as_number && v->cls->tp_as_number->nb_coerce) {
res = (*v->cls->tp_as_number->nb_coerce)(pv, pw);
if (res <= 0)
return res;
}
if (w->cls->tp_as_number && w->cls->tp_as_number->nb_coerce) {
res = (*w->cls->tp_as_number->nb_coerce)(pw, pv);
if (res <= 0)
return res;
}
return 1;
}
extern "C" PyObject* _PyNumber_ConvertIntegralToInt(PyObject* integral, const char* error_format) noexcept {
......
......@@ -472,31 +472,6 @@ extern "C" int PyObject_AsWriteBuffer(PyObject* obj, void** buffer, Py_ssize_t*
Py_FatalError("unimplemented");
}
/* Return -1 if error; 1 if v op w; 0 if not (v op w). */
extern "C" int PyObject_RichCompareBool(PyObject* v, PyObject* w, int op) noexcept {
PyObject* res;
int ok;
/* Quick result when objects are the same.
Guarantees that identity implies equality. */
if (v == w) {
if (op == Py_EQ)
return 1;
else if (op == Py_NE)
return 0;
}
res = PyObject_RichCompare(v, w, op);
if (res == NULL)
return -1;
if (PyBool_Check(res))
ok = (res == Py_True);
else
ok = PyObject_IsTrue(res);
Py_DECREF(res);
return ok;
}
// I'm not sure how we can support this one:
extern "C" PyObject** _PyObject_GetDictPtr(PyObject* obj) noexcept {
fatalOrError(PyExc_NotImplementedError, "unimplemented");
......@@ -564,10 +539,443 @@ extern "C" void Py_ReprLeave(PyObject* obj) noexcept {
}
}
extern "C" int PyObject_Compare(PyObject* o1, PyObject* o2) noexcept {
fatalOrError(PyExc_NotImplementedError, "unimplemented");
// 'On error, the value returned is undefined; use PyErr_Occurred() to detect an error.'
// - https://docs.python.org/2/c-api/object.html
return 0xdeadbeef;
/* Helper to warn about deprecated tp_compare return values. Return:
-2 for an exception;
-1 if v < w;
0 if v == w;
1 if v > w.
(This function cannot return 2.)
*/
static int adjust_tp_compare(int c) {
if (PyErr_Occurred()) {
if (c != -1 && c != -2) {
PyObject* t, *v, *tb;
PyErr_Fetch(&t, &v, &tb);
if (PyErr_Warn(PyExc_RuntimeWarning, "tp_compare didn't return -1 or -2 "
"for exception") < 0) {
Py_XDECREF(t);
Py_XDECREF(v);
Py_XDECREF(tb);
} else
PyErr_Restore(t, v, tb);
}
return -2;
} else if (c < -1 || c > 1) {
if (PyErr_Warn(PyExc_RuntimeWarning, "tp_compare didn't return -1, 0 or 1") < 0)
return -2;
else
return c < -1 ? -1 : 1;
} else {
assert(c >= -1 && c <= 1);
return c;
}
}
/* Macro to get the tp_richcompare field of a type if defined */
#define RICHCOMPARE(t) (PyType_HasFeature((t), Py_TPFLAGS_HAVE_RICHCOMPARE) ? (t)->tp_richcompare : NULL)
/* Map rich comparison operators to their swapped version, e.g. LT --> GT */
extern "C" {
int _Py_SwappedOp[] = { Py_GT, Py_GE, Py_EQ, Py_NE, Py_LT, Py_LE };
}
/* Try a genuine rich comparison, returning an object. Return:
NULL for exception;
NotImplemented if this particular rich comparison is not implemented or
undefined;
some object not equal to NotImplemented if it is implemented
(this latter object may not be a Boolean).
*/
static PyObject* try_rich_compare(PyObject* v, PyObject* w, int op) {
richcmpfunc f;
PyObject* res;
if (v->cls != w->cls && PyType_IsSubtype(w->cls, v->cls) && (f = RICHCOMPARE(w->cls)) != NULL) {
res = (*f)(w, v, _Py_SwappedOp[op]);
if (res != Py_NotImplemented)
return res;
Py_DECREF(res);
}
if ((f = RICHCOMPARE(v->cls)) != NULL) {
res = (*f)(v, w, op);
if (res != Py_NotImplemented)
return res;
Py_DECREF(res);
}
if ((f = RICHCOMPARE(w->cls)) != NULL) {
return (*f)(w, v, _Py_SwappedOp[op]);
}
res = Py_NotImplemented;
Py_INCREF(res);
return res;
}
/* Try a genuine rich comparison, returning an int. Return:
-1 for exception (including the case where try_rich_compare() returns an
object that's not a Boolean);
0 if the outcome is false;
1 if the outcome is true;
2 if this particular rich comparison is not implemented or undefined.
*/
static int try_rich_compare_bool(PyObject* v, PyObject* w, int op) {
PyObject* res;
int ok;
if (RICHCOMPARE(v->cls) == NULL && RICHCOMPARE(w->cls) == NULL)
return 2; /* Shortcut, avoid INCREF+DECREF */
res = try_rich_compare(v, w, op);
if (res == NULL)
return -1;
if (res == Py_NotImplemented) {
Py_DECREF(res);
return 2;
}
ok = PyObject_IsTrue(res);
Py_DECREF(res);
return ok;
}
/* Try rich comparisons to determine a 3-way comparison. Return:
-2 for an exception;
-1 if v < w;
0 if v == w;
1 if v > w;
2 if this particular rich comparison is not implemented or undefined.
*/
static int try_rich_to_3way_compare(PyObject* v, PyObject* w) {
static struct {
int op;
int outcome;
} tries[3] = {
/* Try this operator, and if it is true, use this outcome: */
{ Py_EQ, 0 },
{ Py_LT, -1 },
{ Py_GT, 1 },
};
int i;
if (RICHCOMPARE(v->cls) == NULL && RICHCOMPARE(w->cls) == NULL)
return 2; /* Shortcut */
for (i = 0; i < 3; i++) {
switch (try_rich_compare_bool(v, w, tries[i].op)) {
case -1:
return -2;
case 1:
return tries[i].outcome;
}
}
return 2;
}
/* Try a 3-way comparison, returning an int. Return:
-2 for an exception;
-1 if v < w;
0 if v == w;
1 if v > w;
2 if this particular 3-way comparison is not implemented or undefined.
*/
static int try_3way_compare(PyObject* v, PyObject* w) {
int c;
cmpfunc f;
/* Comparisons involving instances are given to instance_compare,
which has the same return conventions as this function. */
f = v->cls->tp_compare;
if (PyInstance_Check(v))
return (*f)(v, w);
if (PyInstance_Check(w))
return (*w->cls->tp_compare)(v, w);
/* If both have the same (non-NULL) tp_compare, use it. */
if (f != NULL && f == w->cls->tp_compare) {
c = (*f)(v, w);
return adjust_tp_compare(c);
}
/* If either tp_compare is _PyObject_SlotCompare, that's safe. */
if (f == _PyObject_SlotCompare || w->cls->tp_compare == _PyObject_SlotCompare)
return _PyObject_SlotCompare(v, w);
/* If we're here, v and w,
a) are not instances;
b) have different types or a type without tp_compare; and
c) don't have a user-defined tp_compare.
tp_compare implementations in C assume that both arguments
have their type, so we give up if the coercion fails or if
it yields types which are still incompatible (which can
happen with a user-defined nb_coerce).
*/
c = PyNumber_CoerceEx(&v, &w);
if (c < 0)
return -2;
if (c > 0)
return 2;
f = v->cls->tp_compare;
if (f != NULL && f == w->cls->tp_compare) {
c = (*f)(v, w);
Py_DECREF(v);
Py_DECREF(w);
return adjust_tp_compare(c);
}
/* No comparison defined */
Py_DECREF(v);
Py_DECREF(w);
return 2;
}
/* Final fallback 3-way comparison, returning an int. Return:
-2 if an error occurred;
-1 if v < w;
0 if v == w;
1 if v > w.
*/
static int default_3way_compare(PyObject* v, PyObject* w) {
int c;
const char* vname, *wname;
if (v->cls == w->cls) {
/* When comparing these pointers, they must be cast to
* integer types (i.e. Py_uintptr_t, our spelling of C9X's
* uintptr_t). ANSI specifies that pointer compares other
* than == and != to non-related structures are undefined.
*/
Py_uintptr_t vv = (Py_uintptr_t)v;
Py_uintptr_t ww = (Py_uintptr_t)w;
return (vv < ww) ? -1 : (vv > ww) ? 1 : 0;
}
/* None is smaller than anything */
if (v == Py_None)
return -1;
if (w == Py_None)
return 1;
/* different type: compare type names; numbers are smaller */
if (PyNumber_Check(v))
vname = "";
else
vname = v->cls->tp_name;
if (PyNumber_Check(w))
wname = "";
else
wname = w->cls->tp_name;
c = strcmp(vname, wname);
if (c < 0)
return -1;
if (c > 0)
return 1;
/* Same type name, or (more likely) incomparable numeric types */
return ((Py_uintptr_t)(v->cls) < (Py_uintptr_t)(w->cls)) ? -1 : 1;
}
/* Do a 3-way comparison, by hook or by crook. Return:
-2 for an exception (but see below);
-1 if v < w;
0 if v == w;
1 if v > w;
BUT: if the object implements a tp_compare function, it returns
whatever this function returns (whether with an exception or not).
*/
static int do_cmp(PyObject* v, PyObject* w) {
int c;
cmpfunc f;
if (v->cls == w->cls && (f = v->cls->tp_compare) != NULL) {
c = (*f)(v, w);
if (PyInstance_Check(v)) {
/* Instance tp_compare has a different signature.
But if it returns undefined we fall through. */
if (c != 2)
return c;
/* Else fall through to try_rich_to_3way_compare() */
} else
return adjust_tp_compare(c);
}
/* We only get here if one of the following is true:
a) v and w have different types
b) v and w have the same type, which doesn't have tp_compare
c) v and w are instances, and either __cmp__ is not defined or
__cmp__ returns NotImplemented
*/
c = try_rich_to_3way_compare(v, w);
if (c < 2)
return c;
c = try_3way_compare(v, w);
if (c < 2)
return c;
return default_3way_compare(v, w);
}
/* Compare v to w. Return
-1 if v < w or exception (PyErr_Occurred() true in latter case).
0 if v == w.
1 if v > w.
XXX The docs (C API manual) say the return value is undefined in case
XXX of error.
*/
extern "C" int PyObject_Compare(PyObject* v, PyObject* w) noexcept {
int result;
if (v == NULL || w == NULL) {
PyErr_BadInternalCall();
return -1;
}
if (v == w)
return 0;
if (Py_EnterRecursiveCall(" in cmp"))
return -1;
result = do_cmp(v, w);
Py_LeaveRecursiveCall();
return result < 0 ? -1 : result;
}
/* Return (new reference to) Py_True or Py_False. */
static PyObject* convert_3way_to_object(int op, int c) noexcept {
PyObject* result;
switch (op) {
case Py_LT:
c = c < 0;
break;
case Py_LE:
c = c <= 0;
break;
case Py_EQ:
c = c == 0;
break;
case Py_NE:
c = c != 0;
break;
case Py_GT:
c = c > 0;
break;
case Py_GE:
c = c >= 0;
break;
}
result = c ? Py_True : Py_False;
Py_INCREF(result);
return result;
}
/* We want a rich comparison but don't have one. Try a 3-way cmp instead.
Return
NULL if error
Py_True if v op w
Py_False if not (v op w)
*/
static PyObject* try_3way_to_rich_compare(PyObject* v, PyObject* w, int op) noexcept {
int c;
c = try_3way_compare(v, w);
if (c >= 2) {
/* Py3K warning if types are not equal and comparison isn't == or != */
if (Py_Py3kWarningFlag && v->cls != w->cls && op != Py_EQ && op != Py_NE
&& PyErr_WarnEx(PyExc_DeprecationWarning, "comparing unequal types not supported "
"in 3.x",
1) < 0) {
return NULL;
}
c = default_3way_compare(v, w);
}
if (c <= -2)
return NULL;
return convert_3way_to_object(op, c);
}
/* Do rich comparison on v and w. Return
NULL if error
Else a new reference to an object other than Py_NotImplemented, usually(?):
Py_True if v op w
Py_False if not (v op w)
*/
static PyObject* do_richcmp(PyObject* v, PyObject* w, int op) noexcept {
PyObject* res;
res = try_rich_compare(v, w, op);
if (res != Py_NotImplemented)
return res;
Py_DECREF(res);
return try_3way_to_rich_compare(v, w, op);
}
/* Return:
NULL for exception;
some object not equal to NotImplemented if it is implemented
(this latter object may not be a Boolean).
*/
extern "C" PyObject* PyObject_RichCompare(PyObject* v, PyObject* w, int op) noexcept {
PyObject* res;
assert(Py_LT <= op && op <= Py_GE);
if (Py_EnterRecursiveCall(" in cmp"))
return NULL;
/* If the types are equal, and not old-style instances, try to
get out cheap (don't bother with coercions etc.). */
if (v->cls == w->cls && !PyInstance_Check(v)) {
cmpfunc fcmp;
richcmpfunc frich = RICHCOMPARE(v->cls);
/* If the type has richcmp, try it first. try_rich_compare
tries it two-sided, which is not needed since we've a
single type only. */
if (frich != NULL) {
res = (*frich)(v, w, op);
if (res != Py_NotImplemented)
goto Done;
Py_DECREF(res);
}
/* No richcmp, or this particular richmp not implemented.
Try 3-way cmp. */
fcmp = v->cls->tp_compare;
if (fcmp != NULL) {
int c = (*fcmp)(v, w);
c = adjust_tp_compare(c);
if (c == -2) {
res = NULL;
goto Done;
}
res = convert_3way_to_object(op, c);
goto Done;
}
}
/* Fast path not taken, or couldn't deliver a useful result. */
res = do_richcmp(v, w, op);
Done:
Py_LeaveRecursiveCall();
return res;
}
/* Return -1 if error; 1 if v op w; 0 if not (v op w). */
extern "C" int PyObject_RichCompareBool(PyObject* v, PyObject* w, int op) noexcept {
PyObject* res;
int ok;
/* Quick result when objects are the same.
Guarantees that identity implies equality. */
if (v == w) {
if (op == Py_EQ)
return 1;
else if (op == Py_NE)
return 0;
}
res = PyObject_RichCompare(v, w, op);
if (res == NULL)
return -1;
if (PyBool_Check(res))
ok = (res == Py_True);
else
ok = PyObject_IsTrue(res);
Py_DECREF(res);
return ok;
}
}
......@@ -461,6 +461,26 @@ static PyObject* wrap_delitem(PyObject* self, PyObject* args, void* wrapped) noe
return Py_None;
}
static PyObject* wrap_cmpfunc(PyObject* self, PyObject* args, void* wrapped) noexcept {
cmpfunc func = (cmpfunc)wrapped;
int res;
PyObject* other;
if (!check_num_args(args, 1))
return NULL;
other = PyTuple_GET_ITEM(args, 0);
if (Py_TYPE(other)->tp_compare != func && !PyType_IsSubtype(Py_TYPE(other), Py_TYPE(self))) {
PyErr_Format(PyExc_TypeError, "%s.__cmp__(x,y) requires y to be a '%s', not a '%s'", Py_TYPE(self)->tp_name,
Py_TYPE(self)->tp_name, Py_TYPE(other)->tp_name);
return NULL;
}
res = (*func)(self, other);
if (PyErr_Occurred())
return NULL;
return PyInt_FromLong((long)res);
}
static PyObject* wrap_init(PyObject* self, PyObject* args, void* wrapped, PyObject* kwds) noexcept {
initproc func = (initproc)wrapped;
......@@ -565,7 +585,57 @@ static PyObject* call_maybe(PyObject* o, const char* name, PyObject** nameobj, c
return retval;
}
PyObject* slot_tp_repr(PyObject* self) noexcept {
static int half_compare(PyObject* self, PyObject* other) noexcept {
PyObject* func, *args, *res;
static PyObject* cmp_str;
Py_ssize_t c;
func = lookup_method(self, "__cmp__", &cmp_str);
if (func == NULL) {
PyErr_Clear();
} else {
args = PyTuple_Pack(1, other);
if (args == NULL)
res = NULL;
else {
res = PyObject_Call(func, args, NULL);
Py_DECREF(args);
}
Py_DECREF(func);
if (res != Py_NotImplemented) {
if (res == NULL)
return -2;
c = PyInt_AsLong(res);
Py_DECREF(res);
if (c == -1 && PyErr_Occurred())
return -2;
return (c < 0) ? -1 : (c > 0) ? 1 : 0;
}
Py_DECREF(res);
}
return 2;
}
/* This slot is published for the benefit of try_3way_compare in object.c */
extern "C" int _PyObject_SlotCompare(PyObject* self, PyObject* other) noexcept {
int c;
if (Py_TYPE(self)->tp_compare == _PyObject_SlotCompare) {
c = half_compare(self, other);
if (c <= 1)
return c;
}
if (Py_TYPE(other)->tp_compare == _PyObject_SlotCompare) {
c = half_compare(other, self);
if (c < -1)
return -2;
if (c <= 1)
return -c;
}
return (void*)self < (void*)other ? -1 : (void*)self > (void*)other ? 1 : 0;
}
static PyObject* slot_tp_repr(PyObject* self) noexcept {
try {
return repr(self);
} catch (ExcInfo e) {
......@@ -574,7 +644,7 @@ PyObject* slot_tp_repr(PyObject* self) noexcept {
}
}
PyObject* slot_tp_str(PyObject* self) noexcept {
static PyObject* slot_tp_str(PyObject* self) noexcept {
try {
return str(self);
} catch (ExcInfo e) {
......@@ -1264,6 +1334,7 @@ static slotdef slotdefs[]
TPSLOT("__getattr__", tp_getattr, NULL, NULL, ""),
TPSLOT("__setattr__", tp_setattr, NULL, NULL, ""),
TPSLOT("__delattr__", tp_setattr, NULL, NULL, ""),
TPSLOT("__cmp__", tp_compare, _PyObject_SlotCompare, wrap_cmpfunc, "x.__cmp__(y) <==> cmp(x,y)"),
TPSLOT("__repr__", tp_repr, slot_tp_repr, wrap_unaryfunc, "x.__repr__() <==> repr(x)"),
TPSLOT("__hash__", tp_hash, slot_tp_hash, wrap_hashfunc, "x.__hash__() <==> hash(x)"),
......@@ -2596,8 +2667,6 @@ extern "C" int PyType_Ready(PyTypeObject* cls) noexcept {
// unhandled fields:
RELEASE_ASSERT(cls->tp_compare == NULL, "");
RELEASE_ASSERT(cls->tp_getattro == NULL || cls->tp_getattro == PyObject_GenericGetAttr, "");
int ALLOWABLE_FLAGS = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_CHECKTYPES
| Py_TPFLAGS_HAVE_NEWBUFFER;
ALLOWABLE_FLAGS |= Py_TPFLAGS_INT_SUBCLASS | Py_TPFLAGS_LONG_SUBCLASS | Py_TPFLAGS_LIST_SUBCLASS
......
......@@ -1427,6 +1427,8 @@ public:
bool visit_functiondef(AST_FunctionDef* node) override {
auto def = new AST_FunctionDef();
def->lineno = node->lineno;
def->col_offset = node->col_offset;
def->name = node->name;
def->body = node->body; // expensive vector copy
// Decorators are evaluated before the defaults, so this *must* go before remapArguments().
......
......@@ -969,9 +969,11 @@ Box* builtinRound(Box* _number, Box* _ndigits) {
throwCAPIException();
}
Box* builtinCmp(Box* lhs, Box* rhs) {
fatalOrError(PyExc_NotImplementedError, "unimplemented");
Box* builtinCmp(Box* a, Box* b) {
int c;
if (PyObject_Cmp(a, b, &c) < 0)
throwCAPIException();
return PyInt_FromLong((long)c);
}
Box* builtinApply(Box* func, Box* args, Box* keywords) {
......
......@@ -105,7 +105,7 @@ public:
RELEASE_ASSERT(_self->cls == thread_lock_cls, "");
BoxedThreadLock* self = static_cast<BoxedThreadLock*>(_self);
RELEASE_ASSERT(_waitflag->cls == int_cls, "");
RELEASE_ASSERT(isSubclass(_waitflag->cls, int_cls), "");
int waitflag = static_cast<BoxedInt*>(_waitflag)->n;
// Copied + adapted from CPython:
......
......@@ -306,44 +306,6 @@ extern "C" int PyObject_DelItem(PyObject* o, PyObject* key) noexcept {
return -1;
}
extern "C" PyObject* PyObject_RichCompare(PyObject* o1, PyObject* o2, int opid) noexcept {
int translated_op;
switch (opid) {
case Py_LT:
translated_op = AST_TYPE::Lt;
break;
case Py_LE:
translated_op = AST_TYPE::LtE;
break;
case Py_EQ:
translated_op = AST_TYPE::Eq;
break;
case Py_NE:
translated_op = AST_TYPE::NotEq;
break;
case Py_GT:
translated_op = AST_TYPE::Gt;
break;
case Py_GE:
translated_op = AST_TYPE::GtE;
break;
default:
fatalOrError(PyExc_NotImplementedError, "unimplemented");
return nullptr;
};
try {
return compare(o1, o2, translated_op);
} catch (ExcInfo e) {
setCAPIException(e);
return NULL;
}
}
extern "C" {
int _Py_SwappedOp[] = { Py_GT, Py_GE, Py_EQ, Py_NE, Py_LT, Py_LE };
}
extern "C" long PyObject_Hash(PyObject* o) noexcept {
try {
return hash(o)->n;
......@@ -1374,6 +1336,44 @@ static Box* methodGetDoc(Box* b, void*) {
return None;
}
/* extension modules might be compiled with GC support so these
functions must always be available */
#undef PyObject_GC_Track
#undef PyObject_GC_UnTrack
#undef PyObject_GC_Del
#undef _PyObject_GC_Malloc
extern "C" PyObject* _PyObject_GC_Malloc(size_t basicsize) noexcept {
Box* r = ((PyObject*)PyObject_MALLOC(basicsize));
RELEASE_ASSERT(gc::isValidGCObject(r), "");
return r;
}
#undef _PyObject_GC_New
extern "C" PyObject* _PyObject_GC_New(PyTypeObject* tp) noexcept {
PyObject* op = _PyObject_GC_Malloc(_PyObject_SIZE(tp));
if (op != NULL)
op = PyObject_INIT(op, tp);
RELEASE_ASSERT(gc::isValidGCObject(op), "");
return op;
}
extern "C" PyVarObject* _PyObject_GC_NewVar(PyTypeObject* tp, Py_ssize_t nitems) noexcept {
const size_t size = _PyObject_VAR_SIZE(tp, nitems);
PyVarObject* op = (PyVarObject*)_PyObject_GC_Malloc(size);
if (op != NULL)
op = PyObject_INIT_VAR(op, tp, nitems);
RELEASE_ASSERT(gc::isValidGCObject(op), "");
return op;
}
extern "C" void _Py_FatalError(const char* fmt, const char* function, const char* message) {
fprintf(stderr, fmt, function, message);
fflush(stderr); /* it helps in Windows debug build */
abort();
}
void setupCAPI() {
capifunc_cls->giveAttr("__repr__",
new BoxedFunction(boxRTFunction((void*)BoxedCApiFunction::__repr__, UNKNOWN, 1)));
......
......@@ -51,6 +51,20 @@ public:
return boxString(static_cast<BoxedCode*>(b)->f->source->fn);
}
static Box* firstlineno(Box* b, void*) {
RELEASE_ASSERT(b->cls == code_cls, "");
BoxedCode* code = static_cast<BoxedCode*>(b);
CLFunction* cl = code->f;
if (!cl->source) {
// I don't think it really matters what we return here;
// in CPython, builtin functions don't have code objects.
return boxInt(-1);
}
return boxInt(cl->source->ast->lineno);
}
static Box* argcount(Box* b, void*) {
RELEASE_ASSERT(b->cls == code_cls, "");
......@@ -114,6 +128,8 @@ void setupCode() {
code_cls->giveAttr("co_name", new (pyston_getset_cls) BoxedGetsetDescriptor(BoxedCode::name, NULL, NULL));
code_cls->giveAttr("co_filename", new (pyston_getset_cls) BoxedGetsetDescriptor(BoxedCode::filename, NULL, NULL));
code_cls->giveAttr("co_firstlineno",
new (pyston_getset_cls) BoxedGetsetDescriptor(BoxedCode::firstlineno, NULL, NULL));
code_cls->giveAttr("co_argcount", new (pyston_getset_cls) BoxedGetsetDescriptor(BoxedCode::argcount, NULL, NULL));
code_cls->giveAttr("co_varnames", new (pyston_getset_cls) BoxedGetsetDescriptor(BoxedCode::varnames, NULL, NULL));
code_cls->giveAttr("co_flags", new (pyston_getset_cls) BoxedGetsetDescriptor(BoxedCode::flags, NULL, NULL));
......
......@@ -690,7 +690,14 @@ Box* impFindModule(Box* _name, BoxedList* path) {
return BoxedTuple::create({ None, path, BoxedTuple::create({ mode, mode, boxInt(sr.type) }) });
}
Py_FatalError("unimplemented");
if (sr.type == SearchResult::C_EXTENSION) {
Box* path = boxString(sr.path);
Box* mode = boxStrConstant("rb");
Box* f = runtimeCall(file_cls, ArgPassSpec(2), path, mode, NULL, NULL, NULL);
return BoxedTuple::create({ f, path, BoxedTuple::create({ boxStrConstant(".so"), mode, boxInt(sr.type) }) });
}
RELEASE_ASSERT(0, "unknown type: %d", sr.type);
}
Box* impLoadModule(Box* _name, Box* _file, Box* _pathname, Box** args) {
......@@ -724,6 +731,26 @@ Box* impLoadModule(Box* _name, Box* _file, Box* _pathname, Box** args) {
Py_FatalError("unimplemented");
}
Box* impLoadDynamic(Box* _name, Box* _pathname, Box* _file) {
RELEASE_ASSERT(_name->cls == str_cls, "");
RELEASE_ASSERT(_pathname->cls == str_cls, "");
RELEASE_ASSERT(_file == None, "");
BoxedString* name = (BoxedString*)_name;
BoxedString* pathname = (BoxedString*)_pathname;
const char* lastdot = strrchr(name->s.data(), '.');
const char* shortname;
if (lastdot == NULL) {
shortname = name->s.data();
} else {
shortname = lastdot + 1;
}
return importCExtension(name->s, shortname, pathname->s);
}
Box* impGetSuffixes() {
BoxedList* list = new BoxedList;
// For now only add *.py
......@@ -772,9 +799,12 @@ void setupImport() {
CLFunction* load_module_func = boxRTFunction((void*)impLoadModule, UNKNOWN, 4,
ParamNames({ "name", "file", "pathname", "description" }, "", ""));
imp_module->giveAttr("load_module", new BoxedBuiltinFunctionOrMethod(load_module_func, "load_module"));
CLFunction* load_dynamic_func = boxRTFunction((void*)impLoadDynamic, UNKNOWN, 3, 1, false, false,
ParamNames({ "name", "pathname", "file" }, "", ""));
imp_module->giveAttr("load_dynamic", new BoxedBuiltinFunctionOrMethod(load_dynamic_func, "load_dynamic", { None }));
imp_module->giveAttr("get_suffixes", new BoxedBuiltinFunctionOrMethod(
boxRTFunction((void*)impGetSuffixes, UNKNOWN, 0), "get_suffixes"));
imp_module->giveAttr("acquire_lock", new BoxedBuiltinFunctionOrMethod(boxRTFunction((void*)impAcquireLock, NONE, 0),
......
......@@ -325,6 +325,7 @@ BoxedClass::BoxedClass(BoxedClass* base, gcvisit_func gc_visit, int attrs_offset
tp_flags |= Py_TPFLAGS_HAVE_CLASS;
tp_flags |= Py_TPFLAGS_HAVE_GC;
tp_flags |= Py_TPFLAGS_HAVE_WEAKREFS;
tp_flags |= Py_TPFLAGS_HAVE_RICHCOMPARE;
if (base && (base->tp_flags & Py_TPFLAGS_HAVE_NEWBUFFER))
tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER;
......
......@@ -2273,6 +2273,7 @@ void setupRuntime() {
PyType_Ready(&PyByteArrayIter_Type);
PyType_Ready(&PyCapsule_Type);
PyType_Ready(&PyCallIter_Type);
PyType_Ready(&PyCObject_Type);
initerrno();
init_sha();
......
# expected: fail
# - misc issues
import os
import sys
import subprocess
import shutil
VIRTUALENV_SCRIPT = os.path.dirname(__file__) + "/virtualenv/virtualenv.py"
if os.path.exists("test_env"):
print "Removing the existing 'test_env/' directory"
subprocess.check_call(["rm", "-rf", "test_env"])
# shutil follows symlinks to directories, and deletes whatever those contain.
# shutil.rmtree("test_env")
args = [sys.executable, VIRTUALENV_SCRIPT, "-p", sys.executable, "test_env"]
print "Running", args
subprocess.check_call(args)
sh_script = """
set -e
. test_env/bin/activate
set -ux
python -c 'import __future__'
python -c 'import sys; print sys.executable'
pip install bcrypt==1.1.0
python -c 'import bcrypt; assert bcrypt.__version__ == "1.1.0"; assert bcrypt.hashpw("password1", "$2a$12$0123456789012345678901").endswith("I1hdtg4K"); print "bcrypt seems to work"'
""".strip()
# print sh_script
subprocess.check_call(["sh", "-c", sh_script])
......@@ -21,9 +21,12 @@ set -e
set -ux
python -c 'import __future__'
python -c 'import sys; print sys.executable'
pip install six==1.9.0 cffi==0.9.2
python -c 'import six; print six.__version__'
pip install bcrypt==1.1.0
python -c 'import bcrypt; assert bcrypt.__version__ == "1.1.0"; assert bcrypt.hashpw("password1", "$2a$12$0123456789012345678901").endswith("I1hdtg4K"); print "bcrypt seems to work"'
""".strip()
# print sh_script
subprocess.check_call(["sh", "-c", sh_script])
print
print "PASSED"
class C(object):
def __eq__(self, rhs):
print "eq", type(self), type(rhs)
return False
def __lt__(self, rhs):
print "lt", type(self), type(rhs)
return False
def __gt__(self, rhs):
print "gt", type(self), type(rhs)
return True
class D(C):
def __cmp__(self, rhs):
print "cmp", type(self), type(rhs)
return 0
l = [C(), D()]
for lhs in l:
for rhs in l:
r = cmp(lhs, rhs)
print type(lhs), type(rhs), r
......@@ -4,6 +4,7 @@ def f(a, b=2, *args, **kw):
c = f.func_code
print c.co_argcount
print c.co_varnames
print c.co_firstlineno
print hex(c.co_flags & 0x0c)
def f(l=[]):
......@@ -15,3 +16,4 @@ f()
def f():
pass
print f.func_defaults
print f.func_code.co_firstlineno
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