mirror of
https://github.com/pocketpy/pocketpy
synced 2026-03-25 06:30:17 +00:00
Compare commits
No commits in common. "9ecfc0196ff926cb62774903659144b1c0529cbb" and "e84f86b2defb6c4ee9809776a9cb051f393e50ec" have entirely different histories.
9ecfc0196f
...
e84f86b2de
10
.github/workflows/main.yml
vendored
10
.github/workflows/main.yml
vendored
@ -92,18 +92,10 @@ jobs:
|
|||||||
uses: jirutka/setup-alpine@v1
|
uses: jirutka/setup-alpine@v1
|
||||||
with:
|
with:
|
||||||
arch: x86
|
arch: x86
|
||||||
packages: gcc g++ make cmake libc-dev linux-headers python3 gdb
|
packages: gcc g++ make cmake libc-dev linux-headers python3
|
||||||
- name: Build and Test
|
- name: Build and Test
|
||||||
run: |
|
run: |
|
||||||
uname -m
|
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 cmake_build.py
|
||||||
python scripts/run_tests.py
|
python scripts/run_tests.py
|
||||||
python scripts/run_tests.py benchmark
|
python scripts/run_tests.py benchmark
|
||||||
|
|||||||
@ -20,11 +20,3 @@ May be one of:
|
|||||||
### `sys.argv`
|
### `sys.argv`
|
||||||
|
|
||||||
The command line arguments. Set by `py_sys_setargv`.
|
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,10 +38,6 @@ typedef struct VM {
|
|||||||
|
|
||||||
py_TValue last_retval;
|
py_TValue last_retval;
|
||||||
py_TValue curr_exception;
|
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
|
bool is_curr_exc_handled; // handled by try-except block but not cleared yet
|
||||||
|
|
||||||
py_TValue reg[8]; // users' registers
|
py_TValue reg[8]; // users' registers
|
||||||
|
|||||||
@ -495,12 +495,10 @@ PK_API py_StackRef py_pushtmp();
|
|||||||
/// If return false: `[self] -> [self]` (no change).
|
/// If return false: `[self] -> [self]` (no change).
|
||||||
PK_API bool py_pushmethod(py_Name name);
|
PK_API bool py_pushmethod(py_Name name);
|
||||||
/// Call a callable object via pocketpy's calling convention.
|
/// Call a callable object via pocketpy's calling convention.
|
||||||
/// You need to prepare the stack using the following format:
|
/// You need to prepare the stack using this form: `callable, self/nil, arg1, arg2, ..., k1, v1, k2,
|
||||||
/// `callable, self/nil, arg1, arg2, ..., k1, v1, k2, v2, ...`.
|
/// v2, ...` `argc` is the number of positional arguments excluding `self`. `kwargc` is the number
|
||||||
/// `argc` is the number of positional arguments excluding `self`.
|
/// of keyword arguments, i.e. the number of key-value pairs. The result will be set to
|
||||||
/// `kwargc` is the number of keyword arguments.
|
/// `py_retval()`. The stack size will be reduced by `2 + argc + kwargc * 2`.
|
||||||
/// 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;
|
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.
|
/// Evaluate an expression and push the result to the stack.
|
||||||
/// This function is used for testing.
|
/// This function is used for testing.
|
||||||
@ -741,7 +739,7 @@ enum py_PredefinedType {
|
|||||||
tp_KeyboardInterrupt,
|
tp_KeyboardInterrupt,
|
||||||
tp_StopIteration,
|
tp_StopIteration,
|
||||||
tp_SyntaxError,
|
tp_SyntaxError,
|
||||||
tp_RecursionError,
|
tp_StackOverflowError,
|
||||||
tp_OSError,
|
tp_OSError,
|
||||||
tp_NotImplementedError,
|
tp_NotImplementedError,
|
||||||
tp_TypeError,
|
tp_TypeError,
|
||||||
|
|||||||
@ -8,12 +8,9 @@ def test_file(filepath, cpython=False):
|
|||||||
if cpython:
|
if cpython:
|
||||||
return os.system("python " + filepath) == 0
|
return os.system("python " + filepath) == 0
|
||||||
if sys.platform == 'win32':
|
if sys.platform == 'win32':
|
||||||
code = os.system("main.exe " + filepath)
|
return os.system("main.exe " + filepath) == 0
|
||||||
else:
|
else:
|
||||||
code = os.system("./main " + filepath)
|
return os.system("./main " + filepath) == 0
|
||||||
if code != 0:
|
|
||||||
print('Return code:', code)
|
|
||||||
return code == 0
|
|
||||||
|
|
||||||
def test_dir(path):
|
def test_dir(path):
|
||||||
print("Testing directory:", path)
|
print("Testing directory:", path)
|
||||||
|
|||||||
@ -13,6 +13,14 @@ static bool stack_format_object(VM* self, c11_sv spec);
|
|||||||
#define CHECK_RETURN_FROM_EXCEPT_OR_FINALLY() \
|
#define CHECK_RETURN_FROM_EXCEPT_OR_FINALLY() \
|
||||||
if(self->is_curr_exc_handled) py_clearexc(NULL)
|
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() \
|
#define DISPATCH() \
|
||||||
do { \
|
do { \
|
||||||
frame->ip++; \
|
frame->ip++; \
|
||||||
@ -53,7 +61,6 @@ static bool stack_format_object(VM* self, c11_sv spec);
|
|||||||
*SECOND() = *THIRD(); \
|
*SECOND() = *THIRD(); \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
// Must use a DISPATCH() after vectorcall_opcall() immediately!
|
|
||||||
#define vectorcall_opcall(argc, kwargc) \
|
#define vectorcall_opcall(argc, kwargc) \
|
||||||
do { \
|
do { \
|
||||||
FrameResult res = VM__vectorcall(self, (argc), (kwargc), true); \
|
FrameResult res = VM__vectorcall(self, (argc), (kwargc), true); \
|
||||||
@ -86,15 +93,6 @@ FrameResult VM__run_top_frame(VM* self) {
|
|||||||
while(true) {
|
while(true) {
|
||||||
Bytecode byte;
|
Bytecode byte;
|
||||||
__NEXT_FRAME:
|
__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;
|
codes = frame->co->codes.data;
|
||||||
frame->ip++;
|
frame->ip++;
|
||||||
|
|
||||||
@ -151,32 +149,39 @@ FrameResult VM__run_top_frame(VM* self) {
|
|||||||
DISPATCH();
|
DISPATCH();
|
||||||
/*****************************************/
|
/*****************************************/
|
||||||
case OP_LOAD_CONST: {
|
case OP_LOAD_CONST: {
|
||||||
|
CHECK_STACK_OVERFLOW();
|
||||||
PUSH(c11__at(py_TValue, &frame->co->consts, byte.arg));
|
PUSH(c11__at(py_TValue, &frame->co->consts, byte.arg));
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
case OP_LOAD_NONE: {
|
case OP_LOAD_NONE: {
|
||||||
|
CHECK_STACK_OVERFLOW();
|
||||||
py_newnone(SP()++);
|
py_newnone(SP()++);
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
case OP_LOAD_TRUE: {
|
case OP_LOAD_TRUE: {
|
||||||
|
CHECK_STACK_OVERFLOW();
|
||||||
py_newbool(SP()++, true);
|
py_newbool(SP()++, true);
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
case OP_LOAD_FALSE: {
|
case OP_LOAD_FALSE: {
|
||||||
|
CHECK_STACK_OVERFLOW();
|
||||||
py_newbool(SP()++, false);
|
py_newbool(SP()++, false);
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
/*****************************************/
|
/*****************************************/
|
||||||
case OP_LOAD_SMALL_INT: {
|
case OP_LOAD_SMALL_INT: {
|
||||||
|
CHECK_STACK_OVERFLOW();
|
||||||
py_newint(SP()++, (int16_t)byte.arg);
|
py_newint(SP()++, (int16_t)byte.arg);
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
/*****************************************/
|
/*****************************************/
|
||||||
case OP_LOAD_ELLIPSIS: {
|
case OP_LOAD_ELLIPSIS: {
|
||||||
|
CHECK_STACK_OVERFLOW();
|
||||||
py_newellipsis(SP()++);
|
py_newellipsis(SP()++);
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
case OP_LOAD_FUNCTION: {
|
case OP_LOAD_FUNCTION: {
|
||||||
|
CHECK_STACK_OVERFLOW();
|
||||||
FuncDecl_ decl = c11__getitem(FuncDecl_, &frame->co->func_decls, byte.arg);
|
FuncDecl_ decl = c11__getitem(FuncDecl_, &frame->co->func_decls, byte.arg);
|
||||||
Function* ud = py_newobject(SP(), tp_function, 0, sizeof(Function));
|
Function* ud = py_newobject(SP(), tp_function, 0, sizeof(Function));
|
||||||
Function__ctor(ud, decl, frame->module, frame->globals);
|
Function__ctor(ud, decl, frame->module, frame->globals);
|
||||||
@ -347,7 +352,8 @@ FrameResult VM__run_top_frame(VM* self) {
|
|||||||
} else {
|
} else {
|
||||||
INSERT_THIRD(); // [?, a, b]
|
INSERT_THIRD(); // [?, a, b]
|
||||||
*THIRD() = *magic; // [__getitem__, a, b]
|
*THIRD() = *magic; // [__getitem__, a, b]
|
||||||
vectorcall_opcall(1, 0);
|
if(!py_vectorcall(1, 0)) goto __ERROR;
|
||||||
|
PUSH(py_retval());
|
||||||
}
|
}
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
@ -407,7 +413,7 @@ FrameResult VM__run_top_frame(VM* self) {
|
|||||||
if(!py_callcfunc(magic->_cfunc, 3, THIRD())) goto __ERROR;
|
if(!py_callcfunc(magic->_cfunc, 3, THIRD())) goto __ERROR;
|
||||||
STACK_SHRINK(4);
|
STACK_SHRINK(4);
|
||||||
} else {
|
} else {
|
||||||
*FOURTH() = *magic; // [__setitem__, a, b, val]
|
*FOURTH() = *magic; // [__selitem__, a, b, val]
|
||||||
if(!py_vectorcall(2, 0)) goto __ERROR;
|
if(!py_vectorcall(2, 0)) goto __ERROR;
|
||||||
}
|
}
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
@ -497,7 +503,8 @@ FrameResult VM__run_top_frame(VM* self) {
|
|||||||
py_newnil(SP()++); // [complex, NULL]
|
py_newnil(SP()++); // [complex, NULL]
|
||||||
py_newint(SP()++, 0); // [complex, NULL, 0]
|
py_newint(SP()++, 0); // [complex, NULL, 0]
|
||||||
*SP()++ = tmp; // [complex, NULL, 0, x]
|
*SP()++ = tmp; // [complex, NULL, 0, x]
|
||||||
vectorcall_opcall(2, 0);
|
if(!py_vectorcall(2, 0)) goto __ERROR;
|
||||||
|
PUSH(py_retval());
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
case OP_BUILD_BYTES: {
|
case OP_BUILD_BYTES: {
|
||||||
@ -1072,7 +1079,8 @@ FrameResult VM__run_top_frame(VM* self) {
|
|||||||
TOP()->type);
|
TOP()->type);
|
||||||
goto __ERROR;
|
goto __ERROR;
|
||||||
}
|
}
|
||||||
vectorcall_opcall(0, 0);
|
if(!py_vectorcall(0, 0)) goto __ERROR;
|
||||||
|
PUSH(py_retval());
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
case OP_WITH_EXIT: {
|
case OP_WITH_EXIT: {
|
||||||
|
|||||||
@ -64,7 +64,6 @@ static bool generator__next__(int argc, py_Ref argv) {
|
|||||||
}
|
}
|
||||||
vm->stack.sp = ud->frame->p0;
|
vm->stack.sp = ud->frame->p0;
|
||||||
vm->top_frame = vm->top_frame->f_back;
|
vm->top_frame = vm->top_frame->f_back;
|
||||||
vm->recursion_depth--;
|
|
||||||
ud->state = 1;
|
ud->state = 1;
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -71,10 +71,6 @@ void VM__ctor(VM* self) {
|
|||||||
|
|
||||||
self->last_retval = *py_NIL();
|
self->last_retval = *py_NIL();
|
||||||
self->curr_exception = *py_NIL();
|
self->curr_exception = *py_NIL();
|
||||||
|
|
||||||
self->recursion_depth = 0;
|
|
||||||
self->max_recursion_depth = 1000;
|
|
||||||
|
|
||||||
self->is_curr_exc_handled = false;
|
self->is_curr_exc_handled = false;
|
||||||
|
|
||||||
self->ctx = NULL;
|
self->ctx = NULL;
|
||||||
@ -166,7 +162,7 @@ void VM__ctor(VM* self) {
|
|||||||
py_setdict(&self->builtins, py_name("StopIteration"), py_tpobject(tp_StopIteration));
|
py_setdict(&self->builtins, py_name("StopIteration"), py_tpobject(tp_StopIteration));
|
||||||
|
|
||||||
INJECT_BUILTIN_EXC(SyntaxError, tp_Exception);
|
INJECT_BUILTIN_EXC(SyntaxError, tp_Exception);
|
||||||
INJECT_BUILTIN_EXC(RecursionError, tp_Exception);
|
INJECT_BUILTIN_EXC(StackOverflowError, tp_Exception);
|
||||||
INJECT_BUILTIN_EXC(OSError, tp_Exception);
|
INJECT_BUILTIN_EXC(OSError, tp_Exception);
|
||||||
INJECT_BUILTIN_EXC(NotImplementedError, tp_Exception);
|
INJECT_BUILTIN_EXC(NotImplementedError, tp_Exception);
|
||||||
INJECT_BUILTIN_EXC(TypeError, tp_Exception);
|
INJECT_BUILTIN_EXC(TypeError, tp_Exception);
|
||||||
@ -269,7 +265,6 @@ void VM__dtor(VM* self) {
|
|||||||
void VM__push_frame(VM* self, py_Frame* frame) {
|
void VM__push_frame(VM* self, py_Frame* frame) {
|
||||||
frame->f_back = self->top_frame;
|
frame->f_back = self->top_frame;
|
||||||
self->top_frame = frame;
|
self->top_frame = frame;
|
||||||
self->recursion_depth++;
|
|
||||||
if(self->trace_info.func) self->trace_info.func(frame, TRACE_EVENT_PUSH);
|
if(self->trace_info.func) self->trace_info.func(frame, TRACE_EVENT_PUSH);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -282,7 +277,6 @@ void VM__pop_frame(VM* self) {
|
|||||||
// pop frame and delete
|
// pop frame and delete
|
||||||
self->top_frame = frame->f_back;
|
self->top_frame = frame->f_back;
|
||||||
Frame__delete(frame);
|
Frame__delete(frame);
|
||||||
self->recursion_depth--;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _clip_int(int* value, int min, int max) {
|
static void _clip_int(int* value, int min, int max) {
|
||||||
@ -475,6 +469,12 @@ FrameResult VM__vectorcall(VM* self, uint16_t argc, uint16_t kwargc, bool opcall
|
|||||||
py_Ref argv = p0 + 1 + (int)py_isnil(p0 + 1);
|
py_Ref argv = p0 + 1 + (int)py_isnil(p0 + 1);
|
||||||
|
|
||||||
if(p0->type == tp_function) {
|
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);
|
Function* fn = py_touserdata(p0);
|
||||||
const CodeObject* co = &fn->decl->code;
|
const CodeObject* co = &fn->decl->code;
|
||||||
|
|
||||||
|
|||||||
@ -240,28 +240,9 @@ void pk__add_module_io() {}
|
|||||||
|
|
||||||
#endif
|
#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() {
|
void pk__add_module_sys() {
|
||||||
py_Ref mod = py_newmodule("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("platform")), PY_SYS_PLATFORM_STRING);
|
||||||
py_newstr(py_emplacedict(mod, py_name("version")), PK_VERSION);
|
py_newstr(py_emplacedict(mod, py_name("version")), PK_VERSION);
|
||||||
py_newlist(py_emplacedict(mod, py_name("argv")));
|
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:
|
try:
|
||||||
t = TestSuperNoParent()
|
t = TestSuperNoParent()
|
||||||
print('未能拦截错误')
|
print('未能拦截错误')
|
||||||
exit(2)
|
exit(1)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
try:
|
try:
|
||||||
t = TestSuperNoBaseMethod()
|
t = TestSuperNoBaseMethod()
|
||||||
print('未能拦截错误')
|
print('未能拦截错误')
|
||||||
exit(3)
|
exit(1)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -83,7 +83,7 @@ try:
|
|||||||
c = C()
|
c = C()
|
||||||
c.method()
|
c.method()
|
||||||
print('未能拦截错误')
|
print('未能拦截错误')
|
||||||
exit(4)
|
exit(1)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -91,7 +91,7 @@ try:
|
|||||||
d = D()
|
d = D()
|
||||||
d.method()
|
d.method()
|
||||||
print('未能拦截错误')
|
print('未能拦截错误')
|
||||||
exit(5)
|
exit(1)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -134,14 +134,14 @@ assert type(hash(a)) is int
|
|||||||
try:
|
try:
|
||||||
hash({1:1})
|
hash({1:1})
|
||||||
print('未能拦截错误')
|
print('未能拦截错误')
|
||||||
exit(6)
|
exit(1)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
try:
|
try:
|
||||||
hash([1])
|
hash([1])
|
||||||
print('未能拦截错误')
|
print('未能拦截错误')
|
||||||
exit(7)
|
exit(1)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -166,7 +166,7 @@ repr(A())
|
|||||||
try:
|
try:
|
||||||
range(1,2,3,4)
|
range(1,2,3,4)
|
||||||
print('未能拦截错误, 在测试 range')
|
print('未能拦截错误, 在测试 range')
|
||||||
exit(8)
|
exit(1)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -174,14 +174,14 @@ except:
|
|||||||
try:
|
try:
|
||||||
int('asad')
|
int('asad')
|
||||||
print('未能拦截错误, 在测试 int')
|
print('未能拦截错误, 在测试 int')
|
||||||
exit(9)
|
exit(1)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
try:
|
try:
|
||||||
int(123, 16)
|
int(123, 16)
|
||||||
print('未能拦截错误, 在测试 int')
|
print('未能拦截错误, 在测试 int')
|
||||||
exit(10)
|
exit(1)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -192,14 +192,14 @@ assert type(11%2) is int
|
|||||||
try:
|
try:
|
||||||
float('asad')
|
float('asad')
|
||||||
print('未能拦截错误, 在测试 float')
|
print('未能拦截错误, 在测试 float')
|
||||||
exit(11)
|
exit(1)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
try:
|
try:
|
||||||
float([])
|
float([])
|
||||||
print('未能拦截错误, 在测试 float')
|
print('未能拦截错误, 在测试 float')
|
||||||
exit(12)
|
exit(1)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -213,7 +213,7 @@ assert type('25363546'.index('63')) is int
|
|||||||
try:
|
try:
|
||||||
'25363546'.index('err')
|
'25363546'.index('err')
|
||||||
print('未能拦截错误, 在测试 str.index')
|
print('未能拦截错误, 在测试 str.index')
|
||||||
exit(13)
|
exit(1)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -228,7 +228,7 @@ assert '25363546'.find('err') == -1
|
|||||||
try:
|
try:
|
||||||
list(1,2)
|
list(1,2)
|
||||||
print('未能拦截错误, 在测试 list')
|
print('未能拦截错误, 在测试 list')
|
||||||
exit(14)
|
exit(1)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -238,7 +238,7 @@ assert type([1,2,3,4,5].index(4)) is int
|
|||||||
try:
|
try:
|
||||||
[1,2,3,4,5].index(6)
|
[1,2,3,4,5].index(6)
|
||||||
print('未能拦截错误, 在测试 list.index')
|
print('未能拦截错误, 在测试 list.index')
|
||||||
exit(15)
|
exit(1)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -249,7 +249,7 @@ except:
|
|||||||
try:
|
try:
|
||||||
[1,2,3,4,5].remove(6)
|
[1,2,3,4,5].remove(6)
|
||||||
print('未能拦截错误, 在测试 list.remove')
|
print('未能拦截错误, 在测试 list.remove')
|
||||||
exit(16)
|
exit(1)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -259,7 +259,7 @@ except:
|
|||||||
try:
|
try:
|
||||||
[1,2,3,4,5].pop(1,2,3,4)
|
[1,2,3,4,5].pop(1,2,3,4)
|
||||||
print('未能拦截错误, 在测试 list.pop')
|
print('未能拦截错误, 在测试 list.pop')
|
||||||
exit(17)
|
exit(1)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -275,7 +275,7 @@ assert type(12 * [12]) is list
|
|||||||
try:
|
try:
|
||||||
tuple(1,2)
|
tuple(1,2)
|
||||||
print('未能拦截错误, 在测试 tuple')
|
print('未能拦截错误, 在测试 tuple')
|
||||||
exit(18)
|
exit(1)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -305,3 +305,287 @@ assert type(repr(bytes([0x41, 0x42, 0x43]))) is str
|
|||||||
|
|
||||||
# /************ slice ************/
|
# /************ slice ************/
|
||||||
assert type(slice(0.1, 0.2, 0.3)) is 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__']
|
||||||
@ -1,243 +0,0 @@
|
|||||||
# 未完全测试准确性-----------------------------------------------
|
|
||||||
# 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