mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-25 05:50:17 +00:00
add @dataclass
This commit is contained in:
parent
d1080aab1f
commit
475bce9999
14
docs/modules/dataclasses.md
Normal file
14
docs/modules/dataclasses.md
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
---
|
||||||
|
icon: package
|
||||||
|
label: dataclasses
|
||||||
|
---
|
||||||
|
|
||||||
|
### `dataclasses.dataclass`
|
||||||
|
|
||||||
|
A decorator that is used to add generated special method to classes, including `__init__`, `__repr__` and `__eq__`.
|
||||||
|
|
||||||
|
### `dataclasses.asdict(obj) -> dict`
|
||||||
|
|
||||||
|
Convert a dataclass instance to a dictionary.
|
||||||
|
|
||||||
|
|
||||||
@ -22,6 +22,7 @@ namespace pkpy {
|
|||||||
throw std::runtime_error(msg.str()); \
|
throw std::runtime_error(msg.str()); \
|
||||||
} \
|
} \
|
||||||
PyObject* type = vm->new_type_object(mod, #name, base); \
|
PyObject* type = vm->new_type_object(mod, #name, base); \
|
||||||
|
mod->attr().set(#name, type); \
|
||||||
T::_register(vm, mod, type); \
|
T::_register(vm, mod, type); \
|
||||||
return type; \
|
return type; \
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,7 +23,7 @@
|
|||||||
#include <bitset>
|
#include <bitset>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
|
|
||||||
#define PK_VERSION "1.3.3"
|
#define PK_VERSION "1.3.5"
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "export.h"
|
#include "export.h"
|
||||||
@ -166,7 +166,7 @@ static_assert(sizeof(Number::int_t) == sizeof(void*));
|
|||||||
static_assert(sizeof(BitsCvt) == sizeof(void*));
|
static_assert(sizeof(BitsCvt) == sizeof(void*));
|
||||||
static_assert(std::numeric_limits<f64>::is_iec559);
|
static_assert(std::numeric_limits<f64>::is_iec559);
|
||||||
|
|
||||||
struct Dummy { };
|
struct Dummy { }; // for special objects: True, False, None, Ellipsis, etc.
|
||||||
struct DummyInstance { };
|
struct DummyInstance { };
|
||||||
struct DummyModule { };
|
struct DummyModule { };
|
||||||
struct NoReturn { };
|
struct NoReturn { };
|
||||||
|
|||||||
@ -118,7 +118,8 @@ class Compiler {
|
|||||||
bool try_compile_assignment();
|
bool try_compile_assignment();
|
||||||
void compile_stmt();
|
void compile_stmt();
|
||||||
void consume_type_hints();
|
void consume_type_hints();
|
||||||
void compile_class();
|
void _add_decorators(const std::vector<Expr_>& decorators);
|
||||||
|
void compile_class(const std::vector<Expr_>& decorators={});
|
||||||
void _compile_f_args(FuncDecl_ decl, bool enable_type_hints);
|
void _compile_f_args(FuncDecl_ decl, bool enable_type_hints);
|
||||||
void compile_function(const std::vector<Expr_>& decorators={});
|
void compile_function(const std::vector<Expr_>& decorators={});
|
||||||
|
|
||||||
|
|||||||
@ -118,6 +118,9 @@ OPCODE(UNPACK_EX)
|
|||||||
OPCODE(BEGIN_CLASS)
|
OPCODE(BEGIN_CLASS)
|
||||||
OPCODE(END_CLASS)
|
OPCODE(END_CLASS)
|
||||||
OPCODE(STORE_CLASS_ATTR)
|
OPCODE(STORE_CLASS_ATTR)
|
||||||
|
OPCODE(BEGIN_CLASS_DECORATION)
|
||||||
|
OPCODE(END_CLASS_DECORATION)
|
||||||
|
OPCODE(ADD_CLASS_ANNOTATION)
|
||||||
/**************************/
|
/**************************/
|
||||||
OPCODE(WITH_ENTER)
|
OPCODE(WITH_ENTER)
|
||||||
OPCODE(WITH_EXIT)
|
OPCODE(WITH_EXIT)
|
||||||
|
|||||||
@ -55,6 +55,8 @@ struct PyTypeInfo{
|
|||||||
Str name;
|
Str name;
|
||||||
bool subclass_enabled;
|
bool subclass_enabled;
|
||||||
|
|
||||||
|
std::vector<StrName> annotated_fields;
|
||||||
|
|
||||||
// cached special methods
|
// cached special methods
|
||||||
// unary operators
|
// unary operators
|
||||||
PyObject* (*m__repr__)(VM* vm, PyObject*) = nullptr;
|
PyObject* (*m__repr__)(VM* vm, PyObject*) = nullptr;
|
||||||
|
|||||||
@ -5,6 +5,17 @@ def print(*args, sep=' ', end='\n'):
|
|||||||
s = sep.join([str(i) for i in args])
|
s = sep.join([str(i) for i in args])
|
||||||
_sys.stdout.write(s + end)
|
_sys.stdout.write(s + end)
|
||||||
|
|
||||||
|
def issubclass(cls, base):
|
||||||
|
if type(cls) is not type:
|
||||||
|
raise TypeError('issubclass() arg 1 must be a class')
|
||||||
|
if type(base) is not type:
|
||||||
|
raise TypeError('issubclass() arg 2 must be a class')
|
||||||
|
while cls is not None:
|
||||||
|
if cls is base:
|
||||||
|
return True
|
||||||
|
cls = cls.__base__
|
||||||
|
return False
|
||||||
|
|
||||||
def _minmax_reduce(op, args, key):
|
def _minmax_reduce(op, args, key):
|
||||||
if key is None:
|
if key is None:
|
||||||
if len(args) == 2:
|
if len(args) == 2:
|
||||||
|
|||||||
59
python/dataclasses.py
Normal file
59
python/dataclasses.py
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
def _wrapped__init__(self, *args, **kwargs):
|
||||||
|
cls = type(self)
|
||||||
|
cls_d = cls.__dict__
|
||||||
|
fields: tuple[str] = cls.__annotations__
|
||||||
|
i = 0 # index into args
|
||||||
|
for field in fields:
|
||||||
|
if field in kwargs:
|
||||||
|
setattr(self, field, kwargs.pop(field))
|
||||||
|
else:
|
||||||
|
if i < len(args):
|
||||||
|
setattr(self, field, args[i])
|
||||||
|
++i
|
||||||
|
elif field in cls_d: # has default value
|
||||||
|
setattr(self, field, cls_d[field])
|
||||||
|
else:
|
||||||
|
raise TypeError(f"{cls.__name__} missing required argument {field!r}")
|
||||||
|
if len(args) > i:
|
||||||
|
raise TypeError(f"{cls.__name__} takes {len(field)} positional arguments but {len(args)} were given")
|
||||||
|
if len(kwargs) > 0:
|
||||||
|
raise TypeError(f"{cls.__name__} got an unexpected keyword argument {next(iter(kwargs))!r}")
|
||||||
|
|
||||||
|
def _wrapped__repr__(self):
|
||||||
|
fields: tuple[str] = type(self).__annotations__
|
||||||
|
obj_d = self.__dict__
|
||||||
|
args: list = [f"{field}={obj_d[field]!r}" for field in fields]
|
||||||
|
return f"{type(self).__name__}({', '.join(args)})"
|
||||||
|
|
||||||
|
def _wrapped__eq__(self, other):
|
||||||
|
if type(self) is not type(other):
|
||||||
|
return False
|
||||||
|
fields: tuple[str] = type(self).__annotations__
|
||||||
|
for field in fields:
|
||||||
|
if getattr(self, field) != getattr(other, field):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
def dataclass(cls: type):
|
||||||
|
assert type(cls) is type
|
||||||
|
cls_d = cls.__dict__
|
||||||
|
if '__init__' not in cls_d:
|
||||||
|
cls.__init__ = _wrapped__init__
|
||||||
|
if '__repr__' not in cls_d:
|
||||||
|
cls.__repr__ = _wrapped__repr__
|
||||||
|
if '__eq__' not in cls_d:
|
||||||
|
cls.__eq__ = _wrapped__eq__
|
||||||
|
fields: tuple[str] = cls.__annotations__
|
||||||
|
has_default = False
|
||||||
|
for field in fields:
|
||||||
|
if field in cls_d:
|
||||||
|
has_default = True
|
||||||
|
else:
|
||||||
|
if has_default:
|
||||||
|
raise TypeError(f"non-default argument {field!r} follows default argument")
|
||||||
|
return cls
|
||||||
|
|
||||||
|
def asdict(obj) -> dict:
|
||||||
|
fields: tuple[str] = type(obj).__annotations__
|
||||||
|
obj_d = obj.__dict__
|
||||||
|
return {field: obj_d[field] for field in fields}
|
||||||
@ -749,6 +749,8 @@ __NEXT_STEP:;
|
|||||||
} DISPATCH();
|
} DISPATCH();
|
||||||
TARGET(END_CLASS) {
|
TARGET(END_CLASS) {
|
||||||
PK_ASSERT(_curr_class != nullptr);
|
PK_ASSERT(_curr_class != nullptr);
|
||||||
|
StrName _name(byte.arg);
|
||||||
|
frame->_module->attr().set(_name, _curr_class);
|
||||||
_curr_class = nullptr;
|
_curr_class = nullptr;
|
||||||
} DISPATCH();
|
} DISPATCH();
|
||||||
TARGET(STORE_CLASS_ATTR){
|
TARGET(STORE_CLASS_ATTR){
|
||||||
@ -760,6 +762,18 @@ __NEXT_STEP:;
|
|||||||
}
|
}
|
||||||
_curr_class->attr().set(_name, _0);
|
_curr_class->attr().set(_name, _0);
|
||||||
} DISPATCH();
|
} DISPATCH();
|
||||||
|
TARGET(BEGIN_CLASS_DECORATION){
|
||||||
|
PUSH(_curr_class);
|
||||||
|
} DISPATCH();
|
||||||
|
TARGET(END_CLASS_DECORATION){
|
||||||
|
_curr_class = POPX();
|
||||||
|
} DISPATCH();
|
||||||
|
TARGET(ADD_CLASS_ANNOTATION) {
|
||||||
|
PK_ASSERT(_curr_class != nullptr);
|
||||||
|
StrName _name(byte.arg);
|
||||||
|
Type type = PK_OBJ_GET(Type, _curr_class);
|
||||||
|
_type_info(type)->annotated_fields.push_back(_name);
|
||||||
|
} DISPATCH();
|
||||||
/*****************************************/
|
/*****************************************/
|
||||||
TARGET(WITH_ENTER)
|
TARGET(WITH_ENTER)
|
||||||
call_method(POPX(), __enter__);
|
call_method(POPX(), __enter__);
|
||||||
@ -818,8 +832,8 @@ __NEXT_STEP:;
|
|||||||
} DISPATCH();
|
} DISPATCH();
|
||||||
|
|
||||||
#if !PK_ENABLE_COMPUTED_GOTO
|
#if !PK_ENABLE_COMPUTED_GOTO
|
||||||
static_assert(OP_DEC_GLOBAL == 107);
|
static_assert(OP_DEC_GLOBAL == 110);
|
||||||
case 108: case 109: case 110: case 111: case 112: case 113: case 114: case 115: case 116: case 117: case 118: case 119: case 120: case 121: case 122: case 123: case 124: case 125: case 126: case 127: case 128: case 129: case 130: case 131: case 132: case 133: case 134: case 135: case 136: case 137: case 138: case 139: case 140: case 141: case 142: case 143: case 144: case 145: case 146: case 147: case 148: case 149: case 150: case 151: case 152: case 153: case 154: case 155: case 156: case 157: case 158: case 159: case 160: case 161: case 162: case 163: case 164: case 165: case 166: case 167: case 168: case 169: case 170: case 171: case 172: case 173: case 174: case 175: case 176: case 177: case 178: case 179: case 180: case 181: case 182: case 183: case 184: case 185: case 186: case 187: case 188: case 189: case 190: case 191: case 192: case 193: case 194: case 195: case 196: case 197: case 198: case 199: case 200: case 201: case 202: case 203: case 204: case 205: case 206: case 207: case 208: case 209: case 210: case 211: case 212: case 213: case 214: case 215: case 216: case 217: case 218: case 219: case 220: case 221: case 222: case 223: case 224: case 225: case 226: case 227: case 228: case 229: case 230: case 231: case 232: case 233: case 234: case 235: case 236: case 237: case 238: case 239: case 240: case 241: case 242: case 243: case 244: case 245: case 246: case 247: case 248: case 249: case 250: case 251: case 252: case 253: case 254: case 255: FATAL_ERROR(); break;
|
case 111: case 112: case 113: case 114: case 115: case 116: case 117: case 118: case 119: case 120: case 121: case 122: case 123: case 124: case 125: case 126: case 127: case 128: case 129: case 130: case 131: case 132: case 133: case 134: case 135: case 136: case 137: case 138: case 139: case 140: case 141: case 142: case 143: case 144: case 145: case 146: case 147: case 148: case 149: case 150: case 151: case 152: case 153: case 154: case 155: case 156: case 157: case 158: case 159: case 160: case 161: case 162: case 163: case 164: case 165: case 166: case 167: case 168: case 169: case 170: case 171: case 172: case 173: case 174: case 175: case 176: case 177: case 178: case 179: case 180: case 181: case 182: case 183: case 184: case 185: case 186: case 187: case 188: case 189: case 190: case 191: case 192: case 193: case 194: case 195: case 196: case 197: case 198: case 199: case 200: case 201: case 202: case 203: case 204: case 205: case 206: case 207: case 208: case 209: case 210: case 211: case 212: case 213: case 214: case 215: case 216: case 217: case 218: case 219: case 220: case 221: case 222: case 223: case 224: case 225: case 226: case 227: case 228: case 229: case 230: case 231: case 232: case 233: case 234: case 235: case 236: case 237: case 238: case 239: case 240: case 241: case 242: case 243: case 244: case 245: case 246: case 247: case 248: case 249: case 250: case 251: case 252: case 253: case 254: case 255: FATAL_ERROR(); break;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@ -169,6 +169,7 @@ void add_module_c(VM* vm){
|
|||||||
return VAR_T(C99Struct, &val, sizeof(T)); \
|
return VAR_T(C99Struct, &val, sizeof(T)); \
|
||||||
}); \
|
}); \
|
||||||
type = vm->new_type_object(mod, CNAME "_p", VoidP::_type(vm)); \
|
type = vm->new_type_object(mod, CNAME "_p", VoidP::_type(vm)); \
|
||||||
|
mod->attr().set(CNAME "_p", type); \
|
||||||
type_t = PK_OBJ_GET(Type, type); \
|
type_t = PK_OBJ_GET(Type, type); \
|
||||||
vm->bind_method<0>(type, "read", [](VM* vm, ArgsView args){ \
|
vm->bind_method<0>(type, "read", [](VM* vm, ArgsView args){ \
|
||||||
VoidP& voidp = PK_OBJ_GET(VoidP, args[0]); \
|
VoidP& voidp = PK_OBJ_GET(VoidP, args[0]); \
|
||||||
|
|||||||
@ -712,9 +712,14 @@ __EAT_DOTS_END:
|
|||||||
decorators.push_back(ctx()->s_expr.popx());
|
decorators.push_back(ctx()->s_expr.popx());
|
||||||
if(!match_newlines_repl()) SyntaxError();
|
if(!match_newlines_repl()) SyntaxError();
|
||||||
}while(match(TK("@")));
|
}while(match(TK("@")));
|
||||||
|
|
||||||
|
if(match(TK("class"))){
|
||||||
|
compile_class(decorators);
|
||||||
|
}else{
|
||||||
consume(TK("def"));
|
consume(TK("def"));
|
||||||
compile_function(decorators);
|
compile_function(decorators);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool Compiler::try_compile_assignment(){
|
bool Compiler::try_compile_assignment(){
|
||||||
switch (curr().type) {
|
switch (curr().type) {
|
||||||
@ -927,6 +932,12 @@ __EAT_DOTS_END:
|
|||||||
if(match(TK(":"))){
|
if(match(TK(":"))){
|
||||||
consume_type_hints();
|
consume_type_hints();
|
||||||
is_typed_name = true;
|
is_typed_name = true;
|
||||||
|
|
||||||
|
if(ctx()->is_compiling_class){
|
||||||
|
// add to __annotations__
|
||||||
|
NameExpr* ne = static_cast<NameExpr*>(ctx()->s_expr.top().get());
|
||||||
|
ctx()->emit_(OP_ADD_CLASS_ANNOTATION, ne->name.index, BC_KEEPLINE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!try_compile_assignment()){
|
if(!try_compile_assignment()){
|
||||||
@ -955,7 +966,18 @@ __EAT_DOTS_END:
|
|||||||
ctx()->s_expr.pop();
|
ctx()->s_expr.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Compiler::compile_class(){
|
void Compiler::_add_decorators(const std::vector<Expr_>& decorators){
|
||||||
|
// [obj]
|
||||||
|
for(auto it=decorators.rbegin(); it!=decorators.rend(); ++it){
|
||||||
|
(*it)->emit_(ctx()); // [obj, f]
|
||||||
|
ctx()->emit_(OP_ROT_TWO, BC_NOARG, (*it)->line); // [f, obj]
|
||||||
|
ctx()->emit_(OP_LOAD_NULL, BC_NOARG, BC_KEEPLINE); // [f, obj, NULL]
|
||||||
|
ctx()->emit_(OP_ROT_TWO, BC_NOARG, BC_KEEPLINE); // [obj, NULL, f]
|
||||||
|
ctx()->emit_(OP_CALL, 1, (*it)->line); // [obj]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Compiler::compile_class(const std::vector<Expr_>& decorators){
|
||||||
consume(TK("@id"));
|
consume(TK("@id"));
|
||||||
int namei = StrName(prev().sv()).index;
|
int namei = StrName(prev().sv()).index;
|
||||||
Expr_ base = nullptr;
|
Expr_ base = nullptr;
|
||||||
@ -981,7 +1003,14 @@ __EAT_DOTS_END:
|
|||||||
ctx()->is_compiling_class = true;
|
ctx()->is_compiling_class = true;
|
||||||
compile_block_body();
|
compile_block_body();
|
||||||
ctx()->is_compiling_class = false;
|
ctx()->is_compiling_class = false;
|
||||||
ctx()->emit_(OP_END_CLASS, BC_NOARG, BC_KEEPLINE);
|
|
||||||
|
if(!decorators.empty()){
|
||||||
|
ctx()->emit_(OP_BEGIN_CLASS_DECORATION, BC_NOARG, BC_KEEPLINE);
|
||||||
|
_add_decorators(decorators);
|
||||||
|
ctx()->emit_(OP_END_CLASS_DECORATION, BC_NOARG, BC_KEEPLINE);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx()->emit_(OP_END_CLASS, namei, BC_KEEPLINE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Compiler::_compile_f_args(FuncDecl_ decl, bool enable_type_hints){
|
void Compiler::_compile_f_args(FuncDecl_ decl, bool enable_type_hints){
|
||||||
@ -1077,14 +1106,8 @@ __EAT_DOTS_END:
|
|||||||
}
|
}
|
||||||
ctx()->emit_(OP_LOAD_FUNCTION, ctx()->add_func_decl(decl), prev().line);
|
ctx()->emit_(OP_LOAD_FUNCTION, ctx()->add_func_decl(decl), prev().line);
|
||||||
|
|
||||||
// add decorators
|
_add_decorators(decorators);
|
||||||
for(auto it=decorators.rbegin(); it!=decorators.rend(); ++it){
|
|
||||||
(*it)->emit_(ctx());
|
|
||||||
ctx()->emit_(OP_ROT_TWO, BC_NOARG, (*it)->line);
|
|
||||||
ctx()->emit_(OP_LOAD_NULL, BC_NOARG, BC_KEEPLINE);
|
|
||||||
ctx()->emit_(OP_ROT_TWO, BC_NOARG, BC_KEEPLINE);
|
|
||||||
ctx()->emit_(OP_CALL, 1, (*it)->line);
|
|
||||||
}
|
|
||||||
if(!ctx()->is_compiling_class){
|
if(!ctx()->is_compiling_class){
|
||||||
auto e = make_expr<NameExpr>(decl_name, name_scope());
|
auto e = make_expr<NameExpr>(decl_name, name_scope());
|
||||||
e->emit_store(ctx());
|
e->emit_store(ctx());
|
||||||
|
|||||||
@ -1146,29 +1146,6 @@ void init_builtins(VM* _vm) {
|
|||||||
return value;
|
return value;
|
||||||
});
|
});
|
||||||
|
|
||||||
// _vm->bind_method<0>("dict", "_data", [](VM* vm, ArgsView args) {
|
|
||||||
// Dict& self = _CAST(Dict&, args[0]);
|
|
||||||
// SStream ss;
|
|
||||||
// ss << "[\n";
|
|
||||||
// for(int i=0; i<self._capacity; i++){
|
|
||||||
// auto item = self._items[i];
|
|
||||||
// Str key("None");
|
|
||||||
// Str value("None");
|
|
||||||
// if(item.first != nullptr){
|
|
||||||
// key = CAST(Str&, vm->py_repr(item.first));
|
|
||||||
// }
|
|
||||||
// if(item.second != nullptr){
|
|
||||||
// value = CAST(Str&, vm->py_repr(item.second));
|
|
||||||
// }
|
|
||||||
// int prev = self._nodes[i].prev;
|
|
||||||
// int next = self._nodes[i].next;
|
|
||||||
// ss << " [" << key << ", " << value << ", " << prev << ", " << next << "],\n";
|
|
||||||
// }
|
|
||||||
// ss << "]\n";
|
|
||||||
// vm->stdout_write(ss.str());
|
|
||||||
// return vm->None;
|
|
||||||
// });
|
|
||||||
|
|
||||||
_vm->bind__contains__(_vm->tp_dict, [](VM* vm, PyObject* obj, PyObject* key) {
|
_vm->bind__contains__(_vm->tp_dict, [](VM* vm, PyObject* obj, PyObject* key) {
|
||||||
Dict& self = _CAST(Dict&, obj);
|
Dict& self = _CAST(Dict&, obj);
|
||||||
return VAR(self.contains(key));
|
return VAR(self.contains(key));
|
||||||
@ -1615,6 +1592,15 @@ void VM::post_init(){
|
|||||||
return self; // for generics
|
return self; // for generics
|
||||||
});
|
});
|
||||||
|
|
||||||
|
bind_property(_t(tp_type), "__annotations__", [](VM* vm, ArgsView args){
|
||||||
|
PyTypeInfo* ti = vm->_type_info(PK_OBJ_GET(Type, args[0]));
|
||||||
|
Tuple t(ti->annotated_fields.size());
|
||||||
|
for(int i=0; i<ti->annotated_fields.size(); i++){
|
||||||
|
t[i] = VAR(ti->annotated_fields[i].sv());
|
||||||
|
}
|
||||||
|
return VAR(std::move(t));
|
||||||
|
});
|
||||||
|
|
||||||
bind__repr__(tp_type, [](VM* vm, PyObject* self){
|
bind__repr__(tp_type, [](VM* vm, PyObject* self){
|
||||||
SStream ss;
|
SStream ss;
|
||||||
const PyTypeInfo& info = vm->_all_types[PK_OBJ_GET(Type, self)];
|
const PyTypeInfo& info = vm->_all_types[PK_OBJ_GET(Type, self)];
|
||||||
@ -1679,7 +1665,7 @@ void VM::post_init(){
|
|||||||
add_module_operator(this);
|
add_module_operator(this);
|
||||||
add_module_csv(this);
|
add_module_csv(this);
|
||||||
|
|
||||||
for(const char* name: {"this", "functools", "heapq", "bisect", "pickle", "_long", "colorsys", "typing", "datetime"}){
|
for(const char* name: {"this", "functools", "heapq", "bisect", "pickle", "_long", "colorsys", "typing", "datetime", "dataclasses"}){
|
||||||
_lazy_modules[name] = kPythonLibs[name];
|
_lazy_modules[name] = kPythonLibs[name];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -204,7 +204,6 @@ namespace pkpy{
|
|||||||
name.sv(),
|
name.sv(),
|
||||||
subclass_enabled,
|
subclass_enabled,
|
||||||
};
|
};
|
||||||
if(mod != nullptr) mod->attr().set(name, obj);
|
|
||||||
_all_types.push_back(info);
|
_all_types.push_back(info);
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|||||||
29
tests/82_dataclasses.py
Normal file
29
tests/82_dataclasses.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
from dataclasses import dataclass, asdict
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class A:
|
||||||
|
x: int
|
||||||
|
y: str = '123'
|
||||||
|
|
||||||
|
assert repr(A(1)) == "A(x=1, y='123')"
|
||||||
|
assert repr(A(x=3)) == "A(x=3, y='123')"
|
||||||
|
assert repr(A(1, '555')) == "A(x=1, y='555')"
|
||||||
|
assert repr(A(x=7, y='555')) == "A(x=7, y='555')"
|
||||||
|
|
||||||
|
assert asdict(A(1, '555')) == {'x': 1, 'y': '555'}
|
||||||
|
|
||||||
|
assert A(1, 'N') == A(1, 'N')
|
||||||
|
assert A(1, 'N') != A(1, 'M')
|
||||||
|
|
||||||
|
def wrapped(cls):
|
||||||
|
return int
|
||||||
|
|
||||||
|
@wrapped
|
||||||
|
@wrapped
|
||||||
|
@wrapped
|
||||||
|
@wrapped
|
||||||
|
class A:
|
||||||
|
def __init__(self) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
assert A('123') == 123
|
||||||
@ -979,3 +979,12 @@ assert callable(isinstance) is True # builtin function
|
|||||||
|
|
||||||
assert id(0) is None
|
assert id(0) is None
|
||||||
assert id(2**62) is not None
|
assert id(2**62) is not 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
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user