mirror of
https://github.com/pocketpy/pocketpy
synced 2025-11-06 11:40:16 +00:00
some fix.
This commit is contained in:
parent
57e8cf651b
commit
c6e24c69a2
93
.github/workflows/pybind11.yml
vendored
Normal file
93
.github/workflows/pybind11.yml
vendored
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
name: CMake Build and Test
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- pkpy-v2
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- pkpy-v2
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build_linux:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up GCC
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y gcc g++
|
||||||
|
|
||||||
|
- name: Set up CMake
|
||||||
|
uses: jwlawson/actions-setup-cmake@v1.10
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
git submodule update --init --recursive
|
||||||
|
git clone https://github.com/google/googletest.git
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
cmake -B build -DENABLE_TEST=ON
|
||||||
|
cmake --build build --config Release --parallel
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
run: |
|
||||||
|
build/pybind11_test
|
||||||
|
|
||||||
|
build_win:
|
||||||
|
runs-on: windows-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up MSVC
|
||||||
|
uses: ilammy/msvc-dev-cmd@v1
|
||||||
|
|
||||||
|
- name: Set up CMake
|
||||||
|
uses: jwlawson/actions-setup-cmake@v1.10
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
git submodule update --init --recursive
|
||||||
|
git clone https://github.com/google/googletest.git
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
cmake -B build -DENABLE_TEST=ON
|
||||||
|
cmake --build build --config Release --parallel
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
run: |
|
||||||
|
build\Release\pybind11_test.exe
|
||||||
|
|
||||||
|
build_mac:
|
||||||
|
runs-on: macos-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Clang
|
||||||
|
run: |
|
||||||
|
brew install llvm
|
||||||
|
echo 'export PATH="/usr/local/opt/llvm/bin:$PATH"' >> ~/.zshrc
|
||||||
|
source ~/.zshrc
|
||||||
|
|
||||||
|
- name: Set up CMake
|
||||||
|
uses: jwlawson/actions-setup-cmake@v1.10
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
git submodule update --init --recursive
|
||||||
|
git clone https://github.com/google/googletest.git
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: |
|
||||||
|
cmake -B build -DENABLE_TEST=ON
|
||||||
|
cmake --build build --config Release --parallel
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
run: |
|
||||||
|
build/pybind11_test
|
||||||
@ -18,7 +18,9 @@ class accessor : public interface<accessor<policy>> {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
auto ptr() const {
|
auto ptr() const {
|
||||||
if(!m_value) { m_value = policy::get(m_obj, m_key); }
|
if(m_value.empty()) {
|
||||||
|
m_value = borrow(policy::get(m_obj, m_key));
|
||||||
|
}
|
||||||
return m_value.ptr();
|
return m_value.ptr();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,11 +40,12 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
handle m_obj;
|
handle m_obj;
|
||||||
mutable handle m_value;
|
mutable object m_value;
|
||||||
key_type m_key;
|
key_type m_key;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace policy {
|
namespace policy {
|
||||||
|
|
||||||
struct attr {
|
struct attr {
|
||||||
using key_type = name;
|
using key_type = name;
|
||||||
|
|
||||||
@ -136,6 +139,11 @@ inline item_accessor<handle> interface<Derived>::operator[] (handle key) const {
|
|||||||
return {ptr(), key};
|
return {ptr(), key};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
object str::format(Args&&... args) {
|
||||||
|
return attr("format")(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
inline tuple_accessor tuple::operator[] (int index) const { return {m_ptr, index}; }
|
inline tuple_accessor tuple::operator[] (int index) const { return {m_ptr, index}; }
|
||||||
|
|
||||||
inline list_accessor list::operator[] (int index) const { return {m_ptr, index}; };
|
inline list_accessor list::operator[] (int index) const { return {m_ptr, index}; };
|
||||||
@ -148,9 +156,9 @@ inline dict_accessor<handle> dict::operator[] (handle key) const { return {m_ptr
|
|||||||
|
|
||||||
inline dict::iterator::iterator(handle h) : items(h.attr("items")()), iter(items.begin()) {}
|
inline dict::iterator::iterator(handle h) : items(h.attr("items")()), iter(items.begin()) {}
|
||||||
|
|
||||||
inline std::pair<handle, handle> dict::iterator::operator* () const {
|
inline std::pair<object, object> dict::iterator::operator* () const {
|
||||||
tuple pair = tuple(*iter, object::ref_t{});
|
tuple pair = *iter;
|
||||||
return {pair[0], pair[1]};
|
return {borrow(pair[0]), borrow(pair[1])};
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace pkbind
|
} // namespace pkbind
|
||||||
|
|||||||
@ -72,6 +72,8 @@ inline py_i64 hash(handle obj) {
|
|||||||
|
|
||||||
inline bool isinstance(handle obj, type type) { return py_isinstance(obj.ptr(), type.index()); }
|
inline bool isinstance(handle obj, type type) { return py_isinstance(obj.ptr(), type.index()); }
|
||||||
|
|
||||||
|
inline bool python_error::match(type type) const { return isinstance(m_exception.ptr(), type); }
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
constexpr inline bool is_pyobject_v = std::is_base_of_v<object, std::decay_t<T>> || std::is_same_v<type, T>;
|
constexpr inline bool is_pyobject_v = std::is_base_of_v<object, std::decay_t<T>> || std::is_same_v<type, T>;
|
||||||
|
|
||||||
@ -173,13 +175,12 @@ T cast(handle obj, bool convert = true) {
|
|||||||
return std::move(caster.value());
|
return std::move(caster.value());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
std::string msg = "cast python instance to c++ failed, ";
|
std::string msg = "cast python instance to c++ failed, obj type is: {";
|
||||||
msg += "obj type is: {";
|
|
||||||
msg += type::of(obj).name();
|
msg += type::of(obj).name();
|
||||||
msg += "}, target type is: {";
|
msg += "}, target type is: {";
|
||||||
msg += type_name<T>();
|
msg += type_name<T>();
|
||||||
msg += "}.";
|
msg += "}.";
|
||||||
throw std::runtime_error(msg);
|
throw cast_error(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -31,9 +31,9 @@ struct type_caster {
|
|||||||
static_assert(!std::is_reference_v<T>, "type caster for reference type must be specialized.");
|
static_assert(!std::is_reference_v<T>, "type caster for reference type must be specialized.");
|
||||||
|
|
||||||
template <typename U>
|
template <typename U>
|
||||||
static object cast(U&& value, return_value_policy policy, handle parent = none()) {
|
static object cast(U&& value, return_value_policy policy, handle parent) {
|
||||||
// TODO: support implicit cast
|
// TODO: support implicit cast
|
||||||
return instance::create(std::forward<U>(value), type::of<T>(), policy, parent.ptr());
|
return instance::create(type::of<T>(), std::forward<U>(value), parent, policy);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool load(handle src, bool convert) {
|
bool load(handle src, bool convert) {
|
||||||
|
|||||||
@ -37,16 +37,10 @@ public:
|
|||||||
[[maybe_unused]] auto args = py_offset(stack, 1);
|
[[maybe_unused]] auto args = py_offset(stack, 1);
|
||||||
[[maybe_unused]] auto kwargs = py_offset(stack, 2);
|
[[maybe_unused]] auto kwargs = py_offset(stack, 2);
|
||||||
|
|
||||||
// if constexpr(types_count_v<dynamic_attr, Args...> != 0) {
|
|
||||||
// // FIXME:
|
|
||||||
// // bind dynamic attributes
|
|
||||||
// }
|
|
||||||
|
|
||||||
auto type = pkbind::type(cls, object::ref_t{});
|
|
||||||
auto info = &type_info::of<T>();
|
auto info = &type_info::of<T>();
|
||||||
void* data = py_newobject(py_retval(), type.index(), 1, sizeof(instance));
|
int slot = (type_list<Args...>::template count<dynamic_attr> ? -1 : 0);
|
||||||
|
void* data = py_newobject(retv, steal<type>(cls).index(), slot, sizeof(instance));
|
||||||
new (data) instance{instance::Flag::Own, operator new (info->size), info};
|
new (data) instance{instance::Flag::Own, operator new (info->size), info};
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
nullptr,
|
nullptr,
|
||||||
|
|||||||
@ -16,6 +16,10 @@ public:
|
|||||||
|
|
||||||
~python_error() { std::free(m_what); }
|
~python_error() { std::free(m_what); }
|
||||||
|
|
||||||
|
bool match(py_Type type) const { return py_isinstance(m_exception.ptr(), type); }
|
||||||
|
|
||||||
|
bool match(class type) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
char* m_what;
|
char* m_what;
|
||||||
object m_exception;
|
object m_exception;
|
||||||
@ -30,19 +34,54 @@ inline auto raise_call(Args&&... args) {
|
|||||||
|
|
||||||
using type = decltype(result);
|
using type = decltype(result);
|
||||||
if constexpr(std::is_same_v<type, bool>) {
|
if constexpr(std::is_same_v<type, bool>) {
|
||||||
if(result != false) { return result; }
|
if(result != false) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
} else if constexpr(std::is_same_v<type, int>) {
|
} else if constexpr(std::is_same_v<type, int>) {
|
||||||
if(result != -1) { return result; }
|
if(result != -1) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
static_assert(dependent_false<type>, "invalid return type");
|
static_assert(dependent_false<type>, "invalid return type");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool o = py_matchexc(tp_Exception);
|
||||||
|
object e = object::from_ret();
|
||||||
auto what = py_formatexc();
|
auto what = py_formatexc();
|
||||||
py_matchexc(tp_Exception);
|
|
||||||
py_clearexc(pc);
|
py_clearexc(pc);
|
||||||
throw python_error(what, object(retv, object::realloc_t{}));
|
throw python_error(what, std::move(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class stop_iteration {};
|
||||||
|
|
||||||
|
class cast_error : public std::runtime_error {
|
||||||
|
using std::runtime_error::runtime_error;
|
||||||
|
};
|
||||||
|
|
||||||
|
class index_error : public std::runtime_error {
|
||||||
|
using std::runtime_error::runtime_error;
|
||||||
|
};
|
||||||
|
|
||||||
|
class key_error : public std::runtime_error {
|
||||||
|
using std::runtime_error::runtime_error;
|
||||||
|
};
|
||||||
|
|
||||||
|
class value_error : public std::runtime_error {
|
||||||
|
using std::runtime_error::runtime_error;
|
||||||
|
};
|
||||||
|
|
||||||
|
class type_error : public std::runtime_error {
|
||||||
|
using std::runtime_error::runtime_error;
|
||||||
|
};
|
||||||
|
|
||||||
|
class import_error : public std::runtime_error {
|
||||||
|
using std::runtime_error::runtime_error;
|
||||||
|
};
|
||||||
|
|
||||||
|
class attribute_error : public std::runtime_error {
|
||||||
|
using std::runtime_error::runtime_error;
|
||||||
|
};
|
||||||
|
|
||||||
inline object::operator bool () const { return raise_call<py_bool>(m_ptr); }
|
inline object::operator bool () const { return raise_call<py_bool>(m_ptr); }
|
||||||
|
|
||||||
#define PKBIND_BINARY_OPERATOR(name, lop, rop) \
|
#define PKBIND_BINARY_OPERATOR(name, lop, rop) \
|
||||||
|
|||||||
@ -130,10 +130,14 @@ class function_record {
|
|||||||
friend struct template_parser;
|
friend struct template_parser;
|
||||||
|
|
||||||
using destructor_t = void (*)(function_record*);
|
using destructor_t = void (*)(function_record*);
|
||||||
using wrapper_t = bool (*)(function_record&, std::vector<handle>&, dict&, bool convert, handle parent);
|
using wrapper_t = bool (*)(function_record&,
|
||||||
|
std::vector<handle>&,
|
||||||
|
std::vector<std::pair<handle, handle>>&,
|
||||||
|
bool convert,
|
||||||
|
handle parent);
|
||||||
|
|
||||||
struct arguments_t {
|
struct arguments_t {
|
||||||
std::vector<name> names;
|
std::vector<std::string> names;
|
||||||
std::vector<object> defaults;
|
std::vector<object> defaults;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -174,10 +178,18 @@ public:
|
|||||||
function_record& operator= (function_record&&) = delete;
|
function_record& operator= (function_record&&) = delete;
|
||||||
|
|
||||||
~function_record() {
|
~function_record() {
|
||||||
if(destructor) { destructor(this); }
|
if(destructor) {
|
||||||
if(arguments) { delete arguments; }
|
destructor(this);
|
||||||
if(next) { delete next; }
|
}
|
||||||
if(signature) { delete[] signature; }
|
if(arguments) {
|
||||||
|
delete arguments;
|
||||||
|
}
|
||||||
|
if(next) {
|
||||||
|
delete next;
|
||||||
|
}
|
||||||
|
if(signature) {
|
||||||
|
delete[] signature;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void append(function_record* record) {
|
void append(function_record* record) {
|
||||||
@ -202,32 +214,44 @@ public:
|
|||||||
return *static_cast<function_record*>(py_touserdata(slot));
|
return *static_cast<function_record*>(py_touserdata(slot));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator() (int argc, handle stack) {
|
void operator() (int argc, handle stack) {
|
||||||
function_record* p = this;
|
function_record* p = this;
|
||||||
|
|
||||||
bool has_self = argc == 3;
|
bool has_self = argc == 3;
|
||||||
std::vector<handle> args2;
|
std::vector<handle> args;
|
||||||
if(has_self) { args2.push_back(py_offset(stack.ptr(), 0)); }
|
handle self = py_offset(stack.ptr(), 0);
|
||||||
|
if(has_self) {
|
||||||
tuple args(py_offset(stack.ptr(), 0 + has_self), object::ref_t{});
|
args.push_back(self);
|
||||||
for(int i = 0; i < args.size(); ++i) {
|
|
||||||
args2.push_back(args[i]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dict kwargs(py_offset(stack.ptr(), 1 + has_self), object::ref_t{});
|
auto tuple = py_offset(stack.ptr(), 0 + has_self);
|
||||||
|
for(int i = 0; i < py_tuple_len(tuple); ++i) {
|
||||||
|
args.push_back(py_tuple_getitem(tuple, i));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto dict = steal<pkbind::dict>(py_offset(stack.ptr(), 1 + has_self));
|
||||||
|
|
||||||
|
std::vector<std::pair<handle, handle>> kwargs;
|
||||||
|
dict.apply([&](handle key, handle value) {
|
||||||
|
kwargs.emplace_back(key, value);
|
||||||
|
});
|
||||||
|
|
||||||
// foreach function record and call the function with not convert
|
// foreach function record and call the function with not convert
|
||||||
while(p != nullptr) {
|
while(p != nullptr) {
|
||||||
auto result = p->wrapper(*p, args2, kwargs, false, {});
|
auto result = p->wrapper(*p, args, kwargs, false, self);
|
||||||
if(result) { return result; }
|
if(result) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
p = p->next;
|
p = p->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
p = this;
|
p = this;
|
||||||
// foreach function record and call the function with convert
|
// foreach function record and call the function with convert
|
||||||
while(p != nullptr) {
|
while(p != nullptr) {
|
||||||
auto result = p->wrapper(*p, args2, kwargs, true, {});
|
auto result = p->wrapper(*p, args, kwargs, true, self);
|
||||||
if(result) { return result; }
|
if(result) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
p = p->next;
|
p = p->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -344,7 +368,9 @@ struct template_parser<Callable, std::tuple<Extras...>, std::tuple<Args...>, std
|
|||||||
static void initialize(function_record& record, const Extras&... extras) {
|
static void initialize(function_record& record, const Extras&... extras) {
|
||||||
auto extras_tuple = std::make_tuple(extras...);
|
auto extras_tuple = std::make_tuple(extras...);
|
||||||
constexpr static bool has_named_args = (named_argc > 0);
|
constexpr static bool has_named_args = (named_argc > 0);
|
||||||
if constexpr(policy_pos != -1) { record.policy = std::get<policy_pos>(extras_tuple); }
|
if constexpr(policy_pos != -1) {
|
||||||
|
record.policy = std::get<policy_pos>(extras_tuple);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: set others
|
// TODO: set others
|
||||||
|
|
||||||
@ -382,17 +408,17 @@ struct template_parser<Callable, std::tuple<Extras...>, std::tuple<Args...>, std
|
|||||||
sig += record.arguments->names[index].c_str();
|
sig += record.arguments->names[index].c_str();
|
||||||
sig += ": ";
|
sig += ": ";
|
||||||
sig += type_info::of<T>().name;
|
sig += type_info::of<T>().name;
|
||||||
if(!record.arguments->defaults[index].is_empty()) {
|
if(!record.arguments->defaults[index].empty()) {
|
||||||
sig += " = ";
|
sig += " = ";
|
||||||
// FIXME:
|
sig += record.arguments->defaults[index].attr("__repr__")().cast<std::string_view>();
|
||||||
// sig += record.arguments->defaults[index].repr();
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sig += "_: ";
|
sig += "_: ";
|
||||||
sig += type_info::of<T>().name;
|
sig += type_info::of<T>().name;
|
||||||
}
|
}
|
||||||
|
if(index + 1 < argc) {
|
||||||
if(index + 1 < argc) { sig += ", "; }
|
sig += ", ";
|
||||||
|
}
|
||||||
index++;
|
index++;
|
||||||
};
|
};
|
||||||
(append(type_identity<Args>{}), ...);
|
(append(type_identity<Args>{}), ...);
|
||||||
@ -406,7 +432,11 @@ struct template_parser<Callable, std::tuple<Extras...>, std::tuple<Args...>, std
|
|||||||
|
|
||||||
/// try to call a C++ function(store in function_record) with the arguments which are from Python.
|
/// try to call a C++ function(store in function_record) with the arguments which are from Python.
|
||||||
/// if success, return true, otherwise return false.
|
/// if success, return true, otherwise return false.
|
||||||
static bool call(function_record& record, std::vector<handle>& args, dict& kwargs, bool convert, handle parent) {
|
static bool call(function_record& record,
|
||||||
|
std::vector<handle>& args,
|
||||||
|
std::vector<std::pair<handle, handle>>& kwargs,
|
||||||
|
bool convert,
|
||||||
|
handle parent) {
|
||||||
// first, we try to load arguments into the stack.
|
// first, we try to load arguments into the stack.
|
||||||
// use argc + 1 to avoid compile error when argc is 0.
|
// use argc + 1 to avoid compile error when argc is 0.
|
||||||
handle stack[argc + 1] = {};
|
handle stack[argc + 1] = {};
|
||||||
@ -421,48 +451,58 @@ struct template_parser<Callable, std::tuple<Extras...>, std::tuple<Args...>, std
|
|||||||
|
|
||||||
// load arguments from call arguments
|
// load arguments from call arguments
|
||||||
if(args.size() > normal_argc) {
|
if(args.size() > normal_argc) {
|
||||||
if constexpr(args_pos == -1) { return false; }
|
if constexpr(args_pos == -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(std::size_t i = 0; i < std::min(normal_argc, (int)args.size()); ++i) {
|
for(std::size_t i = 0; i < std::min(normal_argc, (int)args.size()); ++i) {
|
||||||
stack[i] = args[i];
|
stack[i] = args[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object repack_args;
|
||||||
// pack the args
|
// pack the args
|
||||||
if constexpr(args_pos != -1) {
|
if constexpr(args_pos != -1) {
|
||||||
const auto n = args.size() > normal_argc ? args.size() - normal_argc : 0;
|
const auto n = args.size() > normal_argc ? args.size() - normal_argc : 0;
|
||||||
reg<0> = tuple(n);
|
auto pack = tuple(n);
|
||||||
stack[args_pos] = reg<0>;
|
|
||||||
auto pack = tuple(reg<0>, object::ref_t{});
|
|
||||||
for(std::size_t i = 0; i < n; ++i) {
|
for(std::size_t i = 0; i < n; ++i) {
|
||||||
pack[i] = args[normal_argc + i];
|
pack[i] = args[normal_argc + i];
|
||||||
}
|
}
|
||||||
|
repack_args = std::move(pack);
|
||||||
|
stack[args_pos] = repack_args;
|
||||||
}
|
}
|
||||||
|
|
||||||
// pack the kwargs
|
// pack the kwargs
|
||||||
int index = 0;
|
int index = 0;
|
||||||
bool init_dict = false;
|
if constexpr(named_argc != 0) {
|
||||||
dict pack2;
|
int arg_index = 0;
|
||||||
|
while(arg_index < named_argc && index < kwargs.size()) {
|
||||||
kwargs.apply([&](handle key, handle value) {
|
const auto name = kwargs[index].first;
|
||||||
if constexpr(named_argc != 0) {
|
const auto value = kwargs[index].second;
|
||||||
for(int i = index; i < named_argc; ++i) {
|
if(name.cast<std::string_view>() == record.arguments->names[arg_index]) {
|
||||||
if(key.cast<std::string_view>() == record.arguments->names[i]) {
|
stack[arg_index] = value;
|
||||||
stack[i] = value;
|
index += 1;
|
||||||
index = i + 1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
arg_index += 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if constexpr(kwargs_pos != -1) { pack2[key] = value; }
|
object repacked_kwargs;
|
||||||
});
|
if constexpr(kwargs_pos != -1) {
|
||||||
|
auto pack = dict();
|
||||||
if constexpr(kwargs_pos != -1) { stack[kwargs_pos] = pack2; }
|
while(index < kwargs.size()) {
|
||||||
|
pack[kwargs[index].first] = kwargs[index].second;
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
repacked_kwargs = std::move(pack);
|
||||||
|
stack[kwargs_pos] = repacked_kwargs;
|
||||||
|
}
|
||||||
|
|
||||||
// check if all the arguments are valid
|
// check if all the arguments are valid
|
||||||
for(std::size_t i = 0; i < argc; ++i) {
|
for(std::size_t i = 0; i < argc; ++i) {
|
||||||
if(!stack[i]) { return false; }
|
if(!stack[i]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ok, all the arguments are valid, call the function
|
// ok, all the arguments are valid, call the function
|
||||||
@ -493,7 +533,9 @@ class cpp_function : public function {
|
|||||||
static bool is_function_record(handle h) {
|
static bool is_function_record(handle h) {
|
||||||
if(isinstance<function>(h)) {
|
if(isinstance<function>(h)) {
|
||||||
auto slot = py_getslot(h.ptr(), 0);
|
auto slot = py_getslot(h.ptr(), 0);
|
||||||
if(slot) { return py_typeof(slot) == m_type; }
|
if(slot) {
|
||||||
|
return py_typeof(slot) == m_type;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -505,8 +547,39 @@ class cpp_function : public function {
|
|||||||
sig += is_method ? "(self, *args, **kwargs)" : "(*args, **kwargs)";
|
sig += is_method ? "(self, *args, **kwargs)" : "(*args, **kwargs)";
|
||||||
auto call = [](int argc, py_Ref stack) {
|
auto call = [](int argc, py_Ref stack) {
|
||||||
handle func = py_inspect_currentfunction();
|
handle func = py_inspect_currentfunction();
|
||||||
auto& record = *static_cast<impl::function_record*>(py_touserdata(py_getslot(func.ptr(), 0)));
|
auto data = py_touserdata(py_getslot(func.ptr(), 0));
|
||||||
return record(argc, stack);
|
auto& record = *static_cast<impl::function_record*>(data);
|
||||||
|
try {
|
||||||
|
record(argc, stack);
|
||||||
|
return true;
|
||||||
|
} catch(std::domain_error& e) {
|
||||||
|
py_exception(tp_ValueError, e.what());
|
||||||
|
} catch(std::invalid_argument& e) {
|
||||||
|
py_exception(tp_ValueError, e.what());
|
||||||
|
} catch(std::length_error& e) {
|
||||||
|
py_exception(tp_ValueError, e.what());
|
||||||
|
} catch(std::out_of_range& e) {
|
||||||
|
py_exception(tp_IndexError, e.what());
|
||||||
|
} catch(std::range_error& e) {
|
||||||
|
py_exception(tp_ValueError, e.what());
|
||||||
|
} catch(stop_iteration& e) {
|
||||||
|
StopIteration();
|
||||||
|
} catch(index_error& e) {
|
||||||
|
py_exception(tp_IndexError, e.what());
|
||||||
|
} catch(key_error& e) {
|
||||||
|
py_exception(tp_KeyError, e.what());
|
||||||
|
} catch(value_error& e) {
|
||||||
|
py_exception(tp_ValueError, e.what());
|
||||||
|
} catch(type_error& e) {
|
||||||
|
py_exception(tp_TypeError, e.what());
|
||||||
|
} catch(import_error& e) {
|
||||||
|
py_exception(tp_ImportError, e.what());
|
||||||
|
} catch(attribute_error& e) {
|
||||||
|
py_exception(tp_AttributeError, e.what());
|
||||||
|
} catch(std::exception& e) {
|
||||||
|
py_exception(tp_RuntimeError, e.what());
|
||||||
|
}
|
||||||
|
return false;
|
||||||
};
|
};
|
||||||
py_newfunction(m_ptr, sig.c_str(), call, nullptr, 1);
|
py_newfunction(m_ptr, sig.c_str(), call, nullptr, 1);
|
||||||
|
|
||||||
|
|||||||
@ -29,8 +29,7 @@ struct type_info {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// all registered C++ class will be ensured as instance type.
|
// all registered C++ class will be ensured as instance type.
|
||||||
class instance {
|
struct instance {
|
||||||
public:
|
|
||||||
// use to record the type information of C++ class.
|
// use to record the type information of C++ class.
|
||||||
enum Flag {
|
enum Flag {
|
||||||
None = 0,
|
None = 0,
|
||||||
@ -41,13 +40,11 @@ public:
|
|||||||
Flag flag;
|
Flag flag;
|
||||||
void* data;
|
void* data;
|
||||||
const type_info* info;
|
const type_info* info;
|
||||||
|
object parent;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
template <typename Value>
|
template <typename Value>
|
||||||
static object create(Value&& value_,
|
static object create(type type, Value&& value_, handle parent_, return_value_policy policy) {
|
||||||
type type,
|
|
||||||
return_value_policy policy = return_value_policy::automatic_reference,
|
|
||||||
handle parent_ = {}) {
|
|
||||||
using underlying_type = remove_cvref_t<Value>;
|
using underlying_type = remove_cvref_t<Value>;
|
||||||
|
|
||||||
auto& value = [&]() -> auto& {
|
auto& value = [&]() -> auto& {
|
||||||
@ -66,7 +63,7 @@ public:
|
|||||||
|
|
||||||
void* data = nullptr;
|
void* data = nullptr;
|
||||||
Flag flag = Flag::None;
|
Flag flag = Flag::None;
|
||||||
handle parent = parent_;
|
object parent;
|
||||||
|
|
||||||
if(policy == return_value_policy::take_ownership) {
|
if(policy == return_value_policy::take_ownership) {
|
||||||
data = &value;
|
data = &value;
|
||||||
@ -95,16 +92,19 @@ public:
|
|||||||
} else if(policy == return_value_policy::reference_internal) {
|
} else if(policy == return_value_policy::reference_internal) {
|
||||||
data = &value;
|
data = &value;
|
||||||
flag = Flag::Ref;
|
flag = Flag::Ref;
|
||||||
|
parent = borrow(parent_);
|
||||||
}
|
}
|
||||||
|
|
||||||
object result(object::alloc_t{});
|
object result(object::alloc_t{});
|
||||||
void* temp = py_newobject(result.ptr(), type.index(), 1, sizeof(instance));
|
void* temp = py_newobject(result.ptr(), type.index(), 1, sizeof(instance));
|
||||||
new (temp) instance{flag, data, info};
|
new (temp) instance{flag, data, info, std::move(parent)};
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
~instance() {
|
~instance() {
|
||||||
if(flag & Flag::Own) { info->destructor(data); }
|
if(flag & Flag::Own) {
|
||||||
|
info->destructor(data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
|||||||
@ -198,7 +198,9 @@ public:
|
|||||||
object() = default;
|
object() = default;
|
||||||
|
|
||||||
object(const object& other) : handle(other), m_index(other.m_index) {
|
object(const object& other) : handle(other), m_index(other.m_index) {
|
||||||
if(other.in_pool()) { object_pool::inc_ref(other); }
|
if(other.in_pool()) {
|
||||||
|
object_pool::inc_ref(other);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object(object&& other) : handle(other), m_index(other.m_index) {
|
object(object&& other) : handle(other), m_index(other.m_index) {
|
||||||
@ -208,8 +210,12 @@ public:
|
|||||||
|
|
||||||
object& operator= (const object& other) {
|
object& operator= (const object& other) {
|
||||||
if(this != &other) {
|
if(this != &other) {
|
||||||
if(in_pool()) { object_pool::dec_ref(*this); }
|
if(in_pool()) {
|
||||||
if(other.in_pool()) { object_pool::inc_ref(other); }
|
object_pool::dec_ref(*this);
|
||||||
|
}
|
||||||
|
if(other.in_pool()) {
|
||||||
|
object_pool::inc_ref(other);
|
||||||
|
}
|
||||||
m_ptr = other.m_ptr;
|
m_ptr = other.m_ptr;
|
||||||
m_index = other.m_index;
|
m_index = other.m_index;
|
||||||
}
|
}
|
||||||
@ -218,7 +224,9 @@ public:
|
|||||||
|
|
||||||
object& operator= (object&& other) {
|
object& operator= (object&& other) {
|
||||||
if(this != &other) {
|
if(this != &other) {
|
||||||
if(in_pool()) { object_pool::dec_ref(*this); }
|
if(in_pool()) {
|
||||||
|
object_pool::dec_ref(*this);
|
||||||
|
}
|
||||||
m_ptr = other.m_ptr;
|
m_ptr = other.m_ptr;
|
||||||
m_index = other.m_index;
|
m_index = other.m_index;
|
||||||
other.m_ptr = nullptr;
|
other.m_ptr = nullptr;
|
||||||
@ -228,12 +236,14 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
~object() {
|
~object() {
|
||||||
if(in_pool()) { object_pool::dec_ref(*this); }
|
if(in_pool()) {
|
||||||
|
object_pool::dec_ref(*this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_singleton() const { return m_ptr && m_index == -1; }
|
bool is_singleton() const { return m_ptr && m_index == -1; }
|
||||||
|
|
||||||
bool is_empty() const { return m_ptr == nullptr && m_index == -1; }
|
bool empty() const { return m_ptr == nullptr && m_index == -1; }
|
||||||
|
|
||||||
/// return whether the object is in the object pool.
|
/// return whether the object is in the object pool.
|
||||||
bool in_pool() const { return m_ptr && m_index != -1; }
|
bool in_pool() const { return m_ptr && m_index != -1; }
|
||||||
@ -271,6 +281,16 @@ protected:
|
|||||||
int m_index = -1;
|
int m_index = -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T = object>
|
||||||
|
T steal(handle h) {
|
||||||
|
return T(h, object::ref_t{});
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T = object>
|
||||||
|
T borrow(handle h) {
|
||||||
|
return T(h, object::realloc_t{});
|
||||||
|
}
|
||||||
|
|
||||||
template <int N>
|
template <int N>
|
||||||
void reg_t<N>::operator= (handle h) & {
|
void reg_t<N>::operator= (handle h) & {
|
||||||
py_setreg(N, h.ptr());
|
py_setreg(N, h.ptr());
|
||||||
|
|||||||
@ -13,8 +13,8 @@ private:
|
|||||||
public: \
|
public: \
|
||||||
using parent::parent; \
|
using parent::parent; \
|
||||||
using parent::operator=; \
|
using parent::operator=; \
|
||||||
child(const object& o) : parent(o) {} \
|
child(const object& o) : parent(type::isinstance<child>(o) ? o : type::of<child>()(o)) {} \
|
||||||
child(object&& o) : parent(std::move(o)) {}
|
child(object&& o) : parent(type::isinstance<child>(o) ? std::move(o) : type::of<child>()(std::move(o))) {}
|
||||||
|
|
||||||
class type : public object {
|
class type : public object {
|
||||||
protected:
|
protected:
|
||||||
@ -106,7 +106,7 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
handle operator* () const { return m_value; }
|
object operator* () const { return m_value; }
|
||||||
|
|
||||||
friend bool operator== (const iterator& lhs, const iterator& rhs) { return lhs.m_value.ptr() == rhs.m_value.ptr(); }
|
friend bool operator== (const iterator& lhs, const iterator& rhs) { return lhs.m_value.ptr() == rhs.m_value.ptr(); }
|
||||||
|
|
||||||
@ -137,6 +137,9 @@ class str : public object {
|
|||||||
str(const char* data) : str(data, strlen(data)) {}
|
str(const char* data) : str(data, strlen(data)) {}
|
||||||
|
|
||||||
str(std::string_view s) : str(s.data(), static_cast<int>(s.size())) {}
|
str(std::string_view s) : str(s.data(), static_cast<int>(s.size())) {}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
object format(Args&&... args);
|
||||||
};
|
};
|
||||||
|
|
||||||
class tuple : public object {
|
class tuple : public object {
|
||||||
@ -172,7 +175,7 @@ class tuple : public object {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
handle operator* () const { return py_tuple_getitem(ptr, index); }
|
object operator* () const { return borrow(py_tuple_getitem(ptr, index)); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
py_Ref ptr;
|
py_Ref ptr;
|
||||||
@ -231,7 +234,7 @@ class list : public object {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
handle operator* () const { return py_list_getitem(ptr, index); }
|
object operator* () const { return borrow(py_list_getitem(ptr, index)); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
py_Ref ptr;
|
py_Ref ptr;
|
||||||
@ -295,7 +298,7 @@ class dict : public object {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<handle, handle> operator* () const;
|
std::pair<object, object> operator* () const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
object items;
|
object items;
|
||||||
@ -335,7 +338,9 @@ class capsule : public object {
|
|||||||
static void register_() {
|
static void register_() {
|
||||||
m_type = py_newtype("capsule", tp_object, nullptr, [](void* data) {
|
m_type = py_newtype("capsule", tp_object, nullptr, [](void* data) {
|
||||||
auto impl = static_cast<capsule_impl*>(data);
|
auto impl = static_cast<capsule_impl*>(data);
|
||||||
if(impl->data && impl->destructor) { impl->destructor(impl->data); }
|
if(impl->data && impl->destructor) {
|
||||||
|
impl->destructor(impl->data);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
26
include/pybind11/tests/CMakeLists.txt
Normal file
26
include/pybind11/tests/CMakeLists.txt
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
project(PKBIND_TEST)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||||
|
|
||||||
|
add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/../../.." "${CMAKE_CURRENT_BINARY_DIR}/pocketpy")
|
||||||
|
|
||||||
|
include(FetchContent)
|
||||||
|
FetchContent_Declare(
|
||||||
|
googletest
|
||||||
|
URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip
|
||||||
|
DOWNLOAD_EXTRACT_TIMESTAMP true
|
||||||
|
)
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
FetchContent_MakeAvailable(googletest)
|
||||||
|
|
||||||
|
file(GLOB CPP_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp")
|
||||||
|
add_executable(PKBIND_TEST ${CPP_SOURCES})
|
||||||
|
|
||||||
|
target_include_directories(PKBIND_TEST PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../..")
|
||||||
|
target_link_libraries(PKBIND_TEST PRIVATE pocketpy gtest_main)
|
||||||
@ -158,7 +158,7 @@ assert p.z == 30
|
|||||||
|
|
||||||
EXPECT_EQ(constructor_calls, 4);
|
EXPECT_EQ(constructor_calls, 4);
|
||||||
}
|
}
|
||||||
// FIXME:
|
|
||||||
TEST_F(PYBIND11_TEST, dynamic_attr) {
|
TEST_F(PYBIND11_TEST, dynamic_attr) {
|
||||||
py::module_ m = py::module_::import("__main__");
|
py::module_ m = py::module_::import("__main__");
|
||||||
|
|
||||||
@ -178,8 +178,8 @@ TEST_F(PYBIND11_TEST, dynamic_attr) {
|
|||||||
EXPECT_EQ(p.attr("x").cast<int>(), 1);
|
EXPECT_EQ(p.attr("x").cast<int>(), 1);
|
||||||
EXPECT_EQ(p.attr("y").cast<int>(), 2);
|
EXPECT_EQ(p.attr("y").cast<int>(), 2);
|
||||||
|
|
||||||
// p.attr("z") = py::int_(3);
|
p.attr("z") = py::int_(3);
|
||||||
// EXPECT_EQ(p.attr("z").cast<int>(), 3);
|
EXPECT_EQ(p.attr("z").cast<int>(), 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(PYBIND11_TEST, enum) {
|
TEST_F(PYBIND11_TEST, enum) {
|
||||||
|
|||||||
50
include/pybind11/tests/error.cpp
Normal file
50
include/pybind11/tests/error.cpp
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#include "test.h"
|
||||||
|
|
||||||
|
TEST_F(PYBIND11_TEST, exception_python_to_cpp) {
|
||||||
|
auto test = [](const char* code, py_Type type) {
|
||||||
|
try {
|
||||||
|
py::exec(code);
|
||||||
|
} catch(py::python_error& e) {
|
||||||
|
EXPECT_TRUE(e.match(type));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
test("raise ValueError()", tp_ValueError);
|
||||||
|
test("raise KeyError()", tp_KeyError);
|
||||||
|
test("raise IndexError()", tp_IndexError);
|
||||||
|
test("raise StopIteration()", tp_StopIteration);
|
||||||
|
test("raise Exception()", tp_Exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PYBIND11_TEST, exception_cpp_to_python) {
|
||||||
|
auto m = py::module_::__main__();
|
||||||
|
|
||||||
|
#define TEST_EXCEPTION(cppe, pye) \
|
||||||
|
m.def("test_" #cppe, []() { \
|
||||||
|
throw cppe(#cppe); \
|
||||||
|
}); \
|
||||||
|
py::exec("try:\n test_" #cppe "()\nexcept Exception as e:\n assert isinstance(e, " #pye \
|
||||||
|
")\n assert str(e) == '" #cppe "'")
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
TEST_EXCEPTION(runtime_error, RuntimeError);
|
||||||
|
TEST_EXCEPTION(domain_error, ValueError);
|
||||||
|
TEST_EXCEPTION(invalid_argument, ValueError);
|
||||||
|
TEST_EXCEPTION(length_error, ValueError);
|
||||||
|
TEST_EXCEPTION(out_of_range, IndexError);
|
||||||
|
TEST_EXCEPTION(range_error, ValueError);
|
||||||
|
|
||||||
|
using namespace py;
|
||||||
|
|
||||||
|
m.def("test_stop_iteration", []() {
|
||||||
|
throw py::stop_iteration();
|
||||||
|
});
|
||||||
|
py::exec("try:\n test_stop_iteration()\nexcept StopIteration as e:\n pass");
|
||||||
|
TEST_EXCEPTION(index_error, IndexError);
|
||||||
|
// FIXME: TEST_EXCEPTION(key_error, KeyError);
|
||||||
|
TEST_EXCEPTION(value_error, ValueError);
|
||||||
|
TEST_EXCEPTION(type_error, TypeError);
|
||||||
|
TEST_EXCEPTION(import_error, ImportError);
|
||||||
|
TEST_EXCEPTION(attribute_error, AttributeError);
|
||||||
|
TEST_EXCEPTION(runtime_error, RuntimeError);
|
||||||
|
}
|
||||||
@ -2,6 +2,31 @@
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
TEST_F(PYBIND11_TEST, vectorcall) {
|
||||||
|
auto m = py::module_::__main__();
|
||||||
|
|
||||||
|
py::exec(R"(
|
||||||
|
def add(a, b):
|
||||||
|
return a + b
|
||||||
|
)");
|
||||||
|
// position only
|
||||||
|
EXPECT_CAST_EQ(m.attr("add")(1, 2), 3);
|
||||||
|
// FIXME: pkpy does not support such calling.
|
||||||
|
// keyword only
|
||||||
|
// EXPECT_CAST_EQ(m.attr("add")(py::arg("a") = 1, py::arg("b") = 2), 3);
|
||||||
|
// mix
|
||||||
|
// EXPECT_CAST_EQ(m.attr("add")(1, py::arg("b") = 2), 3);
|
||||||
|
|
||||||
|
py::exec(R"(
|
||||||
|
def add2(a, *args):
|
||||||
|
return a + sum(args)
|
||||||
|
)");
|
||||||
|
EXPECT_CAST_EQ(m.attr("add2")(1, 2, 3, 4), 10);
|
||||||
|
|
||||||
|
EXPECT_EQ(py::type::of<py::tuple>()(py::eval("[1, 2, 3]")), py::eval("(1, 2, 3)"));
|
||||||
|
EXPECT_EQ(py::type::of<py::list>()(py::eval("(1, 2, 3)")), py::eval("[1, 2, 3]"));
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(PYBIND11_TEST, constructor) {
|
TEST_F(PYBIND11_TEST, constructor) {
|
||||||
auto m = py::module_::__main__();
|
auto m = py::module_::__main__();
|
||||||
|
|
||||||
|
|||||||
@ -63,11 +63,11 @@ TEST_F(PYBIND11_TEST, object) {
|
|||||||
py::exec("p = Point(3, 4)");
|
py::exec("p = Point(3, 4)");
|
||||||
py::object p = py::eval("p");
|
py::object p = py::eval("p");
|
||||||
|
|
||||||
// test is
|
// is
|
||||||
EXPECT_FALSE(p.is_none());
|
EXPECT_FALSE(p.is_none());
|
||||||
EXPECT_TRUE(p.is(p));
|
EXPECT_TRUE(p.is(p));
|
||||||
|
|
||||||
// test attrs
|
// attrs
|
||||||
EXPECT_EQ(p.attr("x").cast<int>(), 3);
|
EXPECT_EQ(p.attr("x").cast<int>(), 3);
|
||||||
EXPECT_EQ(p.attr("y").cast<int>(), 4);
|
EXPECT_EQ(p.attr("y").cast<int>(), 4);
|
||||||
|
|
||||||
@ -78,13 +78,21 @@ TEST_F(PYBIND11_TEST, object) {
|
|||||||
EXPECT_EQ(p.attr("y").cast<int>(), 6);
|
EXPECT_EQ(p.attr("y").cast<int>(), 6);
|
||||||
EXPECT_EXEC_EQ("p", "Point(5, 6)");
|
EXPECT_EXEC_EQ("p", "Point(5, 6)");
|
||||||
|
|
||||||
// test operators
|
// operators
|
||||||
EXPECT_EVAL_EQ("Point(10, 12)", p + p);
|
EXPECT_EVAL_EQ("Point(10, 12)", p + p);
|
||||||
EXPECT_EVAL_EQ("Point(0, 0)", p - p);
|
EXPECT_EVAL_EQ("Point(0, 0)", p - p);
|
||||||
EXPECT_EVAL_EQ("Point(25, 36)", p * p);
|
EXPECT_EVAL_EQ("Point(25, 36)", p * p);
|
||||||
EXPECT_EVAL_EQ("Point(1, 1)", p / p);
|
EXPECT_EVAL_EQ("Point(1, 1)", p / p);
|
||||||
// EXPECT_EVAL_EQ("Point(0, 0)", p // p);
|
// EXPECT_EVAL_EQ("Point(0, 0)", p // p);
|
||||||
EXPECT_EVAL_EQ("Point(0, 0)", p % p);
|
EXPECT_EVAL_EQ("Point(0, 0)", p % p);
|
||||||
|
|
||||||
|
// iterators
|
||||||
|
py::object l = py::eval("[1, 2, 3]");
|
||||||
|
int index = 0;
|
||||||
|
for(auto item: l) {
|
||||||
|
EXPECT_EQ(item.cast<int>(), index + 1);
|
||||||
|
index++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
TEST_F(PYBIND11_TEST, int) {
|
TEST_F(PYBIND11_TEST, int) {
|
||||||
py::object obj = py::int_(123);
|
py::object obj = py::int_(123);
|
||||||
py::handle obj2 = py::eval("123");
|
py::object obj2 = py::eval("123");
|
||||||
|
|
||||||
EXPECT_EQ(obj, obj2);
|
EXPECT_EQ(obj, obj2);
|
||||||
|
|
||||||
@ -13,7 +13,7 @@ TEST_F(PYBIND11_TEST, int) {
|
|||||||
|
|
||||||
TEST_F(PYBIND11_TEST, float) {
|
TEST_F(PYBIND11_TEST, float) {
|
||||||
py::object obj = py::float_(123.0);
|
py::object obj = py::float_(123.0);
|
||||||
py::handle obj2 = py::eval("123.0");
|
py::object obj2 = py::eval("123.0");
|
||||||
|
|
||||||
EXPECT_EQ(obj, obj2);
|
EXPECT_EQ(obj, obj2);
|
||||||
|
|
||||||
@ -23,17 +23,24 @@ TEST_F(PYBIND11_TEST, float) {
|
|||||||
|
|
||||||
TEST_F(PYBIND11_TEST, str) {
|
TEST_F(PYBIND11_TEST, str) {
|
||||||
py::object obj = py::str("123");
|
py::object obj = py::str("123");
|
||||||
py::handle obj2 = py::eval("'123'");
|
py::object obj2 = py::eval("'123'");
|
||||||
|
|
||||||
EXPECT_EQ(obj, obj2);
|
EXPECT_EQ(obj, obj2);
|
||||||
|
|
||||||
EXPECT_STREQ(obj.cast<const char*>(), "123");
|
EXPECT_STREQ(obj.cast<const char*>(), "123");
|
||||||
EXPECT_EQ(obj.cast<std::string>(), "123");
|
EXPECT_EQ(obj.cast<std::string>(), "123");
|
||||||
EXPECT_EQ(obj.cast<std::string_view>(), "123");
|
EXPECT_EQ(obj.cast<std::string_view>(), "123");
|
||||||
|
|
||||||
|
auto s = py::str("Hello, {}");
|
||||||
|
EXPECT_EQ(s.format("world").cast<std::string>(), "Hello, world");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(PYBIND11_TEST, tuple) {
|
TEST_F(PYBIND11_TEST, tuple) {
|
||||||
py::tuple tuple = py::tuple{py::int_(1), py::str("123"), py::int_(3)};
|
py::tuple tuple = py::tuple{
|
||||||
|
py::int_(1),
|
||||||
|
py::str("123"),
|
||||||
|
py::int_(3),
|
||||||
|
};
|
||||||
EXPECT_EQ(tuple, py::eval("(1, '123', 3)"));
|
EXPECT_EQ(tuple, py::eval("(1, '123', 3)"));
|
||||||
EXPECT_EQ(tuple.size(), 3);
|
EXPECT_EQ(tuple.size(), 3);
|
||||||
EXPECT_FALSE(tuple.empty());
|
EXPECT_FALSE(tuple.empty());
|
||||||
@ -41,26 +48,56 @@ TEST_F(PYBIND11_TEST, tuple) {
|
|||||||
tuple[0] = py::int_(3);
|
tuple[0] = py::int_(3);
|
||||||
tuple[2] = py::int_(1);
|
tuple[2] = py::int_(1);
|
||||||
EXPECT_EQ(tuple, py::eval("(3, '123', 1)"));
|
EXPECT_EQ(tuple, py::eval("(3, '123', 1)"));
|
||||||
|
|
||||||
|
// iterators.
|
||||||
|
int index = 0;
|
||||||
|
for(auto item: tuple) {
|
||||||
|
if(index == 0) {
|
||||||
|
EXPECT_EQ(item, py::int_(3));
|
||||||
|
} else if(index == 1) {
|
||||||
|
EXPECT_EQ(item, py::str("123"));
|
||||||
|
} else if(index == 2) {
|
||||||
|
EXPECT_EQ(item, py::int_(1));
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(PYBIND11_TEST, list) {
|
TEST_F(PYBIND11_TEST, list) {
|
||||||
// test constructors
|
// constructors
|
||||||
py::list list = py::list();
|
py::list list = py::list();
|
||||||
EXPECT_EQ(list, py::eval("[]"));
|
EXPECT_EQ(list, py::eval("[]"));
|
||||||
EXPECT_EQ(list.size(), 0);
|
EXPECT_EQ(list.size(), 0);
|
||||||
EXPECT_TRUE(list.empty());
|
EXPECT_TRUE(list.empty());
|
||||||
|
|
||||||
list = py::list{py::int_(1), py::int_(2), py::int_(3)};
|
list = py::list{
|
||||||
|
py::int_(1),
|
||||||
|
py::int_(2),
|
||||||
|
py::int_(3),
|
||||||
|
};
|
||||||
EXPECT_EQ(list, py::eval("[1, 2, 3]"));
|
EXPECT_EQ(list, py::eval("[1, 2, 3]"));
|
||||||
EXPECT_EQ(list.size(), 3);
|
EXPECT_EQ(list.size(), 3);
|
||||||
EXPECT_FALSE(list.empty());
|
EXPECT_FALSE(list.empty());
|
||||||
|
|
||||||
// test accessor
|
// accessor
|
||||||
list[0] = py::int_(3);
|
list[0] = py::int_(3);
|
||||||
list[2] = py::int_(1);
|
list[2] = py::int_(1);
|
||||||
EXPECT_EQ(list, py::eval("[3, 2, 1]"));
|
EXPECT_EQ(list, py::eval("[3, 2, 1]"));
|
||||||
|
|
||||||
// test other apis
|
// iterators
|
||||||
|
int index = 0;
|
||||||
|
for(auto item: list) {
|
||||||
|
if(index == 0) {
|
||||||
|
EXPECT_EQ(item, py::int_(3));
|
||||||
|
} else if(index == 1) {
|
||||||
|
EXPECT_EQ(item, py::int_(2));
|
||||||
|
} else if(index == 2) {
|
||||||
|
EXPECT_EQ(item, py::int_(1));
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// others
|
||||||
list.append(py::int_(4));
|
list.append(py::int_(4));
|
||||||
EXPECT_EQ(list, py::eval("[3, 2, 1, 4]"));
|
EXPECT_EQ(list, py::eval("[3, 2, 1, 4]"));
|
||||||
|
|
||||||
@ -69,22 +106,39 @@ TEST_F(PYBIND11_TEST, list) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(PYBIND11_TEST, dict) {
|
TEST_F(PYBIND11_TEST, dict) {
|
||||||
// test constructors
|
// constructors
|
||||||
py::dict dict = py::dict();
|
py::dict dict = py::dict();
|
||||||
EXPECT_EQ(dict, py::eval("{}"));
|
EXPECT_EQ(dict, py::eval("{}"));
|
||||||
EXPECT_EQ(dict.size(), 0);
|
EXPECT_EQ(dict.size(), 0);
|
||||||
EXPECT_TRUE(dict.empty());
|
EXPECT_TRUE(dict.empty());
|
||||||
|
|
||||||
// test accessor
|
// accessor
|
||||||
dict["a"] = py::int_(1);
|
dict["a"] = py::int_(1);
|
||||||
dict["b"] = py::int_(2);
|
dict["b"] = py::int_(2);
|
||||||
dict["c"] = py::int_(3);
|
dict["c"] = py::int_(3);
|
||||||
EXPECT_EQ(dict, py::eval("{'a': 1, 'b': 2, 'c': 3}"));
|
EXPECT_EQ(dict, py::eval("{'a': 1, 'b': 2, 'c': 3}"));
|
||||||
|
EXPECT_EQ(dict,
|
||||||
|
py::dict({
|
||||||
|
{"a", py::int_(1)},
|
||||||
|
{"b", py::int_(2)},
|
||||||
|
{"c", py::int_(3)},
|
||||||
|
}));
|
||||||
|
|
||||||
// FIXME:
|
// iterators
|
||||||
// test other apis
|
int index = 0;
|
||||||
// dict.clear();
|
for(auto item: dict) {
|
||||||
// EXPECT_EQ(dict, py::eval("{}"));
|
if(index == 0) {
|
||||||
|
EXPECT_EQ(item.first.cast<std::string>(), "a");
|
||||||
|
EXPECT_EQ(item.second, py::int_(1));
|
||||||
|
} else if(index == 1) {
|
||||||
|
EXPECT_EQ(item.first.cast<std::string>(), "b");
|
||||||
|
EXPECT_EQ(item.second, py::int_(2));
|
||||||
|
} else if(index == 2) {
|
||||||
|
EXPECT_EQ(item.first.cast<std::string>(), "c");
|
||||||
|
EXPECT_EQ(item.second, py::int_(3));
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(PYBIND11_TEST, capsule) {
|
TEST_F(PYBIND11_TEST, capsule) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user