mirror of
https://github.com/pocketpy/pocketpy
synced 2025-11-09 13:10:17 +00:00
Compare commits
3 Commits
e84f86b2de
...
9ecfc0196f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9ecfc0196f | ||
|
|
cef0a4a254 | ||
|
|
c99f0ee919 |
10
.github/workflows/main.yml
vendored
10
.github/workflows/main.yml
vendored
@ -92,10 +92,18 @@ jobs:
|
||||
uses: jirutka/setup-alpine@v1
|
||||
with:
|
||||
arch: x86
|
||||
packages: gcc g++ make cmake libc-dev linux-headers python3
|
||||
packages: gcc g++ make cmake libc-dev linux-headers python3 gdb
|
||||
- name: Build and Test
|
||||
run: |
|
||||
uname -m
|
||||
|
||||
python cmake_build.py Debug
|
||||
# gdb_commands.txt
|
||||
echo "run" > gdb_commands.txt
|
||||
echo "backtrace" >> gdb_commands.txt
|
||||
echo "quit" >> gdb_commands.txt
|
||||
gdb -batch -x gdb_commands.txt --args ./main tests/77_builtin_func_1.py
|
||||
|
||||
python cmake_build.py
|
||||
python scripts/run_tests.py
|
||||
python scripts/run_tests.py benchmark
|
||||
|
||||
@ -20,3 +20,11 @@ May be one of:
|
||||
### `sys.argv`
|
||||
|
||||
The command line arguments. Set by `py_sys_setargv`.
|
||||
|
||||
### `sys.setrecursionlimit(limit: int)`
|
||||
|
||||
Set the maximum depth of the Python interpreter stack to `limit`. This limit prevents infinite recursion from causing an overflow of the C stack and crashing the interpreter.
|
||||
|
||||
### `sys.getrecursionlimit() -> int`
|
||||
|
||||
Return the current value of the recursion limit.
|
||||
|
||||
@ -38,6 +38,10 @@ typedef struct VM {
|
||||
|
||||
py_TValue last_retval;
|
||||
py_TValue curr_exception;
|
||||
|
||||
int recursion_depth;
|
||||
int max_recursion_depth;
|
||||
|
||||
bool is_curr_exc_handled; // handled by try-except block but not cleared yet
|
||||
|
||||
py_TValue reg[8]; // users' registers
|
||||
|
||||
@ -495,10 +495,12 @@ PK_API py_StackRef py_pushtmp();
|
||||
/// If return false: `[self] -> [self]` (no change).
|
||||
PK_API bool py_pushmethod(py_Name name);
|
||||
/// Call a callable object via pocketpy's calling convention.
|
||||
/// You need to prepare the stack using this form: `callable, self/nil, arg1, arg2, ..., k1, v1, k2,
|
||||
/// v2, ...` `argc` is the number of positional arguments excluding `self`. `kwargc` is the number
|
||||
/// of keyword arguments, i.e. the number of key-value pairs. The result will be set to
|
||||
/// `py_retval()`. The stack size will be reduced by `2 + argc + kwargc * 2`.
|
||||
/// You need to prepare the stack using the following format:
|
||||
/// `callable, self/nil, arg1, arg2, ..., k1, v1, k2, v2, ...`.
|
||||
/// `argc` is the number of positional arguments excluding `self`.
|
||||
/// `kwargc` is the number of keyword arguments.
|
||||
/// The result will be set to `py_retval()`.
|
||||
/// The stack size will be reduced by `2 + argc + kwargc * 2`.
|
||||
PK_API bool py_vectorcall(uint16_t argc, uint16_t kwargc) PY_RAISE PY_RETURN;
|
||||
/// Evaluate an expression and push the result to the stack.
|
||||
/// This function is used for testing.
|
||||
@ -739,7 +741,7 @@ enum py_PredefinedType {
|
||||
tp_KeyboardInterrupt,
|
||||
tp_StopIteration,
|
||||
tp_SyntaxError,
|
||||
tp_StackOverflowError,
|
||||
tp_RecursionError,
|
||||
tp_OSError,
|
||||
tp_NotImplementedError,
|
||||
tp_TypeError,
|
||||
|
||||
@ -8,9 +8,12 @@ def test_file(filepath, cpython=False):
|
||||
if cpython:
|
||||
return os.system("python " + filepath) == 0
|
||||
if sys.platform == 'win32':
|
||||
return os.system("main.exe " + filepath) == 0
|
||||
code = os.system("main.exe " + filepath)
|
||||
else:
|
||||
return os.system("./main " + filepath) == 0
|
||||
code = os.system("./main " + filepath)
|
||||
if code != 0:
|
||||
print('Return code:', code)
|
||||
return code == 0
|
||||
|
||||
def test_dir(path):
|
||||
print("Testing directory:", path)
|
||||
|
||||
@ -13,14 +13,6 @@ static bool stack_format_object(VM* self, c11_sv spec);
|
||||
#define CHECK_RETURN_FROM_EXCEPT_OR_FINALLY() \
|
||||
if(self->is_curr_exc_handled) py_clearexc(NULL)
|
||||
|
||||
#define CHECK_STACK_OVERFLOW() \
|
||||
do { \
|
||||
if(self->stack.sp > self->stack.end) { \
|
||||
py_exception(tp_StackOverflowError, ""); \
|
||||
goto __ERROR; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define DISPATCH() \
|
||||
do { \
|
||||
frame->ip++; \
|
||||
@ -61,6 +53,7 @@ static bool stack_format_object(VM* self, c11_sv spec);
|
||||
*SECOND() = *THIRD(); \
|
||||
} while(0)
|
||||
|
||||
// Must use a DISPATCH() after vectorcall_opcall() immediately!
|
||||
#define vectorcall_opcall(argc, kwargc) \
|
||||
do { \
|
||||
FrameResult res = VM__vectorcall(self, (argc), (kwargc), true); \
|
||||
@ -93,6 +86,15 @@ FrameResult VM__run_top_frame(VM* self) {
|
||||
while(true) {
|
||||
Bytecode byte;
|
||||
__NEXT_FRAME:
|
||||
if(self->recursion_depth >= self->max_recursion_depth) {
|
||||
py_exception(tp_RecursionError, "maximum recursion depth exceeded");
|
||||
goto __ERROR;
|
||||
}
|
||||
if(self->stack.sp >= self->stack.end) {
|
||||
c11__abort(
|
||||
"Stack overflow! Please increase PK_VM_STACK_SIZE or reduce the max recursion limit.");
|
||||
}
|
||||
|
||||
codes = frame->co->codes.data;
|
||||
frame->ip++;
|
||||
|
||||
@ -149,39 +151,32 @@ FrameResult VM__run_top_frame(VM* self) {
|
||||
DISPATCH();
|
||||
/*****************************************/
|
||||
case OP_LOAD_CONST: {
|
||||
CHECK_STACK_OVERFLOW();
|
||||
PUSH(c11__at(py_TValue, &frame->co->consts, byte.arg));
|
||||
DISPATCH();
|
||||
}
|
||||
case OP_LOAD_NONE: {
|
||||
CHECK_STACK_OVERFLOW();
|
||||
py_newnone(SP()++);
|
||||
DISPATCH();
|
||||
}
|
||||
case OP_LOAD_TRUE: {
|
||||
CHECK_STACK_OVERFLOW();
|
||||
py_newbool(SP()++, true);
|
||||
DISPATCH();
|
||||
}
|
||||
case OP_LOAD_FALSE: {
|
||||
CHECK_STACK_OVERFLOW();
|
||||
py_newbool(SP()++, false);
|
||||
DISPATCH();
|
||||
}
|
||||
/*****************************************/
|
||||
case OP_LOAD_SMALL_INT: {
|
||||
CHECK_STACK_OVERFLOW();
|
||||
py_newint(SP()++, (int16_t)byte.arg);
|
||||
DISPATCH();
|
||||
}
|
||||
/*****************************************/
|
||||
case OP_LOAD_ELLIPSIS: {
|
||||
CHECK_STACK_OVERFLOW();
|
||||
py_newellipsis(SP()++);
|
||||
DISPATCH();
|
||||
}
|
||||
case OP_LOAD_FUNCTION: {
|
||||
CHECK_STACK_OVERFLOW();
|
||||
FuncDecl_ decl = c11__getitem(FuncDecl_, &frame->co->func_decls, byte.arg);
|
||||
Function* ud = py_newobject(SP(), tp_function, 0, sizeof(Function));
|
||||
Function__ctor(ud, decl, frame->module, frame->globals);
|
||||
@ -352,8 +347,7 @@ FrameResult VM__run_top_frame(VM* self) {
|
||||
} else {
|
||||
INSERT_THIRD(); // [?, a, b]
|
||||
*THIRD() = *magic; // [__getitem__, a, b]
|
||||
if(!py_vectorcall(1, 0)) goto __ERROR;
|
||||
PUSH(py_retval());
|
||||
vectorcall_opcall(1, 0);
|
||||
}
|
||||
DISPATCH();
|
||||
}
|
||||
@ -413,7 +407,7 @@ FrameResult VM__run_top_frame(VM* self) {
|
||||
if(!py_callcfunc(magic->_cfunc, 3, THIRD())) goto __ERROR;
|
||||
STACK_SHRINK(4);
|
||||
} else {
|
||||
*FOURTH() = *magic; // [__selitem__, a, b, val]
|
||||
*FOURTH() = *magic; // [__setitem__, a, b, val]
|
||||
if(!py_vectorcall(2, 0)) goto __ERROR;
|
||||
}
|
||||
DISPATCH();
|
||||
@ -503,8 +497,7 @@ FrameResult VM__run_top_frame(VM* self) {
|
||||
py_newnil(SP()++); // [complex, NULL]
|
||||
py_newint(SP()++, 0); // [complex, NULL, 0]
|
||||
*SP()++ = tmp; // [complex, NULL, 0, x]
|
||||
if(!py_vectorcall(2, 0)) goto __ERROR;
|
||||
PUSH(py_retval());
|
||||
vectorcall_opcall(2, 0);
|
||||
DISPATCH();
|
||||
}
|
||||
case OP_BUILD_BYTES: {
|
||||
@ -1079,8 +1072,7 @@ FrameResult VM__run_top_frame(VM* self) {
|
||||
TOP()->type);
|
||||
goto __ERROR;
|
||||
}
|
||||
if(!py_vectorcall(0, 0)) goto __ERROR;
|
||||
PUSH(py_retval());
|
||||
vectorcall_opcall(0, 0);
|
||||
DISPATCH();
|
||||
}
|
||||
case OP_WITH_EXIT: {
|
||||
|
||||
@ -64,6 +64,7 @@ static bool generator__next__(int argc, py_Ref argv) {
|
||||
}
|
||||
vm->stack.sp = ud->frame->p0;
|
||||
vm->top_frame = vm->top_frame->f_back;
|
||||
vm->recursion_depth--;
|
||||
ud->state = 1;
|
||||
return true;
|
||||
} else {
|
||||
|
||||
@ -71,6 +71,10 @@ void VM__ctor(VM* self) {
|
||||
|
||||
self->last_retval = *py_NIL();
|
||||
self->curr_exception = *py_NIL();
|
||||
|
||||
self->recursion_depth = 0;
|
||||
self->max_recursion_depth = 1000;
|
||||
|
||||
self->is_curr_exc_handled = false;
|
||||
|
||||
self->ctx = NULL;
|
||||
@ -162,7 +166,7 @@ void VM__ctor(VM* self) {
|
||||
py_setdict(&self->builtins, py_name("StopIteration"), py_tpobject(tp_StopIteration));
|
||||
|
||||
INJECT_BUILTIN_EXC(SyntaxError, tp_Exception);
|
||||
INJECT_BUILTIN_EXC(StackOverflowError, tp_Exception);
|
||||
INJECT_BUILTIN_EXC(RecursionError, tp_Exception);
|
||||
INJECT_BUILTIN_EXC(OSError, tp_Exception);
|
||||
INJECT_BUILTIN_EXC(NotImplementedError, tp_Exception);
|
||||
INJECT_BUILTIN_EXC(TypeError, tp_Exception);
|
||||
@ -265,6 +269,7 @@ void VM__dtor(VM* self) {
|
||||
void VM__push_frame(VM* self, py_Frame* frame) {
|
||||
frame->f_back = self->top_frame;
|
||||
self->top_frame = frame;
|
||||
self->recursion_depth++;
|
||||
if(self->trace_info.func) self->trace_info.func(frame, TRACE_EVENT_PUSH);
|
||||
}
|
||||
|
||||
@ -277,6 +282,7 @@ void VM__pop_frame(VM* self) {
|
||||
// pop frame and delete
|
||||
self->top_frame = frame->f_back;
|
||||
Frame__delete(frame);
|
||||
self->recursion_depth--;
|
||||
}
|
||||
|
||||
static void _clip_int(int* value, int min, int max) {
|
||||
@ -469,12 +475,6 @@ FrameResult VM__vectorcall(VM* self, uint16_t argc, uint16_t kwargc, bool opcall
|
||||
py_Ref argv = p0 + 1 + (int)py_isnil(p0 + 1);
|
||||
|
||||
if(p0->type == tp_function) {
|
||||
// check stack overflow
|
||||
if(self->stack.sp > self->stack.end) {
|
||||
py_exception(tp_StackOverflowError, "");
|
||||
return RES_ERROR;
|
||||
}
|
||||
|
||||
Function* fn = py_touserdata(p0);
|
||||
const CodeObject* co = &fn->decl->code;
|
||||
|
||||
|
||||
@ -240,9 +240,28 @@ void pk__add_module_io() {}
|
||||
|
||||
#endif
|
||||
|
||||
static bool sys_setrecursionlimit(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(1);
|
||||
PY_CHECK_ARG_TYPE(0, tp_int);
|
||||
int limit = py_toint(py_arg(0));
|
||||
if(limit <= pk_current_vm->recursion_depth) return ValueError("the limit is too low");
|
||||
pk_current_vm->max_recursion_depth = limit;
|
||||
py_newnone(py_retval());
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool sys_getrecursionlimit(int argc, py_Ref argv) {
|
||||
PY_CHECK_ARGC(0);
|
||||
py_newint(py_retval(), pk_current_vm->max_recursion_depth);
|
||||
return true;
|
||||
}
|
||||
|
||||
void pk__add_module_sys() {
|
||||
py_Ref mod = py_newmodule("sys");
|
||||
py_newstr(py_emplacedict(mod, py_name("platform")), PY_SYS_PLATFORM_STRING);
|
||||
py_newstr(py_emplacedict(mod, py_name("version")), PK_VERSION);
|
||||
py_newlist(py_emplacedict(mod, py_name("argv")));
|
||||
|
||||
py_bindfunc(mod, "setrecursionlimit", sys_setrecursionlimit);
|
||||
py_bindfunc(mod, "getrecursionlimit", sys_getrecursionlimit);
|
||||
}
|
||||
|
||||
@ -57,14 +57,14 @@ class TestSuperNoBaseMethod(TestSuperBase):
|
||||
try:
|
||||
t = TestSuperNoParent()
|
||||
print('未能拦截错误')
|
||||
exit(1)
|
||||
exit(2)
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
t = TestSuperNoBaseMethod()
|
||||
print('未能拦截错误')
|
||||
exit(1)
|
||||
exit(3)
|
||||
except:
|
||||
pass
|
||||
|
||||
@ -83,7 +83,7 @@ try:
|
||||
c = C()
|
||||
c.method()
|
||||
print('未能拦截错误')
|
||||
exit(1)
|
||||
exit(4)
|
||||
except:
|
||||
pass
|
||||
|
||||
@ -91,7 +91,7 @@ try:
|
||||
d = D()
|
||||
d.method()
|
||||
print('未能拦截错误')
|
||||
exit(1)
|
||||
exit(5)
|
||||
except:
|
||||
pass
|
||||
|
||||
@ -134,14 +134,14 @@ assert type(hash(a)) is int
|
||||
try:
|
||||
hash({1:1})
|
||||
print('未能拦截错误')
|
||||
exit(1)
|
||||
exit(6)
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
hash([1])
|
||||
print('未能拦截错误')
|
||||
exit(1)
|
||||
exit(7)
|
||||
except:
|
||||
pass
|
||||
|
||||
@ -166,7 +166,7 @@ repr(A())
|
||||
try:
|
||||
range(1,2,3,4)
|
||||
print('未能拦截错误, 在测试 range')
|
||||
exit(1)
|
||||
exit(8)
|
||||
except:
|
||||
pass
|
||||
|
||||
@ -174,14 +174,14 @@ except:
|
||||
try:
|
||||
int('asad')
|
||||
print('未能拦截错误, 在测试 int')
|
||||
exit(1)
|
||||
exit(9)
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
int(123, 16)
|
||||
print('未能拦截错误, 在测试 int')
|
||||
exit(1)
|
||||
exit(10)
|
||||
except:
|
||||
pass
|
||||
|
||||
@ -192,14 +192,14 @@ assert type(11%2) is int
|
||||
try:
|
||||
float('asad')
|
||||
print('未能拦截错误, 在测试 float')
|
||||
exit(1)
|
||||
exit(11)
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
float([])
|
||||
print('未能拦截错误, 在测试 float')
|
||||
exit(1)
|
||||
exit(12)
|
||||
except:
|
||||
pass
|
||||
|
||||
@ -213,7 +213,7 @@ assert type('25363546'.index('63')) is int
|
||||
try:
|
||||
'25363546'.index('err')
|
||||
print('未能拦截错误, 在测试 str.index')
|
||||
exit(1)
|
||||
exit(13)
|
||||
except:
|
||||
pass
|
||||
|
||||
@ -228,7 +228,7 @@ assert '25363546'.find('err') == -1
|
||||
try:
|
||||
list(1,2)
|
||||
print('未能拦截错误, 在测试 list')
|
||||
exit(1)
|
||||
exit(14)
|
||||
except:
|
||||
pass
|
||||
|
||||
@ -238,7 +238,7 @@ assert type([1,2,3,4,5].index(4)) is int
|
||||
try:
|
||||
[1,2,3,4,5].index(6)
|
||||
print('未能拦截错误, 在测试 list.index')
|
||||
exit(1)
|
||||
exit(15)
|
||||
except:
|
||||
pass
|
||||
|
||||
@ -249,7 +249,7 @@ except:
|
||||
try:
|
||||
[1,2,3,4,5].remove(6)
|
||||
print('未能拦截错误, 在测试 list.remove')
|
||||
exit(1)
|
||||
exit(16)
|
||||
except:
|
||||
pass
|
||||
|
||||
@ -259,7 +259,7 @@ except:
|
||||
try:
|
||||
[1,2,3,4,5].pop(1,2,3,4)
|
||||
print('未能拦截错误, 在测试 list.pop')
|
||||
exit(1)
|
||||
exit(17)
|
||||
except:
|
||||
pass
|
||||
|
||||
@ -275,7 +275,7 @@ assert type(12 * [12]) is list
|
||||
try:
|
||||
tuple(1,2)
|
||||
print('未能拦截错误, 在测试 tuple')
|
||||
exit(1)
|
||||
exit(18)
|
||||
except:
|
||||
pass
|
||||
|
||||
@ -305,287 +305,3 @@ assert type(repr(bytes([0x41, 0x42, 0x43]))) is str
|
||||
|
||||
# /************ slice ************/
|
||||
assert type(slice(0.1, 0.2, 0.3)) is slice
|
||||
|
||||
|
||||
# 未完全测试准确性-----------------------------------------------
|
||||
# 116: 1529: bind_property(_t(tp_slice), "start", [](VM* vm, ArgsView args){
|
||||
# #####: 1530: return CAST(Slice&, args[0]).start;
|
||||
# -: 1531: });
|
||||
# 116: 1532: bind_property(_t(tp_slice), "stop", [](VM* vm, ArgsView args){
|
||||
# #####: 1533: return CAST(Slice&, args[0]).stop;
|
||||
# -: 1534: });
|
||||
# 116: 1535: bind_property(_t(tp_slice), "step", [](VM* vm, ArgsView args){
|
||||
# #####: 1536: return CAST(Slice&, args[0]).step;
|
||||
# -: 1537: });
|
||||
s = slice(1, 2, 3)
|
||||
assert type(s) is slice
|
||||
assert s.start == 1
|
||||
assert s.stop == 2
|
||||
assert s.step == 3
|
||||
|
||||
# 未完全测试准确性-----------------------------------------------
|
||||
# test slice.__repr__
|
||||
assert type(repr(slice(1,1,1))) is str
|
||||
|
||||
# /************ namedict ************/
|
||||
# # test namedict.keys:
|
||||
# class A():
|
||||
# def __init__(self):
|
||||
# self.a = 10
|
||||
# def method(self):
|
||||
# pass
|
||||
|
||||
|
||||
# my_namedict = A().__dict__
|
||||
# assert type(my_namedict.keys()) is list
|
||||
|
||||
# # test namedict.values:
|
||||
# class A():
|
||||
# def __init__(self):
|
||||
# self.a = 10
|
||||
# def method(self):
|
||||
# pass
|
||||
|
||||
|
||||
# my_namedict = A().__dict__
|
||||
# assert type(my_namedict.values()) is list
|
||||
|
||||
|
||||
# class A():
|
||||
# def __init__(self):
|
||||
# self.a = 10
|
||||
# def method(self):
|
||||
# pass
|
||||
|
||||
|
||||
# my_namedict = A().__dict__
|
||||
# assert type(len(my_namedict)) is int
|
||||
|
||||
|
||||
class A():
|
||||
def __init__(self):
|
||||
self.a = 10
|
||||
def method(self):
|
||||
pass
|
||||
|
||||
|
||||
my_namedict = A().__dict__
|
||||
|
||||
try:
|
||||
hash(my_namedict)
|
||||
print('未能拦截错误, 在测试 namedict.__hash__')
|
||||
exit(1)
|
||||
except TypeError:
|
||||
pass
|
||||
|
||||
a = hash(object()) # object is hashable
|
||||
a = hash(A()) # A is hashable
|
||||
class B:
|
||||
def __eq__(self, o): return True
|
||||
def __ne__(self, o): return False
|
||||
|
||||
try:
|
||||
hash(B())
|
||||
print('未能拦截错误, 在测试 B.__hash__')
|
||||
exit(1)
|
||||
except TypeError:
|
||||
pass
|
||||
|
||||
# 未完全测试准确性-----------------------------------------------
|
||||
# test namedict.__repr__:
|
||||
class A():
|
||||
def __init__(self):
|
||||
self.a = 10
|
||||
def method(self):
|
||||
pass
|
||||
|
||||
|
||||
my_namedict = A().__dict__
|
||||
assert type(repr(my_namedict)) is str
|
||||
|
||||
|
||||
# /************ dict ************/
|
||||
# 未完全测试准确性-----------------------------------------------
|
||||
# test dict:
|
||||
assert type(dict([(1,2)])) is dict
|
||||
|
||||
try:
|
||||
dict([(1, 2, 3)])
|
||||
print('未能拦截错误, 在测试 dict')
|
||||
exit(1)
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
dict([(1, 2)], 1)
|
||||
print('未能拦截错误, 在测试 dict')
|
||||
exit(1)
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
hash(dict([(1,2)]))
|
||||
print('未能拦截错误, 在测试 dict.__hash__')
|
||||
exit(1)
|
||||
except:
|
||||
pass
|
||||
|
||||
# test dict.__iter__
|
||||
for k in {1:2, 2:3, 3:4}.keys():
|
||||
assert k in [1,2,3]
|
||||
|
||||
# 未完全测试准确性-----------------------------------------------
|
||||
# test dict.get
|
||||
|
||||
assert {1:2, 3:4}.get(1) == 2
|
||||
assert {1:2, 3:4}.get(2) is None
|
||||
assert {1:2, 3:4}.get(20, 100) == 100
|
||||
|
||||
try:
|
||||
{1:2, 3:4}.get(1,1, 1)
|
||||
print('未能拦截错误, 在测试 dict.get')
|
||||
exit(1)
|
||||
except:
|
||||
pass
|
||||
|
||||
# 未完全测试准确性-----------------------------------------------
|
||||
# test dict.__repr__
|
||||
assert type(repr({1:2, 3:4})) is str
|
||||
|
||||
# /************ property ************/
|
||||
class A():
|
||||
def __init__(self):
|
||||
self._name = '123'
|
||||
|
||||
@property
|
||||
def value(self):
|
||||
return 2
|
||||
|
||||
def get_name(self):
|
||||
'''
|
||||
doc string 1
|
||||
'''
|
||||
return self._name
|
||||
|
||||
def set_name(self, val):
|
||||
'''
|
||||
doc string 2
|
||||
'''
|
||||
self._name = val
|
||||
|
||||
assert A().value == 2
|
||||
|
||||
A.name = property(A.get_name, A.set_name)
|
||||
|
||||
class Vector2:
|
||||
def __init__(self) -> None:
|
||||
self._x = 0
|
||||
|
||||
@property
|
||||
def x(self):
|
||||
return self._x
|
||||
|
||||
@x.setter
|
||||
def x(self, val):
|
||||
self._x = val
|
||||
|
||||
v = Vector2()
|
||||
assert v.x == 0
|
||||
v.x = 10
|
||||
assert v.x == 10
|
||||
|
||||
# function.__doc__
|
||||
def aaa():
|
||||
'12345'
|
||||
pass
|
||||
assert aaa.__doc__ == '12345'
|
||||
|
||||
# test callable
|
||||
assert callable(lambda: 1) is True # function
|
||||
assert callable(1) is False # int
|
||||
assert callable(object) is True # type
|
||||
assert callable(object()) is False
|
||||
assert callable([].append) is True # bound method
|
||||
assert callable([].__getitem__) is True # bound method
|
||||
|
||||
class A:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def __call__(self):
|
||||
pass
|
||||
|
||||
assert callable(A) is True # type
|
||||
assert callable(A()) is True # instance with __call__
|
||||
assert callable(A.__call__) is True # bound method
|
||||
assert callable(A.__init__) is True # bound method
|
||||
assert callable(print) is True # builtin function
|
||||
assert callable(isinstance) is True # builtin function
|
||||
|
||||
|
||||
assert id(0) is None
|
||||
assert id(2**62) is None
|
||||
|
||||
# test issubclass
|
||||
assert issubclass(int, int) is True
|
||||
assert issubclass(int, object) is True
|
||||
assert issubclass(object, int) is False
|
||||
assert issubclass(object, object) is True
|
||||
assert issubclass(int, type) is False
|
||||
assert issubclass(type, type) is True
|
||||
assert issubclass(float, int) is False
|
||||
|
||||
|
||||
def f(a, b):
|
||||
c = a
|
||||
del a
|
||||
return sum([b, c])
|
||||
|
||||
assert f(1, 2) == 3
|
||||
|
||||
# /************ module time ************/
|
||||
import time
|
||||
# test time.time
|
||||
assert type(time.time()) is float
|
||||
|
||||
local_t = time.localtime()
|
||||
assert type(local_t.tm_year) is int
|
||||
assert type(local_t.tm_mon) is int
|
||||
assert type(local_t.tm_mday) is int
|
||||
assert type(local_t.tm_hour) is int
|
||||
assert type(local_t.tm_min) is int
|
||||
assert type(local_t.tm_sec) is int
|
||||
assert type(local_t.tm_wday) is int
|
||||
assert type(local_t.tm_yday) is int
|
||||
assert type(local_t.tm_isdst) is int
|
||||
|
||||
# test time.sleep
|
||||
time.sleep(0.1)
|
||||
# test time.localtime
|
||||
assert type(time.localtime()) is time.struct_time
|
||||
|
||||
# test min/max
|
||||
assert min(1, 2) == 1
|
||||
assert min(1, 2, 3) == 1
|
||||
assert min([1, 2]) == 1
|
||||
assert min([1, 2], key=lambda x: -x) == 2
|
||||
|
||||
assert max(1, 2) == 2
|
||||
assert max(1, 2, 3) == 3
|
||||
assert max([1, 2]) == 2
|
||||
assert max([1, 2, 3], key=lambda x: -x) == 1
|
||||
|
||||
assert min([
|
||||
(3, 1),
|
||||
(1, 2),
|
||||
(1, 3),
|
||||
(1, 4),
|
||||
]) == (1, 2)
|
||||
|
||||
assert min(1, 2) == 1
|
||||
assert max(1, 2) == 2
|
||||
|
||||
exit()
|
||||
|
||||
dir_int = dir(int)
|
||||
assert dir_int[:4] == ['__add__', '__and__', '__base__', '__eq__']
|
||||
243
tests/77_builtin_func_2.py
Normal file
243
tests/77_builtin_func_2.py
Normal file
@ -0,0 +1,243 @@
|
||||
# 未完全测试准确性-----------------------------------------------
|
||||
# 116: 1529: bind_property(_t(tp_slice), "start", [](VM* vm, ArgsView args){
|
||||
# #####: 1530: return CAST(Slice&, args[0]).start;
|
||||
# -: 1531: });
|
||||
# 116: 1532: bind_property(_t(tp_slice), "stop", [](VM* vm, ArgsView args){
|
||||
# #####: 1533: return CAST(Slice&, args[0]).stop;
|
||||
# -: 1534: });
|
||||
# 116: 1535: bind_property(_t(tp_slice), "step", [](VM* vm, ArgsView args){
|
||||
# #####: 1536: return CAST(Slice&, args[0]).step;
|
||||
# -: 1537: });
|
||||
s = slice(1, 2, 3)
|
||||
assert type(s) is slice
|
||||
assert s.start == 1
|
||||
assert s.stop == 2
|
||||
assert s.step == 3
|
||||
|
||||
# 未完全测试准确性-----------------------------------------------
|
||||
# test slice.__repr__
|
||||
assert type(repr(slice(1,1,1))) is str
|
||||
|
||||
|
||||
class A():
|
||||
def __init__(self):
|
||||
self.a = 10
|
||||
def method(self):
|
||||
pass
|
||||
|
||||
|
||||
my_namedict = A().__dict__
|
||||
|
||||
try:
|
||||
hash(my_namedict)
|
||||
print('未能拦截错误, 在测试 namedict.__hash__')
|
||||
exit(1)
|
||||
except TypeError:
|
||||
pass
|
||||
|
||||
a = hash(object()) # object is hashable
|
||||
a = hash(A()) # A is hashable
|
||||
class B:
|
||||
def __eq__(self, o): return True
|
||||
def __ne__(self, o): return False
|
||||
|
||||
try:
|
||||
hash(B())
|
||||
print('未能拦截错误, 在测试 B.__hash__')
|
||||
exit(1)
|
||||
except TypeError:
|
||||
pass
|
||||
|
||||
# 未完全测试准确性-----------------------------------------------
|
||||
# test namedict.__repr__:
|
||||
class A():
|
||||
def __init__(self):
|
||||
self.a = 10
|
||||
def method(self):
|
||||
pass
|
||||
|
||||
|
||||
my_namedict = A().__dict__
|
||||
assert type(repr(my_namedict)) is str
|
||||
|
||||
|
||||
# /************ dict ************/
|
||||
# 未完全测试准确性-----------------------------------------------
|
||||
# test dict:
|
||||
assert type(dict([(1,2)])) is dict
|
||||
|
||||
try:
|
||||
dict([(1, 2, 3)])
|
||||
print('未能拦截错误, 在测试 dict')
|
||||
exit(1)
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
dict([(1, 2)], 1)
|
||||
print('未能拦截错误, 在测试 dict')
|
||||
exit(1)
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
hash(dict([(1,2)]))
|
||||
print('未能拦截错误, 在测试 dict.__hash__')
|
||||
exit(1)
|
||||
except:
|
||||
pass
|
||||
|
||||
# test dict.__iter__
|
||||
for k in {1:2, 2:3, 3:4}.keys():
|
||||
assert k in [1,2,3]
|
||||
|
||||
# 未完全测试准确性-----------------------------------------------
|
||||
# test dict.get
|
||||
|
||||
assert {1:2, 3:4}.get(1) == 2
|
||||
assert {1:2, 3:4}.get(2) is None
|
||||
assert {1:2, 3:4}.get(20, 100) == 100
|
||||
|
||||
try:
|
||||
{1:2, 3:4}.get(1,1, 1)
|
||||
print('未能拦截错误, 在测试 dict.get')
|
||||
exit(1)
|
||||
except:
|
||||
pass
|
||||
|
||||
# 未完全测试准确性-----------------------------------------------
|
||||
# test dict.__repr__
|
||||
assert type(repr({1:2, 3:4})) is str
|
||||
|
||||
# /************ property ************/
|
||||
class A():
|
||||
def __init__(self):
|
||||
self._name = '123'
|
||||
|
||||
@property
|
||||
def value(self):
|
||||
return 2
|
||||
|
||||
def get_name(self):
|
||||
'''
|
||||
doc string 1
|
||||
'''
|
||||
return self._name
|
||||
|
||||
def set_name(self, val):
|
||||
'''
|
||||
doc string 2
|
||||
'''
|
||||
self._name = val
|
||||
|
||||
assert A().value == 2
|
||||
|
||||
A.name = property(A.get_name, A.set_name)
|
||||
|
||||
class Vector2:
|
||||
def __init__(self) -> None:
|
||||
self._x = 0
|
||||
|
||||
@property
|
||||
def x(self):
|
||||
return self._x
|
||||
|
||||
@x.setter
|
||||
def x(self, val):
|
||||
self._x = val
|
||||
|
||||
v = Vector2()
|
||||
assert v.x == 0
|
||||
v.x = 10
|
||||
assert v.x == 10
|
||||
|
||||
# function.__doc__
|
||||
def aaa():
|
||||
'12345'
|
||||
pass
|
||||
assert aaa.__doc__ == '12345'
|
||||
|
||||
# test callable
|
||||
assert callable(lambda: 1) is True # function
|
||||
assert callable(1) is False # int
|
||||
assert callable(object) is True # type
|
||||
assert callable(object()) is False
|
||||
assert callable([].append) is True # bound method
|
||||
assert callable([].__getitem__) is True # bound method
|
||||
|
||||
class A:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def __call__(self):
|
||||
pass
|
||||
|
||||
assert callable(A) is True # type
|
||||
assert callable(A()) is True # instance with __call__
|
||||
assert callable(A.__call__) is True # bound method
|
||||
assert callable(A.__init__) is True # bound method
|
||||
assert callable(print) is True # builtin function
|
||||
assert callable(isinstance) is True # builtin function
|
||||
|
||||
|
||||
assert id(0) is None
|
||||
assert id(2**62) is None
|
||||
|
||||
# test issubclass
|
||||
assert issubclass(int, int) is True
|
||||
assert issubclass(int, object) is True
|
||||
assert issubclass(object, int) is False
|
||||
assert issubclass(object, object) is True
|
||||
assert issubclass(int, type) is False
|
||||
assert issubclass(type, type) is True
|
||||
assert issubclass(float, int) is False
|
||||
|
||||
|
||||
def f(a, b):
|
||||
c = a
|
||||
del a
|
||||
return sum([b, c])
|
||||
|
||||
assert f(1, 2) == 3
|
||||
|
||||
# /************ module time ************/
|
||||
import time
|
||||
# test time.time
|
||||
assert type(time.time()) is float
|
||||
|
||||
local_t = time.localtime()
|
||||
assert type(local_t.tm_year) is int
|
||||
assert type(local_t.tm_mon) is int
|
||||
assert type(local_t.tm_mday) is int
|
||||
assert type(local_t.tm_hour) is int
|
||||
assert type(local_t.tm_min) is int
|
||||
assert type(local_t.tm_sec) is int
|
||||
assert type(local_t.tm_wday) is int
|
||||
assert type(local_t.tm_yday) is int
|
||||
assert type(local_t.tm_isdst) is int
|
||||
|
||||
# test time.sleep
|
||||
time.sleep(0.1)
|
||||
# test time.localtime
|
||||
assert type(time.localtime()) is time.struct_time
|
||||
|
||||
# test min/max
|
||||
assert min(1, 2) == 1
|
||||
assert min(1, 2, 3) == 1
|
||||
assert min([1, 2]) == 1
|
||||
assert min([1, 2], key=lambda x: -x) == 2
|
||||
|
||||
assert max(1, 2) == 2
|
||||
assert max(1, 2, 3) == 3
|
||||
assert max([1, 2]) == 2
|
||||
assert max([1, 2, 3], key=lambda x: -x) == 1
|
||||
|
||||
assert min([
|
||||
(3, 1),
|
||||
(1, 2),
|
||||
(1, 3),
|
||||
(1, 4),
|
||||
]) == (1, 2)
|
||||
|
||||
assert min(1, 2) == 1
|
||||
assert max(1, 2) == 2
|
||||
Loading…
x
Reference in New Issue
Block a user