mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-28 23:40:16 +00:00
Compare commits
No commits in common. "4ba0b7d2e2348d5efbb294d168574db72163c148" and "fece79b169987cb51f09c1f11e0ef551ec2e745a" have entirely different histories.
4ba0b7d2e2
...
fece79b169
37
README.md
37
README.md
@ -25,8 +25,7 @@ pkpy is extremely easy to embed via a single header file `pocketpy.h`, without e
|
|||||||
|
|
||||||
Please see https://pocketpy.dev for details and try the following resources.
|
Please see https://pocketpy.dev for details and try the following resources.
|
||||||
+ [Live Python Demo](https://pocketpy.dev/static/web/): Python REPL of the latest version
|
+ [Live Python Demo](https://pocketpy.dev/static/web/): Python REPL of the latest version
|
||||||
|
+ [Live C++ Examples](https://pocketpy.github.io/examples/): Common usage of pkpy in C++
|
||||||
> We are moving to v2.0 branch, which is a complete refactor of this project in C11. See [Migration Guide](https://pocketpy.dev/migrate/) for more details.
|
|
||||||
|
|
||||||
## Supported Platforms
|
## Supported Platforms
|
||||||
|
|
||||||
@ -91,33 +90,39 @@ python scripts/run_tests.py
|
|||||||
### Example
|
### Example
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
#include <pybind11/pybind11.h>
|
#include "pocketpy.h"
|
||||||
|
|
||||||
namespace py = pybind11;
|
using namespace pkpy;
|
||||||
|
|
||||||
int main() {
|
int main(){
|
||||||
// Start the interpreter
|
// Create a virtual machine
|
||||||
py::scoped_interpreter guard{};
|
VM* vm = new VM();
|
||||||
|
|
||||||
// Hello world!
|
// Hello world!
|
||||||
py::exec("print('Hello world!')");
|
vm->exec("print('Hello world!')");
|
||||||
|
|
||||||
// Create a list
|
// Create a list
|
||||||
py::exec("a = [1, 2, 3]");
|
vm->exec("a = [1, 2, 3]");
|
||||||
|
|
||||||
// Eval the sum of the list
|
// Eval the sum of the list
|
||||||
auto result = py::eval("sum(a)");
|
PyVar result = vm->eval("sum(a)");
|
||||||
std::cout << "Sum of the list: " << result.cast<int>() << std::endl; // 6
|
std::cout << "Sum of the list: "<< py_cast<int>(vm, result) << std::endl; // 6
|
||||||
|
|
||||||
// Bindings
|
// Bindings
|
||||||
auto m = py::module_::__main__();
|
vm->bind(vm->_main, "add(a: int, b: int)",
|
||||||
m.def("add", [](int a, int b) {
|
[](VM* vm, ArgsView args){
|
||||||
return a + b;
|
int a = py_cast<int>(vm, args[0]);
|
||||||
});
|
int b = py_cast<int>(vm, args[1]);
|
||||||
|
return py_var(vm, a + b);
|
||||||
|
});
|
||||||
|
|
||||||
// Call the function
|
// Call the function
|
||||||
std::cout << "Sum of 2 variables: " << m.attr("add")(1, 2).cast<int>() << std::endl; // 10
|
PyVar f_add = vm->_main->attr("add");
|
||||||
|
result = vm->call(f_add, py_var(vm, 3), py_var(vm, 7));
|
||||||
|
std::cout << "Sum of 2 variables: "<< py_cast<int>(vm, result) << std::endl; // 10
|
||||||
|
|
||||||
|
// Dispose the virtual machine
|
||||||
|
delete vm;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|||||||
333
docs/cheatsheet.md
Normal file
333
docs/cheatsheet.md
Normal file
@ -0,0 +1,333 @@
|
|||||||
|
---
|
||||||
|
icon: log
|
||||||
|
title: 'Cheatsheet'
|
||||||
|
order: 22
|
||||||
|
---
|
||||||
|
|
||||||
|
## Basics
|
||||||
|
|
||||||
|
Setup pocketpy
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include "pocketpy.h"
|
||||||
|
using namespace pkpy;
|
||||||
|
```
|
||||||
|
|
||||||
|
Create a python virtual machine
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
VM* vm = new VM();
|
||||||
|
```
|
||||||
|
|
||||||
|
Dispose a python virtual machine
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
delete vm;
|
||||||
|
```
|
||||||
|
|
||||||
|
Execute a source string
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
vm->exec("print('Hello!')");
|
||||||
|
```
|
||||||
|
|
||||||
|
Evaluate a source string
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
PyVar obj = vm->eval("123");
|
||||||
|
std::cout << py_cast<int>(vm, obj); // 123
|
||||||
|
```
|
||||||
|
|
||||||
|
Compile a source string into a code object
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
CodeObject_ co = vm->compile("print('Hello!')", "main.py", EXEC_MODE);
|
||||||
|
```
|
||||||
|
|
||||||
|
Execute a compiled code object
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
try{
|
||||||
|
vm->_exec(co); // may throw
|
||||||
|
}catch(Exception& e){
|
||||||
|
std::cerr << e.summary() << std::endl;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Interop with native types
|
||||||
|
|
||||||
|
Create primitive objects
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
PyVar obj;
|
||||||
|
obj = py_var(vm, 1); // create a int
|
||||||
|
obj = py_var(vm, 1.0); // create a float
|
||||||
|
obj = py_var(vm, "123"); // create a string
|
||||||
|
obj = py_var(vm, true); // create a bool
|
||||||
|
```
|
||||||
|
|
||||||
|
Create a tuple object
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// obj = (1, 1.0, '123')
|
||||||
|
Tuple t(3);
|
||||||
|
t[0] = py_var(vm, 1);
|
||||||
|
t[1] = py_var(vm, 1.0);
|
||||||
|
t[2] = py_var(vm, "123");
|
||||||
|
PyVar obj = py_var(vm, std::move(t));
|
||||||
|
```
|
||||||
|
|
||||||
|
Create a list object
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// obj = [1, 1.0, '123']
|
||||||
|
List t;
|
||||||
|
t.push_back(py_var(vm, 1));
|
||||||
|
t.push_back(py_var(vm, 1.0));
|
||||||
|
t.push_back(py_var(vm, "123"));
|
||||||
|
PyVar obj = py_var(vm, std::move(t));
|
||||||
|
```
|
||||||
|
|
||||||
|
Create a dict object
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// obj = {'x': 1, 'y': '123'}
|
||||||
|
Dict d(vm);
|
||||||
|
d.set(py_var(vm, "x"), py_var(vm, 1));
|
||||||
|
d.set(py_var(vm, "y"), py_var(vm, "123"));
|
||||||
|
PyVar obj = py_var(vm, std::move(d));
|
||||||
|
```
|
||||||
|
|
||||||
|
Get native types from python objects
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
PyVar obj;
|
||||||
|
i64 a = py_cast<i64>(vm, obj);
|
||||||
|
f64 b = py_cast<f64>(vm, obj);
|
||||||
|
Str& c = py_cast<Str&>(vm, obj); // reference cast
|
||||||
|
bool d = py_cast<bool>(vm, obj);
|
||||||
|
|
||||||
|
Tuple& e = py_cast<Tuple&>(vm, obj); // reference cast
|
||||||
|
List& f = py_cast<List&>(vm, obj); // reference cast
|
||||||
|
Dict& g = py_cast<Dict&>(vm, obj); // reference cast
|
||||||
|
```
|
||||||
|
|
||||||
|
Get native types without type checking
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// unsafe version 1 (for int object you must use `_py_cast`)
|
||||||
|
i64 a = _py_cast<i64>(vm, obj);
|
||||||
|
f64 b = _py_cast<f64>(vm, obj);
|
||||||
|
Tuple& c = _py_cast<Tuple&>(vm, obj);
|
||||||
|
// unsafe version 2 (for others, you can also use `PK_OBJ_GET` macro)
|
||||||
|
Str& a_ = PK_OBJ_GET(Str, obj);
|
||||||
|
List& b_ = PK_OBJ_GET(List, obj);
|
||||||
|
Tuple& c_ = PK_OBJ_GET(Tuple, obj);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Access python types
|
||||||
|
|
||||||
|
Access built-in python types
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
PyVar int_t = vm->_t(VM::tp_int);
|
||||||
|
PyVar float_t = vm->_t(VM::tp_float);
|
||||||
|
PyVar object_t = vm->_t(VM::tp_object);
|
||||||
|
PyVar tuple_t = vm->_t(VM::tp_tuple);
|
||||||
|
PyVar list_t = vm->_t(VM::tp_list);
|
||||||
|
```
|
||||||
|
|
||||||
|
Access user registered types
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
Type voidp_t = vm->_tp_user<VoidP>();
|
||||||
|
```
|
||||||
|
|
||||||
|
Check if an object is a python type
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
PyVar obj;
|
||||||
|
bool ok = is_type(obj, VM::tp_int); // check if obj is an int
|
||||||
|
```
|
||||||
|
|
||||||
|
Get the type of a python object
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
PyVar obj = py_var(vm, 1);
|
||||||
|
PyVar t = vm->_t(obj); // <class 'int'>
|
||||||
|
Type type = vm->_tp(obj); // VM::tp_int
|
||||||
|
```
|
||||||
|
|
||||||
|
Convert a type object into a type index
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
PyVar int_t = vm->_t(VM::tp_int);
|
||||||
|
Type t = PK_OBJ_GET(Type, int_t);
|
||||||
|
// t == VM::tp_int
|
||||||
|
```
|
||||||
|
|
||||||
|
## Access attributes
|
||||||
|
|
||||||
|
Check an object supports attribute access
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
PyVar obj;
|
||||||
|
bool ok = !is_tagged(obj) && obj->is_attr_valid();
|
||||||
|
```
|
||||||
|
|
||||||
|
```python
|
||||||
|
class MyClass:
|
||||||
|
def __init__(self, x, y):
|
||||||
|
self.x = x
|
||||||
|
self.y = y
|
||||||
|
|
||||||
|
def sum(self):
|
||||||
|
return self.x + self.y
|
||||||
|
```
|
||||||
|
|
||||||
|
Get and set attributes
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
PyVar obj = vm->exec("MyClass(1, 2)");
|
||||||
|
PyVar x = vm->getattr(obj, "x"); // obj.x
|
||||||
|
vm->setattr(obj, "x", py_var(vm, 3)); // obj.x = 3
|
||||||
|
```
|
||||||
|
|
||||||
|
## Call python functions
|
||||||
|
|
||||||
|
```python
|
||||||
|
def add(a, b):
|
||||||
|
return a + b
|
||||||
|
```
|
||||||
|
|
||||||
|
Call a function
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
PyVar f_add = vm->eval("add");
|
||||||
|
PyVar ret = vm->call(f_add, py_var(vm, 1), py_var(vm, 2));
|
||||||
|
std::cout << py_cast<int>(vm, ret); // 3
|
||||||
|
```
|
||||||
|
|
||||||
|
Call a method
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
PyVar obj = vm->exec("MyClass(1, 2)");
|
||||||
|
PyVar ret = vm->call_method(obj, "sum");
|
||||||
|
std::cout << CAST(i64, ret); // 3
|
||||||
|
```
|
||||||
|
|
||||||
|
Cache the name of a function or method to avoid string-based lookup
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// cache the name "add" to avoid string-based lookup
|
||||||
|
const static StrName m_sum("sum");
|
||||||
|
PyVar ret = vm->call_method(obj, m_sum);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Special operations
|
||||||
|
|
||||||
|
Compare two python objects
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
PyVar obj1 = py_var(vm, 1);
|
||||||
|
PyVar obj2 = py_var(vm, 2);
|
||||||
|
bool ok = vm->py_eq(obj1, obj2);
|
||||||
|
```
|
||||||
|
|
||||||
|
Convert a python object to string
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
PyVar obj = py_var(vm, 123);
|
||||||
|
std::cout << vm->py_str(obj); // 123
|
||||||
|
```
|
||||||
|
|
||||||
|
Get the string representation of a python object
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
PyVar obj = py_var(vm, "123");
|
||||||
|
std::cout << vm->py_repr(obj); // "'123'"
|
||||||
|
```
|
||||||
|
|
||||||
|
Get the JSON representation of a python object
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
PyVar obj = py_var(vm, 123);
|
||||||
|
std::cout << vm->py_json(obj); // "123"
|
||||||
|
```
|
||||||
|
|
||||||
|
Get the hash value of a python object
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
PyVar obj = py_var(vm, 1);
|
||||||
|
i64 h = vm->py_hash(obj); // 1
|
||||||
|
```
|
||||||
|
|
||||||
|
Get the iterator of a python object
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
PyVar obj = vm->eval("range(3)");
|
||||||
|
PyVar iter = vm->py_iter(obj);
|
||||||
|
```
|
||||||
|
|
||||||
|
Get the next item of an iterator
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
PyVar obj = vm->py_next(iter);
|
||||||
|
if(obj == vm->StopIteration){
|
||||||
|
// end of iteration
|
||||||
|
}else{
|
||||||
|
// process obj
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Convert a python iterable to a list
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
PyVar obj = vm->eval("range(3)");
|
||||||
|
List list = vm->py_list(obj);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Bindings
|
||||||
|
|
||||||
|
Bind a native function
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
vm->bind(obj, "add(a: int, b: int) -> int", [](VM* vm, ArgsView args){
|
||||||
|
int a = py_cast<int>(vm, args[0]);
|
||||||
|
int b = py_cast<int>(vm, args[1]);
|
||||||
|
return py_var(vm, a + b);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Bind a property
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
// getter and setter of property `x`
|
||||||
|
vm->bind_property(type, "x: int",
|
||||||
|
[](VM* vm, ArgsView args){
|
||||||
|
Point& self = PK_OBJ_GET(Point, args[0]);
|
||||||
|
return VAR(self.x);
|
||||||
|
},
|
||||||
|
[](VM* vm, ArgsView args){
|
||||||
|
Point& self = PK_OBJ_GET(Point, args[0]);
|
||||||
|
self.x = py_cast<int>(vm, args[1]);
|
||||||
|
return vm->None;
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## Modules
|
||||||
|
|
||||||
|
Create a source module
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
vm->_lazy_modules["test"] = "pi = 3.14";
|
||||||
|
// import test
|
||||||
|
// print(test.pi) # 3.14
|
||||||
|
```
|
||||||
|
|
||||||
|
Create a native module
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
PyVar mod = vm->new_module("test");
|
||||||
|
vm->setattr(mod, "pi", py_var(vm, 3.14));
|
||||||
|
```
|
||||||
@ -5,12 +5,6 @@ label: Welcome
|
|||||||
|
|
||||||
# Welcome to pocketpy
|
# Welcome to pocketpy
|
||||||
|
|
||||||
!!!
|
|
||||||
We are moving to v2.0 branch, which is a complete refactor of this project in C11.
|
|
||||||
|
|
||||||
See [Migration Guide](migrate.md) for more details.
|
|
||||||
!!!
|
|
||||||
|
|
||||||
pkpy is a lightweight(~15K LOC) Python interpreter for game scripting, built on C++17 with STL.
|
pkpy is a lightweight(~15K LOC) Python interpreter for game scripting, built on C++17 with STL.
|
||||||
|
|
||||||
It aims to be an alternative to lua for game scripting, with elegant syntax, powerful features and competitive performance.
|
It aims to be an alternative to lua for game scripting, with elegant syntax, powerful features and competitive performance.
|
||||||
|
|||||||
@ -1,32 +0,0 @@
|
|||||||
---
|
|
||||||
icon: log
|
|
||||||
title: 'Migration Guide'
|
|
||||||
order: 22
|
|
||||||
---
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
v2.0 branch is a complete refactor of pocketpy in C11,
|
|
||||||
which enables users to run pocketpy on platforms that do not support C++.
|
|
||||||
Also we redesign the core interpreter to be more efficient and maintainable
|
|
||||||
by using modern C11 language features.
|
|
||||||
|
|
||||||
> v2.0 will be released on 2024/08.
|
|
||||||
|
|
||||||
## API compatibility
|
|
||||||
|
|
||||||
| name | v1.x | v2.0 |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| legacy C++ API (v1.x only) | ✅ | ❌ |
|
|
||||||
| legacy C API (v1.x only) | ✅ | ❌ |
|
|
||||||
| C11 API (v2.0 only) | ❌ | ✅ (work-in-progress) |
|
|
||||||
| pybind11 API (both) | ✅ | ✅ (work-in-progress) |
|
|
||||||
|
|
||||||
## Suggestions
|
|
||||||
|
|
||||||
- If you are a C++ user
|
|
||||||
- Use **pybind11 API** if you want to upgrade to v2.0 in the future
|
|
||||||
- Use **legacy C++ API** if you want to stay in v1.x
|
|
||||||
- If you are a C user
|
|
||||||
- Use **v2.0's C11 API** (will be available soon)
|
|
||||||
- Use **legacy C API** if you want to stay in v1.x
|
|
||||||
291
docs/pybind11.md
291
docs/pybind11.md
@ -1,291 +0,0 @@
|
|||||||
---
|
|
||||||
icon: log
|
|
||||||
title: 'pybind11 User Guide'
|
|
||||||
order: 21
|
|
||||||
---
|
|
||||||
|
|
||||||
## Quick Start
|
|
||||||
|
|
||||||
pkpy provides a [pybind11](https://pybind11.readthedocs.io/en/stable/) compatible layer which allows users to do convenient bindings.
|
|
||||||
|
|
||||||
To begin with, use `py::scoped_interpreter guard{}` to start the interpreter before using any Python objects.
|
|
||||||
Or explicitly call `py::interpreter::initialize()` and `py::interpreter::finalize()`.
|
|
||||||
|
|
||||||
### module
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
#include <pybind11/pybind11.h>
|
|
||||||
namespace py = pybind11;
|
|
||||||
|
|
||||||
PYBIND11_MODULE(example, m) {
|
|
||||||
m.def("add", [](int a, int b) {
|
|
||||||
return a + b;
|
|
||||||
});
|
|
||||||
|
|
||||||
auto math = m.def_submodule("math");
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### function
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
int add(int a, int b) { return a + b; }
|
|
||||||
|
|
||||||
int add(int a, int b, int c) { return a + b + c; }
|
|
||||||
|
|
||||||
void register_function(py::module_& m)
|
|
||||||
{
|
|
||||||
m.def("add", py::overload_cast<int, int>(&add));
|
|
||||||
|
|
||||||
// support function overload
|
|
||||||
m.def("add", py::overload_cast<int, int, int>(&add));
|
|
||||||
|
|
||||||
// bind with default arguments
|
|
||||||
m.def("sub", [](int a, int b) {
|
|
||||||
return a - b;
|
|
||||||
}, py::arg("a") = 1, py::arg("b") = 2);
|
|
||||||
|
|
||||||
// bind *args
|
|
||||||
m.def("add", [](py::args args) {
|
|
||||||
int sum = 0;
|
|
||||||
for (auto& arg : args) {
|
|
||||||
sum += arg.cast<int>();
|
|
||||||
}
|
|
||||||
return sum;
|
|
||||||
});
|
|
||||||
|
|
||||||
// bind **kwargs
|
|
||||||
m.def("add", [](py::kwargs kwargs) {
|
|
||||||
int sum = 0;
|
|
||||||
for (auto item : kwargs) {
|
|
||||||
sum += item.second.cast<int>();
|
|
||||||
}
|
|
||||||
return sum;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### class
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
struct Point
|
|
||||||
{
|
|
||||||
const int x;
|
|
||||||
int y;
|
|
||||||
|
|
||||||
public:
|
|
||||||
Point() : x(0), y(0) {}
|
|
||||||
|
|
||||||
Point(int x, int y) : x(x), y(y) {}
|
|
||||||
|
|
||||||
Point(const Point& p) : x(p.x), y(p.y) {}
|
|
||||||
|
|
||||||
std::string stringfy() const {
|
|
||||||
return "(" + std::to_string(x) + ", " + std::to_string(y) + ")";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Point3D : Point
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
int z;
|
|
||||||
|
|
||||||
public:
|
|
||||||
Point3D(int x, int y, int z) : Point(x, y), z(z) {}
|
|
||||||
|
|
||||||
int get_z() const { return z; }
|
|
||||||
|
|
||||||
void set_z(int z) { this->z = z; }
|
|
||||||
};
|
|
||||||
|
|
||||||
void bind_class(py::module_& m)
|
|
||||||
{
|
|
||||||
py::class_<Point>(m, "Point")
|
|
||||||
.def(py::init<>())
|
|
||||||
.def(py::init<int, int>())
|
|
||||||
.def(py::init<const Point&>())
|
|
||||||
.def_readonly("x", &Point::x)
|
|
||||||
.def_readwrite("y", &Point::y)
|
|
||||||
.def("__str__", &Point::stringfy);
|
|
||||||
|
|
||||||
// only support single inheritance
|
|
||||||
py::class_<Point3D, Point>(m, "Point3D", py::dynamic_attr())
|
|
||||||
.def(py::init<int, int, int>())
|
|
||||||
.def_property("z", &Point3D::get_z, &Point3D::set_z);
|
|
||||||
|
|
||||||
// dynamic_attr will enable the dict of bound class
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### operators
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
#include <pybind11/operators.h>
|
|
||||||
namespace py = pybind11;
|
|
||||||
|
|
||||||
struct Int {
|
|
||||||
int value;
|
|
||||||
|
|
||||||
Int(int value) : value(value) {}
|
|
||||||
|
|
||||||
Int operator+(const Int& other) const {
|
|
||||||
return Int(value + other.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
Int operator-(const Int& other) const {
|
|
||||||
return Int(value - other.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator==(const Int& other) const {
|
|
||||||
return value == other.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator!=(const Int& other) const {
|
|
||||||
return value != other.value;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void bind_operators(py::module_& m)
|
|
||||||
{
|
|
||||||
py::class_<Int>(m, "Int")
|
|
||||||
.def(py::init<int>())
|
|
||||||
.def(py::self + py::self)
|
|
||||||
.def(py::self - py::self)
|
|
||||||
.def(py::self == py::self)
|
|
||||||
.def(py::self != py::self);
|
|
||||||
// other operators are similar
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### py::object
|
|
||||||
|
|
||||||
`py::object` is just simple wrapper around `PyVar`. It supports some convenient methods to interact with Python objects.
|
|
||||||
|
|
||||||
|
|
||||||
here are some common methods:
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
obj.attr("x"); // access attribute
|
|
||||||
obj[1]; // access item
|
|
||||||
|
|
||||||
obj.is_none(); // same as obj is None in Python
|
|
||||||
obj.is(obj2); // same as obj is obj2 in Python
|
|
||||||
|
|
||||||
// operators
|
|
||||||
obj + obj2; // same as obj + obj2 in Python
|
|
||||||
// ...
|
|
||||||
obj == obj2; // same as obj == obj2 in Python
|
|
||||||
// ...
|
|
||||||
|
|
||||||
obj(...); // same as obj.__call__(...)
|
|
||||||
|
|
||||||
py::cast(obj); // cast to Python object
|
|
||||||
obj.cast<T>; // cast to C++ type
|
|
||||||
|
|
||||||
py::type::of(obj); // get type of obj
|
|
||||||
py::type::of<T>(); // get type of T, if T is registered
|
|
||||||
```
|
|
||||||
|
|
||||||
you can also create some builtin objects with their according wrappers:
|
|
||||||
|
|
||||||
```cpp
|
|
||||||
py::bool_ b = {true};
|
|
||||||
py::int_ i = {1};
|
|
||||||
py::float_ f = {1.0};
|
|
||||||
py::str s = {"hello"};
|
|
||||||
py::list l = {1, 2, 3};
|
|
||||||
py::tuple t = {1, 2, 3};
|
|
||||||
// ...
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## More Examples
|
|
||||||
|
|
||||||
More examples please see the test [folder](https://github.com/pocketpy/gsoc-2024-dev/tree/main/pybind11/tests) in the GSoC repository. All tested features are supported.
|
|
||||||
|
|
||||||
## Limits and Comparison
|
|
||||||
|
|
||||||
This is a feature list of pybind11 for pocketpy. It lists all completed and pending features. It also lists the features that cannot be implemented in the current version of pocketpy.
|
|
||||||
|
|
||||||
### [Function](https://pybind11.readthedocs.io/en/stable/advanced/functions.html)
|
|
||||||
|
|
||||||
- [x] Function overloading
|
|
||||||
- [x] Return value policy
|
|
||||||
- [x] is_prepend
|
|
||||||
- [x] `*args` and `**kwargs`
|
|
||||||
- [ ] Keep-alive
|
|
||||||
- [ ] Call Guard
|
|
||||||
- [x] Default arguments
|
|
||||||
- [ ] Keyword-Only arguments
|
|
||||||
- [ ] Positional-Only arguments
|
|
||||||
- [ ] Allow/Prohibiting None arguments
|
|
||||||
|
|
||||||
### [Class](https://pybind11.readthedocs.io/en/stable/classes.html)
|
|
||||||
|
|
||||||
- [x] Creating bindings for a custom type
|
|
||||||
- [x] Binding lambda functions
|
|
||||||
- [x] Dynamic attributes
|
|
||||||
- [x] Inheritance and automatic downcasting
|
|
||||||
- [x] Enumerations and internal types
|
|
||||||
- [ ] Instance and static fields
|
|
||||||
|
|
||||||
> Binding static fields may never be implemented in pocketpy because it requires a metaclass, which is a heavy and infrequently used feature.
|
|
||||||
|
|
||||||
### [Exceptions](https://pybind11.readthedocs.io/en/stable/advanced/exceptions.html)
|
|
||||||
|
|
||||||
Need further discussion.
|
|
||||||
|
|
||||||
### [Smart pointers](https://pybind11.readthedocs.io/en/stable/advanced/smart_ptrs.html)
|
|
||||||
|
|
||||||
- [ ] std::shared_ptr
|
|
||||||
- [ ] std::unique_ptr
|
|
||||||
- [ ] Custom smart pointers
|
|
||||||
|
|
||||||
### [Type conversions](https://pybind11.readthedocs.io/en/stable/advanced/cast/index.html)
|
|
||||||
|
|
||||||
- [x] Python built-in types
|
|
||||||
- [x] STL Containers
|
|
||||||
- [ ] Functional
|
|
||||||
- [ ] Chrono
|
|
||||||
|
|
||||||
### [Python C++ interface](https://pybind11.readthedocs.io/en/stable/advanced/pycpp/object.html)
|
|
||||||
|
|
||||||
Need further discussion.
|
|
||||||
|
|
||||||
- [x] `object`
|
|
||||||
- [x] `none`
|
|
||||||
- [x] `type`
|
|
||||||
- [x] `bool_`
|
|
||||||
- [x] `int_`
|
|
||||||
- [x] `float_`
|
|
||||||
- [x] `str`
|
|
||||||
- [ ] `bytes`
|
|
||||||
- [ ] `bytearray`
|
|
||||||
- [x] `tuple`
|
|
||||||
- [x] `list`
|
|
||||||
- [ ] `set`
|
|
||||||
- [x] `dict`
|
|
||||||
- [ ] `slice`
|
|
||||||
- [x] `iterable`
|
|
||||||
- [x] `iterator`
|
|
||||||
- [ ] `function`
|
|
||||||
- [ ] `buffer`
|
|
||||||
- [ ] `memoryview`
|
|
||||||
- [x] `capsule`
|
|
||||||
|
|
||||||
### [Miscellaneous](https://pybind11.readthedocs.io/en/stable/advanced/misc.html)
|
|
||||||
|
|
||||||
- [ ] Global Interpreter Lock (GIL)
|
|
||||||
- [ ] Binding sequence data types, iterators, the slicing protocol, etc.
|
|
||||||
- [x] Convenient operators binding
|
|
||||||
|
|
||||||
### Differences between CPython and pocketpy
|
|
||||||
|
|
||||||
- only `add`, `sub` and `mul` have corresponding right versions in pocketpy. So if you bind `int() >> py::self`, it will has no effect in pocketpy.
|
|
||||||
|
|
||||||
- `__new__` and `__del__` are not supported in pocketpy.
|
|
||||||
|
|
||||||
- in-place operators, such as `+=`, `-=`, `*=`, etc., are not supported in pocketpy.
|
|
||||||
|
|
||||||
- thre return value of `globals` is immutable in pocketpy.
|
|
||||||
@ -3,7 +3,7 @@ output: .retype
|
|||||||
url: https://pocketpy.dev
|
url: https://pocketpy.dev
|
||||||
branding:
|
branding:
|
||||||
title: pocketpy
|
title: pocketpy
|
||||||
label: v1.4.6
|
label: v1.5.0
|
||||||
logo: "./static/logo.png"
|
logo: "./static/logo.png"
|
||||||
favicon: "./static/logo.png"
|
favicon: "./static/logo.png"
|
||||||
meta:
|
meta:
|
||||||
@ -16,10 +16,10 @@ links:
|
|||||||
icon: play
|
icon: play
|
||||||
link: "https://pocketpy.dev/static/web/"
|
link: "https://pocketpy.dev/static/web/"
|
||||||
target: blank
|
target: blank
|
||||||
# - text: "Live Examples"
|
- text: "Live Examples"
|
||||||
# icon: play
|
icon: play
|
||||||
# link: "https://pocketpy.github.io/examples/"
|
link: "https://pocketpy.github.io/examples/"
|
||||||
# target: blank
|
target: blank
|
||||||
- text: "Github"
|
- text: "Github"
|
||||||
icon: mark-github
|
icon: mark-github
|
||||||
link: https://github.com/blueloveth/pocketpy
|
link: https://github.com/blueloveth/pocketpy
|
||||||
|
|||||||
@ -20,10 +20,10 @@
|
|||||||
#include <typeindex>
|
#include <typeindex>
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
|
|
||||||
#define PK_VERSION "1.4.6"
|
#define PK_VERSION "1.5.0"
|
||||||
#define PK_VERSION_MAJOR 1
|
#define PK_VERSION_MAJOR 1
|
||||||
#define PK_VERSION_MINOR 4
|
#define PK_VERSION_MINOR 5
|
||||||
#define PK_VERSION_PATCH 6
|
#define PK_VERSION_PATCH 0
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "export.h"
|
#include "export.h"
|
||||||
|
|||||||
@ -81,13 +81,9 @@ inline bool isinstance(const handle& obj, const handle& type) {
|
|||||||
|
|
||||||
inline int64_t hash(const handle& obj) { return vm->py_hash(obj.ptr()); }
|
inline int64_t hash(const handle& obj) { return vm->py_hash(obj.ptr()); }
|
||||||
|
|
||||||
namespace impl {
|
|
||||||
|
|
||||||
template <typename T, typename SFINAE = void>
|
template <typename T, typename SFINAE = void>
|
||||||
struct type_caster;
|
struct type_caster;
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
handle cast(T&& value, return_value_policy policy, handle parent) {
|
handle cast(T&& value, return_value_policy policy, handle parent) {
|
||||||
// decay_t can resolve c-array type, but remove_cv_ref_t can't.
|
// decay_t can resolve c-array type, but remove_cv_ref_t can't.
|
||||||
@ -111,7 +107,7 @@ handle cast(T&& value, return_value_policy policy, handle parent) {
|
|||||||
: return_value_policy::move;
|
: return_value_policy::move;
|
||||||
}
|
}
|
||||||
|
|
||||||
return impl::type_caster<underlying_type>::cast(std::forward<T>(value), policy, parent);
|
return type_caster<underlying_type>::cast(std::forward<T>(value), policy, parent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,7 +115,7 @@ template <typename T>
|
|||||||
T cast(const handle& obj, bool convert) {
|
T cast(const handle& obj, bool convert) {
|
||||||
assert(obj.ptr() != nullptr);
|
assert(obj.ptr() != nullptr);
|
||||||
|
|
||||||
impl::type_caster<T> caster = {};
|
type_caster<T> caster = {};
|
||||||
|
|
||||||
if(caster.load(obj, convert)) {
|
if(caster.load(obj, convert)) {
|
||||||
return caster.value;
|
return caster.value;
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
#include "instance.h"
|
#include "instance.h"
|
||||||
#include "accessor.h"
|
#include "accessor.h"
|
||||||
|
|
||||||
namespace pybind11::impl {
|
namespace pybind11 {
|
||||||
|
|
||||||
using pkpy::is_floating_point_v;
|
using pkpy::is_floating_point_v;
|
||||||
using pkpy::is_integral_v;
|
using pkpy::is_integral_v;
|
||||||
|
|||||||
@ -169,15 +169,15 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum_& value(const char* name, T value) {
|
enum_& value(const char* name, T value) {
|
||||||
handle var = pybind11::cast(value, return_value_policy::copy);
|
handle var = type_caster<T>::cast(value, return_value_policy::copy);
|
||||||
setattr(*this, name, var);
|
this->m_ptr->attr().set(name, var.ptr());
|
||||||
m_values.emplace_back(name, var);
|
m_values.emplace_back(name, var);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum_& export_values() {
|
enum_& export_values() {
|
||||||
for(auto& [name, value]: m_values) {
|
for(auto& [name, value]: m_values) {
|
||||||
setattr(Base::m_scope, name, value);
|
Base::m_scope.ptr()->attr().set(name, value.ptr());
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -176,7 +176,7 @@ public:
|
|||||||
template <typename Fn, std::size_t... Is, typename... Args>
|
template <typename Fn, std::size_t... Is, typename... Args>
|
||||||
handle invoke(Fn&& fn,
|
handle invoke(Fn&& fn,
|
||||||
std::index_sequence<Is...>,
|
std::index_sequence<Is...>,
|
||||||
std::tuple<impl::type_caster<Args>...>& casters,
|
std::tuple<type_caster<Args>...>& casters,
|
||||||
return_value_policy policy,
|
return_value_policy policy,
|
||||||
handle parent) {
|
handle parent) {
|
||||||
using underlying_type = std::decay_t<Fn>;
|
using underlying_type = std::decay_t<Fn>;
|
||||||
@ -361,10 +361,10 @@ struct template_parser<Callable, std::tuple<Extras...>, std::tuple<Args...>, std
|
|||||||
|
|
||||||
// resolve keyword arguments
|
// resolve keyword arguments
|
||||||
const auto n = vm->s_data._sp - view.end();
|
const auto n = vm->s_data._sp - view.end();
|
||||||
int index = 0;
|
std::size_t index = 0;
|
||||||
|
|
||||||
if constexpr(named_argc > 0) {
|
if constexpr(named_argc > 0) {
|
||||||
int arg_index = 0;
|
std::size_t arg_index = 0;
|
||||||
auto& arguments = *record.arguments;
|
auto& arguments = *record.arguments;
|
||||||
|
|
||||||
while(arg_index < named_argc && index < n) {
|
while(arg_index < named_argc && index < n) {
|
||||||
@ -403,7 +403,7 @@ struct template_parser<Callable, std::tuple<Extras...>, std::tuple<Args...>, std
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ok, all the arguments are valid, call the function
|
// ok, all the arguments are valid, call the function
|
||||||
std::tuple<impl::type_caster<Args>...> casters;
|
std::tuple<type_caster<Args>...> casters;
|
||||||
|
|
||||||
// check type compatibility
|
// check type compatibility
|
||||||
if(((std::get<Is>(casters).load(stack[Is], convert)) && ...)) {
|
if(((std::get<Is>(casters).load(stack[Is], convert)) && ...)) {
|
||||||
@ -489,14 +489,14 @@ pkpy::PyVar setter_wrapper(pkpy::VM* vm, pkpy::ArgsView view) {
|
|||||||
|
|
||||||
if constexpr(std::is_member_object_pointer_v<Setter>) {
|
if constexpr(std::is_member_object_pointer_v<Setter>) {
|
||||||
// specialize for pointer to data member
|
// specialize for pointer to data member
|
||||||
impl::type_caster<member_type_t<Setter>> caster;
|
type_caster<member_type_t<Setter>> caster;
|
||||||
if(caster.load(view[1], true)) {
|
if(caster.load(view[1], true)) {
|
||||||
self.*setter = caster.value;
|
self.*setter = caster.value;
|
||||||
return vm->None;
|
return vm->None;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// specialize for pointer to member function
|
// specialize for pointer to member function
|
||||||
impl::type_caster<std::tuple_element_t<1, callable_args_t<Setter>>> caster;
|
type_caster<std::tuple_element_t<1, callable_args_t<Setter>>> caster;
|
||||||
if(caster.load(view[1], true)) {
|
if(caster.load(view[1], true)) {
|
||||||
(self.*setter)(caster.value);
|
(self.*setter)(caster.value);
|
||||||
return vm->None;
|
return vm->None;
|
||||||
@ -507,7 +507,7 @@ pkpy::PyVar setter_wrapper(pkpy::VM* vm, pkpy::ArgsView view) {
|
|||||||
using Self = remove_cvref_t<std::tuple_element_t<0, callable_args_t<Setter>>>;
|
using Self = remove_cvref_t<std::tuple_element_t<0, callable_args_t<Setter>>>;
|
||||||
auto& self = handle(view[0])._as<instance>()._as<Self>();
|
auto& self = handle(view[0])._as<instance>()._as<Self>();
|
||||||
|
|
||||||
impl::type_caster<std::tuple_element_t<1, callable_args_t<Setter>>> caster;
|
type_caster<std::tuple_element_t<1, callable_args_t<Setter>>> caster;
|
||||||
if(caster.load(view[1], true)) {
|
if(caster.load(view[1], true)) {
|
||||||
setter(self, caster.value);
|
setter(self, caster.value);
|
||||||
return vm->None;
|
return vm->None;
|
||||||
|
|||||||
@ -37,7 +37,7 @@ class handle;
|
|||||||
class object;
|
class object;
|
||||||
class iterator;
|
class iterator;
|
||||||
class str;
|
class str;
|
||||||
struct arg;
|
class arg;
|
||||||
struct args_proxy;
|
struct args_proxy;
|
||||||
struct kwargs_proxy;
|
struct kwargs_proxy;
|
||||||
|
|
||||||
@ -210,7 +210,12 @@ constexpr inline bool is_pyobject_v = std::is_base_of_v<object, T>;
|
|||||||
#if PK_VERSION_MAJOR == 2
|
#if PK_VERSION_MAJOR == 2
|
||||||
using error_already_set = pkpy::TopLevelException;
|
using error_already_set = pkpy::TopLevelException;
|
||||||
#else
|
#else
|
||||||
using error_already_set = pkpy::Exception;
|
class error_already_set : std::exception {
|
||||||
|
public:
|
||||||
|
error_already_set() = default;
|
||||||
|
|
||||||
|
const char* what() const noexcept override { return "An error occurred while calling a Python function."; }
|
||||||
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
inline void setattr(const handle& obj, const handle& name, const handle& value);
|
inline void setattr(const handle& obj, const handle& name, const handle& value);
|
||||||
|
|||||||
@ -19,10 +19,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
module_ def_submodule(const char* name, const char* doc = nullptr) {
|
module_ def_submodule(const char* name, const char* doc = nullptr) {
|
||||||
// TODO: resolve package
|
auto package = this->package()._as<pkpy::Str>() + "." + this->name()._as<pkpy::Str>();
|
||||||
//auto package = this->package()._as<pkpy::Str>() + "." + this->name()._as<pkpy::Str>();
|
auto m = vm->new_module(name, package);
|
||||||
auto fname = this->name()._as<pkpy::Str>() + "." + name;
|
|
||||||
auto m = vm->new_module(fname, "");
|
|
||||||
setattr(*this, name, m);
|
setattr(*this, name, m);
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -69,19 +69,15 @@ public:
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
decltype(auto) _as() const {
|
decltype(auto) _as() const {
|
||||||
static_assert(!std::is_reference_v<T>, "T must not be a reference type.");
|
static_assert(!std::is_reference_v<T>, "T must not be a reference type.");
|
||||||
if constexpr(std::is_same_v<T, empty>) {
|
|
||||||
return empty();
|
|
||||||
} else {
|
|
||||||
#if PK_VERSION_MAJOR == 2
|
#if PK_VERSION_MAJOR == 2
|
||||||
if constexpr(pkpy::is_sso_v<T>) {
|
if constexpr(pkpy::is_sso_v<T>) {
|
||||||
return pkpy::_py_cast<T>(vm, ptr());
|
return pkpy::_py_cast<T>(vm, ptr());
|
||||||
} else {
|
} else {
|
||||||
return ptr().template obj_get<T>();
|
return ptr().template obj_get<T>();
|
||||||
}
|
|
||||||
#else
|
|
||||||
return (((pkpy::Py_<T>*)ptr())->_value);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
return (((pkpy::Py_<T>*)ptr())->_value);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -25,9 +25,9 @@ struct function_traits {
|
|||||||
static_assert(dependent_false<Fn>, "unsupported function type");
|
static_assert(dependent_false<Fn>, "unsupported function type");
|
||||||
};
|
};
|
||||||
|
|
||||||
#define PYBIND11_FUNCTION_TRAITS_SPECIALIZE(...) \
|
#define PYBIND11_FUNCTION_TRAITS_SPECIALIZE(qualifiers) \
|
||||||
template <typename R, typename... Args> \
|
template <typename R, typename... Args> \
|
||||||
struct function_traits<R(Args...) __VA_ARGS__> { \
|
struct function_traits<R(Args...) qualifiers> { \
|
||||||
using return_type = R; \
|
using return_type = R; \
|
||||||
using args_type = std::tuple<Args...>; \
|
using args_type = std::tuple<Args...>; \
|
||||||
constexpr static std::size_t args_count = sizeof...(Args); \
|
constexpr static std::size_t args_count = sizeof...(Args); \
|
||||||
@ -167,32 +167,4 @@ constexpr auto type_name() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename... Args>
|
|
||||||
struct overload_cast_t {
|
|
||||||
template <typename Return>
|
|
||||||
constexpr auto operator() (Return (*pf)(Args...)) const noexcept -> decltype(pf) {
|
|
||||||
return pf;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Return, typename Class>
|
|
||||||
constexpr auto operator() (Return (Class::*pmf)(Args...), std::false_type = {}) const noexcept -> decltype(pmf) {
|
|
||||||
return pmf;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Return, typename Class>
|
|
||||||
constexpr auto operator() (Return (Class::*pmf)(Args...) const, std::true_type) const noexcept -> decltype(pmf) {
|
|
||||||
return pmf;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Syntax sugar for resolving overloaded function pointers:
|
|
||||||
/// - regular: static_cast<Return (Class::*)(Arg0, Arg1, Arg2)>(&Class::func)
|
|
||||||
/// - sweet: overload_cast<Arg0, Arg1, Arg2>(&Class::func)
|
|
||||||
template <typename... Args>
|
|
||||||
constexpr inline overload_cast_t<Args...> overload_cast;
|
|
||||||
|
|
||||||
/// Const member function selector for overload_cast
|
|
||||||
/// - regular: static_cast<Return (Class::*)(Arg) const>(&Class::func)
|
|
||||||
/// - sweet: overload_cast<Arg>(&Class::func, const_)
|
|
||||||
constexpr static auto const_ = std::true_type{};
|
|
||||||
} // namespace pybind11
|
} // namespace pybind11
|
||||||
|
|||||||
@ -49,11 +49,6 @@ public:
|
|||||||
return type_visitor::type<T>();
|
return type_visitor::type<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
static type of() {
|
|
||||||
return type_visitor::type<T>();
|
|
||||||
}
|
|
||||||
|
|
||||||
static type of(const handle& obj) { return type(vm->_t(obj.ptr())); }
|
static type of(const handle& obj) { return type(vm->_t(obj.ptr())); }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -390,11 +385,11 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
class args : public tuple {
|
class args : public tuple {
|
||||||
PYBIND11_TYPE_IMPLEMENT(tuple, pybind11::empty, vm->tp_tuple);
|
PYBIND11_TYPE_IMPLEMENT(tuple, struct empty, vm->tp_tuple);
|
||||||
};
|
};
|
||||||
|
|
||||||
class kwargs : public dict {
|
class kwargs : public dict {
|
||||||
PYBIND11_TYPE_IMPLEMENT(dict, pybind11::empty, vm->tp_dict);
|
PYBIND11_TYPE_IMPLEMENT(dict, struct empty, vm->tp_dict);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace pybind11
|
} // namespace pybind11
|
||||||
|
|||||||
@ -9,7 +9,7 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
namespace pybind11::impl {
|
namespace pybind11 {
|
||||||
|
|
||||||
template <typename T, std::size_t N>
|
template <typename T, std::size_t N>
|
||||||
struct type_caster<std::array<T, N>> {
|
struct type_caster<std::array<T, N>> {
|
||||||
@ -140,5 +140,5 @@ struct type_caster<T, std::enable_if_t<is_py_map_like_v<T>>> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace pybind11::impl
|
} // namespace pybind11
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user