mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 03:20:18 +00:00
Compare commits
16 Commits
fece79b169
...
4ba0b7d2e2
Author | SHA1 | Date | |
---|---|---|---|
|
4ba0b7d2e2 | ||
|
2d6def4bbd | ||
|
a5a3c75b83 | ||
|
8ffcacf99f | ||
|
a2cb91b125 | ||
|
86006d0b61 | ||
|
a08c5af6e9 | ||
|
475be8ce80 | ||
|
12d748ba7d | ||
|
0c1bd532f8 | ||
|
d52cbec80c | ||
|
e16aa501ef | ||
|
59bbecdbee | ||
|
f5c356a047 | ||
|
68f8cd1159 | ||
|
259394d7ad |
37
README.md
37
README.md
@ -25,7 +25,8 @@ 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
|
||||||
|
|
||||||
@ -90,39 +91,33 @@ python scripts/run_tests.py
|
|||||||
### Example
|
### Example
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
#include "pocketpy.h"
|
#include <pybind11/pybind11.h>
|
||||||
|
|
||||||
using namespace pkpy;
|
namespace py = pybind11;
|
||||||
|
|
||||||
int main(){
|
int main() {
|
||||||
// Create a virtual machine
|
// Start the interpreter
|
||||||
VM* vm = new VM();
|
py::scoped_interpreter guard{};
|
||||||
|
|
||||||
// Hello world!
|
// Hello world!
|
||||||
vm->exec("print('Hello world!')");
|
py::exec("print('Hello world!')");
|
||||||
|
|
||||||
// Create a list
|
// Create a list
|
||||||
vm->exec("a = [1, 2, 3]");
|
py::exec("a = [1, 2, 3]");
|
||||||
|
|
||||||
// Eval the sum of the list
|
// Eval the sum of the list
|
||||||
PyVar result = vm->eval("sum(a)");
|
auto result = py::eval("sum(a)");
|
||||||
std::cout << "Sum of the list: "<< py_cast<int>(vm, result) << std::endl; // 6
|
std::cout << "Sum of the list: " << result.cast<int>() << std::endl; // 6
|
||||||
|
|
||||||
// Bindings
|
// Bindings
|
||||||
vm->bind(vm->_main, "add(a: int, b: int)",
|
auto m = py::module_::__main__();
|
||||||
[](VM* vm, ArgsView args){
|
m.def("add", [](int a, int b) {
|
||||||
int a = py_cast<int>(vm, args[0]);
|
return a + b;
|
||||||
int b = py_cast<int>(vm, args[1]);
|
});
|
||||||
return py_var(vm, a + b);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Call the function
|
// Call the function
|
||||||
PyVar f_add = vm->_main->attr("add");
|
std::cout << "Sum of 2 variables: " << m.attr("add")(1, 2).cast<int>() << std::endl; // 10
|
||||||
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;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -1,333 +0,0 @@
|
|||||||
---
|
|
||||||
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,6 +5,12 @@ 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.
|
||||||
|
32
docs/migrate.md
Normal file
32
docs/migrate.md
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
---
|
||||||
|
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
Normal file
291
docs/pybind11.md
Normal file
@ -0,0 +1,291 @@
|
|||||||
|
---
|
||||||
|
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.5.0
|
label: v1.4.6
|
||||||
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.5.0"
|
#define PK_VERSION "1.4.6"
|
||||||
#define PK_VERSION_MAJOR 1
|
#define PK_VERSION_MAJOR 1
|
||||||
#define PK_VERSION_MINOR 5
|
#define PK_VERSION_MINOR 4
|
||||||
#define PK_VERSION_PATCH 0
|
#define PK_VERSION_PATCH 6
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "export.h"
|
#include "export.h"
|
||||||
|
@ -81,9 +81,13 @@ 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.
|
||||||
@ -107,7 +111,7 @@ handle cast(T&& value, return_value_policy policy, handle parent) {
|
|||||||
: return_value_policy::move;
|
: return_value_policy::move;
|
||||||
}
|
}
|
||||||
|
|
||||||
return type_caster<underlying_type>::cast(std::forward<T>(value), policy, parent);
|
return impl::type_caster<underlying_type>::cast(std::forward<T>(value), policy, parent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,7 +119,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);
|
||||||
|
|
||||||
type_caster<T> caster = {};
|
impl::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 {
|
namespace pybind11::impl {
|
||||||
|
|
||||||
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 = type_caster<T>::cast(value, return_value_policy::copy);
|
handle var = pybind11::cast(value, return_value_policy::copy);
|
||||||
this->m_ptr->attr().set(name, var.ptr());
|
setattr(*this, name, var);
|
||||||
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) {
|
||||||
Base::m_scope.ptr()->attr().set(name, value.ptr());
|
setattr(Base::m_scope, name, value);
|
||||||
}
|
}
|
||||||
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<type_caster<Args>...>& casters,
|
std::tuple<impl::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();
|
||||||
std::size_t index = 0;
|
int index = 0;
|
||||||
|
|
||||||
if constexpr(named_argc > 0) {
|
if constexpr(named_argc > 0) {
|
||||||
std::size_t arg_index = 0;
|
int 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<type_caster<Args>...> casters;
|
std::tuple<impl::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
|
||||||
type_caster<member_type_t<Setter>> caster;
|
impl::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
|
||||||
type_caster<std::tuple_element_t<1, callable_args_t<Setter>>> caster;
|
impl::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>();
|
||||||
|
|
||||||
type_caster<std::tuple_element_t<1, callable_args_t<Setter>>> caster;
|
impl::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;
|
||||||
class arg;
|
struct arg;
|
||||||
struct args_proxy;
|
struct args_proxy;
|
||||||
struct kwargs_proxy;
|
struct kwargs_proxy;
|
||||||
|
|
||||||
@ -210,12 +210,7 @@ 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
|
||||||
class error_already_set : std::exception {
|
using error_already_set = pkpy::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,8 +19,10 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
module_ def_submodule(const char* name, const char* doc = nullptr) {
|
module_ def_submodule(const char* name, const char* doc = nullptr) {
|
||||||
auto package = this->package()._as<pkpy::Str>() + "." + this->name()._as<pkpy::Str>();
|
// TODO: resolve package
|
||||||
auto m = vm->new_module(name, package);
|
//auto package = this->package()._as<pkpy::Str>() + "." + this->name()._as<pkpy::Str>();
|
||||||
|
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,15 +69,19 @@ 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 PK_VERSION_MAJOR == 2
|
if constexpr(std::is_same_v<T, empty>) {
|
||||||
if constexpr(pkpy::is_sso_v<T>) {
|
return empty();
|
||||||
return pkpy::_py_cast<T>(vm, ptr());
|
|
||||||
} else {
|
} else {
|
||||||
return ptr().template obj_get<T>();
|
#if PK_VERSION_MAJOR == 2
|
||||||
}
|
if constexpr(pkpy::is_sso_v<T>) {
|
||||||
|
return pkpy::_py_cast<T>(vm, ptr());
|
||||||
|
} else {
|
||||||
|
return ptr().template obj_get<T>();
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
return (((pkpy::Py_<T>*)ptr())->_value);
|
return (((pkpy::Py_<T>*)ptr())->_value);
|
||||||
#endif
|
#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(qualifiers) \
|
#define PYBIND11_FUNCTION_TRAITS_SPECIALIZE(...) \
|
||||||
template <typename R, typename... Args> \
|
template <typename R, typename... Args> \
|
||||||
struct function_traits<R(Args...) qualifiers> { \
|
struct function_traits<R(Args...) __VA_ARGS__> { \
|
||||||
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,4 +167,32 @@ 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,6 +49,11 @@ 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())); }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -385,11 +390,11 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
class args : public tuple {
|
class args : public tuple {
|
||||||
PYBIND11_TYPE_IMPLEMENT(tuple, struct empty, vm->tp_tuple);
|
PYBIND11_TYPE_IMPLEMENT(tuple, pybind11::empty, vm->tp_tuple);
|
||||||
};
|
};
|
||||||
|
|
||||||
class kwargs : public dict {
|
class kwargs : public dict {
|
||||||
PYBIND11_TYPE_IMPLEMENT(dict, struct empty, vm->tp_dict);
|
PYBIND11_TYPE_IMPLEMENT(dict, pybind11::empty, vm->tp_dict);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace pybind11
|
} // namespace pybind11
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
namespace pybind11 {
|
namespace pybind11::impl {
|
||||||
|
|
||||||
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
|
} // namespace pybind11::impl
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user