| 1 |
- [[{"l":"Welcome to pocketpy","p":["pocketpy is a portable Python 3.x interpreter, written in C11. It aims to be an alternative to Lua for game scripting, with elegant syntax, powerful features and competitive performance. pocketpy has no dependencies other than the C standard library, which can be easily integrated into your C/C++ project. Developers are able to write Python bindings via C-API or pybind11 compatible interfaces.","Live Python Demo: Run Python code in your browser","Live C Examples: Explore C-APIs in your browser","Godot Extension: Use pocketpy in Godot Engine","VSCode Extension: Debug and profile pocketpy scripts in VSCode","Flutter Plugin: Use pocketpy in Flutter apps","Raylib Bindings: Use raylib with pocketpy"]},{"l":"What it looks like"},{"i":"what-it-looks-like-code-1","c":["def is_prime(x):\n if x < 2:\n return False\n for i in range(2, x):\n if x % i == 0:\n return False\n return True\n\nprimes = [i for i in range(2, 20) if is_prime(i)]\nprint(primes)\n# [2, 3, 5, 7, 11, 13, 17, 19]"]},{"l":"Supported platforms","p":["pkpy should work on any platform with a C11 compiler. These platforms are officially tested.","Windows 64-bit","Linux 64-bit / 32-bit","macOS 64-bit","Android 64-bit / 32-bit","iOS 64-bit","Emscripten 32-bit","Raspberry Pi OS 64-bit","Luckfox Pico SDK 32-bit","On Windows platform, only MSVC compiler is officially supported."]},{"l":"Star the repo","p":["If you find pkpy useful, consider star this repository (●'◡'●)"]},{"l":"Sponsor this project","p":["You can sponsor this project via these ways.","Github Sponsors","Buy me a coffee","Your sponsorship will help us develop pkpy continuously."]},{"l":"Upgrade to v2.0","p":["pkpy v2.0 is a C11 project instead of C++17. All your existing code for v1.x won't work anymore.","We provide two API sets for v2.0, C-API and pybind11 API (C++17). If you are a C user, use the C-API. If you are a C++ user, use the pybind11 API."]}],[{"l":"Quick Start","p":["You have two options to integrate pkpy into your project."]},{"l":"Use CMake (Recommended)","p":["Clone the whole repository as a submodule into your project, In your CMakelists.txt, add the following lines:","See CMakeLists.txt for details.","It is safe to use main branch in production if CI badge is green."]},{"i":"use-cmake-recommended-code-1","c":["add_subdirectory(pocketpy)\ntarget_link_libraries(<your_target> pocketpy)"]},{"l":"Use the single header file","p":["Download the pocketpy.h and pocketpy.c on our GitHub Release page. And #include it in your project."]},{"l":"Compile flags","p":["To compile it with your project, these flags must be set:","--std=c11 flag must be set","For MSVC, /utf-8 and /experimental:c11atomics flag must be set","NDEBUG macro should be defined for release build, or you will get poor performance"]},{"l":"Get prebuilt binaries","p":["We have prebuilt binaries, check them out on our GitHub Actions.","You can download an artifact there which contains the following files."]},{"i":"get-prebuilt-binaries-code-1","c":["├── android\n│\u00A0\u00A0 ├── arm64-v8a\n│\u00A0\u00A0 │\u00A0\u00A0 └── libpocketpy.so\n│\u00A0\u00A0 ├── armeabi-v7a\n│\u00A0\u00A0 │\u00A0\u00A0 └── libpocketpy.so\n│\u00A0\u00A0 └── x86_64\n│\u00A0\u00A0 └── libpocketpy.so\n├── ios\n│\u00A0\u00A0 └── libpocketpy.a\n├── linux\n│\u00A0\u00A0 └── x86_64\n│\u00A0\u00A0 ├── libpocketpy.so\n│\u00A0\u00A0 └── main\n└── windows\n └── x86_64\n ├── main.exe\n └── pocketpy.dll"]},{"l":"Example"},{"i":"example-code-1","c":["#include \"pocketpy.h\"\n#include <stdio.h>\n\nstatic bool int_add(int argc, py_Ref argv) {\n PY_CHECK_ARGC(2);\n PY_CHECK_ARG_TYPE(0, tp_int);\n PY_CHECK_ARG_TYPE(1, tp_int);\n py_i64 a = py_toint(py_arg(0));\n py_i64 b = py_toint(py_arg(1));\n py_newint(py_retval(), a + b);\n return true;\n}\n\nint main() {\n // Initialize pocketpy\n py_initialize();\n\n // Hello world!\n bool ok = py_exec(\"print('Hello world!')\", \"<string>\", EXEC_MODE, NULL);\n if(!ok) goto __ERROR;\n\n // Create a list: [1, 2, 3]\n py_Ref r0 = py_tmpr0();\n py_newlistn(r0, 3);\n py_newint(py_list_getitem(r0, 0), 1);\n py_newint(py_list_getitem(r0, 1), 2);\n py_newint(py_list_getitem(r0, 2), 3);\n\n // Eval the sum of the list\n py_Ref f_sum = py_getbuiltin(py_name(\"sum\"));\n py_push(f_sum);\n py_pushnil();\n py_push(r0);\n ok = py_vectorcall(1, 0);\n if(!ok) goto __ERROR;\n\n printf(\"Sum of the list: %d\\n\", (int)py_toint(py_retval())); // 6\n\n // Bind native `int_add` as a global variable\n py_newnativefunc(r0, int_add);\n py_setglobal(py_name(\"add\"), r0);\n\n // Call `add` in python\n ok = py_exec(\"add(3, 7)\", \"<string>\", EVAL_MODE, NULL);\n if(!ok) goto __ERROR;\n\n py_i64 res = py_toint(py_retval());\n printf(\"Sum of 2 variables: %d\\n\", (int)res); // 10\n\n py_finalize();\n return 0;\n\n__ERROR:\n py_printexc();\n py_finalize();\n return 1;\n}"]}],[{"l":"Write C Bindings","p":["In order to use a C/C++ library in python, you need to write bindings for it.","pkpy uses an universal signature to wrap a C function pointer as a python function or method, i.e py_CFunction.","argc is the number of arguments passed to the function.","argv is the pointer to the first argument.","If successful, the function should return true and set the return value in py_retval(). In case there is no return value, you should use py_newnone(py_retval()). If an error occurs, the function should raise an exception and return false."]},{"i":"write-c-bindings-code-1","c":["typedef bool (*py_CFunction)(int argc, py_Ref argv);"]},{"l":"Steps","p":["Say you have a function add that takes two integers and returns their sum.","Here is how you can write the binding for it:","Once you have the wrapper function, you can bind it to a python module via py_bindfunc.","Alternatively, you can use py_bind with a signature, which allows you to specify some default values.","See also:","py_bind","py_bindmethod","py_bindfunc","py_bindproperty","py_newmodule","py_newtype"]},{"i":"steps-code-1","c":["int add(int a, int b) {\n return a + b;\n}"]},{"i":"steps-code-2","c":["// 1. Define a wrapper function with the signature `py_CFunction`.\nbool py_add(int argc, py_Ref argv) {\n // 2. Check the number of arguments.\n PY_CHECK_ARGC(2);\n // 3. Check the type of arguments.\n PY_CHECK_ARG_TYPE(0, tp_int);\n PY_CHECK_ARG_TYPE(1, tp_int);\n // 4. Convert the arguments into C types.\n int _0 = py_toint(py_arg(0));\n int _1 = py_toint(py_arg(1));\n // 5. Call the original function.\n int res = add(_0, _1);\n // 6. Set the return value.\n py_newint(py_retval(), res);\n // 7. Return `true`.\n return true;\n}"]},{"i":"steps-code-3","c":["py_GlobalRef mod = py_getmodule(\"__main__\");\npy_bindfunc(mod, \"add\", py_add);"]},{"i":"steps-code-4","c":["py_GlobalRef mod = py_getmodule(\"__main__\");\npy_bind(mod, \"add(a, b=1)\", py_add);"]}],[{"l":"Write C++ Bindings"},{"l":"Quick Start","p":["pkpy provides a pybind11 compatible layer which allows users to do convenient bindings. Header files are located in the include/pybind11 directory. Make sure you have added -Iinclude to your compiler flags.","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()."]},{"l":"module"},{"i":"module-code-1","c":["#include <pybind11/pybind11.h>\nnamespace py = pybind11;\n\nPYBIND11_EMBEDDED_MODULE(example, m) {\n m.def(\"add\", [](int a, int b) {\n return a + b;\n });\n\n auto math = m.def_submodule(\"math\");\n}"]},{"l":"function"},{"i":"function-code-1","c":["int add(int a, int b) { return a + b; }\n\nint add(int a, int b, int c) { return a + b + c; }\n\nvoid register_function(py::module_& m)\n{\n m.def(\"add\", py::overload_cast<int, int>(&add));\n\n // support function overload\n m.def(\"add\", py::overload_cast<int, int, int>(&add));\n\n // bind with default arguments\n m.def(\"sub\", [](int a, int b) { \n return a - b; \n }, py::arg(\"a\") = 1, py::arg(\"b\") = 2);\n\n // bind *args\n m.def(\"add\", [](py::args args) {\n int sum = 0;\n for (auto& arg : args) {\n sum += arg.cast<int>();\n }\n return sum;\n });\n\n // bind **kwargs\n m.def(\"add\", [](py::kwargs kwargs) {\n int sum = 0;\n for (auto item : kwargs) {\n sum += item.second.cast<int>();\n }\n return sum;\n });\n}"]},{"l":"class"},{"i":"class-code-1","c":["struct Point\n{\n const int x;\n int y;\n\npublic:\n Point() : x(0), y(0) {}\n\n Point(int x, int y) : x(x), y(y) {}\n\n Point(const Point& p) : x(p.x), y(p.y) {}\n\n std::string stringfy() const { \n return \"(\" + std::to_string(x) + \", \" + std::to_string(y) + \")\"; \n }\n};\n\nstruct Point3D : Point\n{\nprivate:\n int z;\n\npublic:\n Point3D(int x, int y, int z) : Point(x, y), z(z) {}\n\n int get_z() const { return z; }\n\n void set_z(int z) { this->z = z; }\n};\n\nvoid bind_class(py::module_& m)\n{\n py::class_<Point>(m, \"Point\")\n .def(py::init<>())\n .def(py::init<int, int>())\n .def(py::init<const Point&>())\n .def_readonly(\"x\", &Point::x)\n .def_readwrite(\"y\", &Point::y)\n .def(\"__str__\", &Point::stringfy);\n\n // only support single inheritance\n py::class_<Point3D, Point>(m, \"Point3D\", py::dynamic_attr())\n .def(py::init<int, int, int>())\n .def_property(\"z\", &Point3D::get_z, &Point3D::set_z);\n\n // dynamic_attr will enable the dict of bound class\n}"]},{"l":"operators"},{"i":"operators-code-1","c":["#include <pybind11/operators.h>\nnamespace py = pybind11;\n\nstruct Int {\n int value;\n\n Int(int value) : value(value) {}\n\n Int operator+(const Int& other) const {\n return Int(value + other.value);\n }\n\n Int operator-(const Int& other) const {\n return Int(value - other.value);\n }\n\n bool operator==(const Int& other) const {\n return value == other.value;\n }\n\n bool operator!=(const Int& other) const {\n return value != other.value;\n }\n};\n\nvoid bind_operators(py::module_& m)\n{\n py::class_<Int>(m, \"Int\")\n .def(py::init<int>())\n .def(py::self + py::self)\n .def(py::self - py::self)\n .def(py::self == py::self)\n .def(py::self != py::self);\n // other operators are similar\n}"]},{"l":"py::object","p":["py::object is just simple wrapper around PyVar. It supports some convenient methods to interact with Python objects.","here are some common methods:","you can also create some builtin objects with their according wrappers:"]},{"i":"pyobject-code-1","c":["obj.attr(\"x\"); // access attribute\nobj[1]; // access item\n\nobj.is_none(); // same as obj is None in Python\nobj.is(obj2); // same as obj is obj2 in Python\n\n// operators\nobj + obj2; // same as obj + obj2 in Python\n// ...\nobj == obj2; // same as obj == obj2 in Python\n// ...\n\nobj(...); // same as obj.__call__(...)\n\npy::cast(obj); // cast to Python object\nobj.cast<T>; // cast to C++ type\n\npy::type::of(obj); // get type of obj\npy::type::of<T>(); // get type of T, if T is registered"]},{"i":"pyobject-code-2","c":["py::bool_ b = {true};\npy::int_ i = {1};\npy::float_ f = {1.0};\npy::str s = {\"hello\"};\npy::list l = {1, 2, 3};\npy::tuple t = {1, 2, 3};\n// ..."]},{"l":"More Examples","p":["More examples please see the test folder in the GSoC repository. All tested features are supported."]},{"l":"Limits and Comparison","p":["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."]},{"i":"function-1","l":"Function","p":["Function overloading","Return value policy","is_prepend","*args and **kwargs","Keep-alive","Call Guard","Default arguments","Keyword-Only arguments","Positional-Only arguments","Allow/Prohibiting None arguments"]},{"i":"class-1","l":"Class","p":["Creating bindings for a custom type","Binding lambda functions","Dynamic attributes","Inheritance and automatic downcasting","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."]},{"l":"Exceptions","p":["Need further discussion."]},{"l":"Smart pointers","p":["std::shared_ptr","std::unique_ptr","Custom smart pointers"]},{"l":"Type conversions","p":["Python built-in types","STL Containers","Functional","Chrono"]},{"l":"Python C++ interface","p":["bool_","buffer","bytearray","bytes","capsule","dict","float_","function","int_","iterable","iterator","list","memoryview","Need further discussion.","none","object","set","slice","str","tuple","type"]},{"l":"Miscellaneous","p":["Global Interpreter Lock (GIL)","Binding sequence data types, iterators, the slicing protocol, etc.","Convenient operators binding"]},{"l":"Differences between CPython and pocketpy","p":["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.","the return value of globals is immutable in pocketpy."]}],[{"l":"Basic Features","p":["(1, 2, 'a')","[1, 2, 'a']","[i for i in range(5)]","{'a': 1, 'b': 2}","@cache","✅","a, *b = [1, 2, 3]","a, b = 1, 2","a[1:2], a[:2], a[1:]","class A(B):","Context Block","Decorator","def f(a:int, b:float=1)","def f(x,*args,y=1):","Dict","Dynamic Code","eval()/exec()","Example","Exception","F-String","f'value is {x}'","for/while/break/continue","Function","Generator","hasattr()/getattr()/setattr()","If Else","if..else..elif","Import","import/from..import","List","ListComp","Loop","Match Case","match code: case 200:","Name","raise/try..except..","Reflection","Slice","Star Unpacking","Subclass","Supported","The following table shows the basic features of pkpy with respect to cpython.","Tuple","Type Annotation","Unpacking","with expr as id:","yield i"]},{"l":"Supported magic methods"},{"l":"Unary operators","p":["__repr__","__str__","__hash__","__len__","__iter__","__next__","__neg__"]},{"l":"Logical operators","p":["__eq__","__lt__","__le__","__gt__","__ge__","__contains__"]},{"l":"Binary operators","p":["__add__","__and__","__floordiv__","__invert__","__lshift__","__matmul__","__mod__","__mul__","__or__","__pow__","__radd__","__rmul__","__rshift__","__rsub__","__sub__","__truediv__","__xor__"]},{"l":"Indexer","p":["__getitem__","__setitem__","__delitem__"]},{"l":"Specials","p":["__new__","__init__","__call__","__divmod__","__enter__","__exit__","__name__","__all__"]}],[{"l":"Comparison with CPython","p":["cpython is the reference implementation of the Python programming language. It is written in C and is the most widely used implementation of Python."]},{"l":"The design goal","p":["pkpy aims to be an alternative to lua for game scripting, not cpython for general purpose programming.","For syntax and semantics, pkpy is designed to be as close to cpython as possible.","For ecosystem and others, pkpy is not compatible with cpython.","pkpy supports most of the syntax and semantics of python. For performance and simplicity, some features are not implemented, or behave differently. The easiest way to test a feature is to try it on your browser."]},{"l":"Unimplemented features","p":["Descriptor protocol __get__ and __set__. However, @property is implemented.","__slots__ in class definition.","else and finally clause in try..except.","Inplace methods like __iadd__ and __imul__.","__del__ in class definition.","Multiple inheritance."]},{"l":"Different behaviors","p":["positional and keyword arguments are strictly evaluated.","bool does not derive from int. They are independent types.","int is 64-bit.","Raw string cannot have boundary quotes in it, even escaped. See #55.","In a starred unpacked assignment, e.g. a, b, *c = x, the starred variable can only be presented in the last position. a, *b, c = x is not supported.","A Tab is equivalent to 4 spaces. You can mix Tab and spaces in indentation, but it is not recommended.","A return, break, continue in try/except/with block will make the finally block not executed.","match is a keyword and match..case is equivalent to if..elif..else."]}],[{"l":"Deploy Bytecodes","p":["The feature requires pocketpy version >= 2.1.7","You can deploy your pocketpy program as .pyc files, which are compiled bytecodes with necessary metadata. This slightly improves the loading speed of your program.","It also makes your users unable to get your source code directly, unless they do expensive reverse engineering.","To compile a .py file into a .pyc bytecode file, you need the command-line executable main, which can be simply built by running python cmake_build.py in the repository root."]},{"l":"Example","p":["Once you have main executable, you can run the following command to compile input_file.py:","Alternatively, you can invoke the compileall.py script in the repository root. It compiles all .py files in the specified directory into .pyc files."]},{"i":"example-code-1","c":["./main --compile input_file.py output_file.pyc"]},{"i":"example-code-2","c":["python compileall.py ./main input_path output_path"]},{"l":"Running .pyc files","p":["The command-line executable main can run .pyc files directly:","If you are using C-APIs, you can use the py_execo() function."]},{"i":"running-pyc-files-code-1","c":["./main output_file.pyc"]},{"i":"running-pyc-files-code-2","c":["/// Run a compiled code object.\nPK_API bool py_execo(const void* data, int size, const char* filename, py_Ref module) PY_RAISE PY_RETURN;"]},{"l":"Trackback Support","p":["Since .pyc files do not contain raw sources, trackbacks will show line numbers but not the actual source code lines."]}],[{"l":"Debugging"},{"l":"Install VSCode Extension","p":["To debug a pocketpy program, you need to install our VSCode extension first:","https://marketplace.visualstudio.com/items?itemName=pocketpy.pocketpy","The VSCode extension requires pocketpy version >= 2.1.1"]},{"l":"Create a launch.json file","p":["Navigate to the Debug view in VSCode, and click on \"create a launch.json file\" link. In the dropdown menu, select \"pocketpy\".","launch_json","Then a default launch.json file will be created in the .vscode folder with a sample pocketpy debug configuration."]},{"l":"How does it work?","p":["pocketpy provides a C-API py_debugger_waitforattach, which starts a debug server and waits for the VSCode extension to attach. When the debugger is attached, the program will continue to run.","If you are using pocketpy's standalone executable main.exe, you can pass --debug flag to it. This will automatically call py_debugger_waitforattach(127.0.0.1, 6110) before running your program.","If you are embedding pocketpy as a library, you need to call py_debugger_waitforattach manually in your C/C++ code."]},{"l":"Configuration","p":["type: must be pocketpy","request: can be attach or launch","name: the name of this configuration","port: the port number of the debug server, must match the one in py_debugger_waitforattach","host: the host of the debug server, must match the one in py_debugger_waitforattach","sourceFolder: the root folder of your python source code, default to ${workspaceFolder}. However, sometimes you may run your program from a subfolder, in this case you need to set sourceFolder to the correct path. If this is not set correctly, breakpoints will not be hit.","program: (for launch mode only) the path to the executable file which calls py_debugger_waitforattach, e.g. the pocketpy standalone executable main.exe.","args: (for launch mode only) the arguments to pass to the executable file, e.g. --debug and the script path if you are using main.exe.","cwd: (for launch mode only) the working directory to launch the executable file, default to ${workspaceFolder}."]},{"l":"For attach mode","p":["In this mode, you need to start your pocketpy program manually which must call py_debugger_waitforattach first. After the program starts, you can let VSCode attach to the debug server."]},{"i":"for-attach-mode-code-1","c":["{\n \"type\": \"pocketpy\",\n \"request\": \"attach\",\n \"name\": \"Attach to pocketpy program\",\n \"port\": 6110,\n \"host\": \"localhost\",\n \"sourceFolder\": \"${workspaceFolder}\"\n}"]},{"l":"For launch mode","p":["In this mode, VSCode will start your program with the specified program, args and cwd. After the program starts, VSCode attempts to attach to the debug server automatically."]},{"i":"for-launch-mode-code-1","c":["{\n \"type\": \"pocketpy\",\n \"request\": \"launch\",\n \"name\": \"Launch pocketpy program\",\n \"port\": 6110,\n \"host\": \"localhost\",\n \"sourceFolder\": \"${workspaceFolder}\",\n \"program\": \"${workspaceFolder}/pocketpy/main.exe\",\n \"args\": [\n \"--debug\"\n ],\n \"cwd\": \"${workspaceFolder}\"\n}"]},{"l":"Showcase","p":["debugger_demo"]}],[{"l":"Profiling","p":["To profile your pocketpy program, you can run main.exe with --profile flag.","For example, to profile test/test_math.py, run","This will output a JSON report file named profile_report.json in the current directory, which records the time spent for each line. To visualize the report, please install our VSCode extension.","https://marketplace.visualstudio.com/items?itemName=pocketpy.pocketpy","The VSCode extension requires pocketpy version >= 2.1.1","With pocketpy VSCode extension, press F1 and type pocketpy: Load Line Profiler Report, select 1. the profile_report.json file; 2. the source root of the program. Then you will see a nice visualization of the profiling result.","profiler_report","Press ESC to exit the report view."]},{"i":"profiling-code-1","c":["main.exe --profile test/test_math.py"]}],[{"l":"Compute Threads","p":["pocketpy organizes its state by VM structure. Users can have at maximum 16 VM instances (index from 0 to 15). Each VM instance can only be accessed by exactly one thread at a time. If you are trying to run two python scripts in parallel refering the same VM instance, you will crash it definitely.","However, there are two ways to achieve multi-threading in pocketpy.","One way is to use a native threading library such as pthread. You can wrap the multi-threading logic into a C function and bind it to pocketpy. Be careful and not to access the same VM instance from multiple threads at the same time. You need to lock critical resources or perform a deep copy of all needed data."]},{"l":"ComputeThread","p":["The other way is to use pkpy.ComputeThread. It is like an isolate in Dart language. ComputeThread is a true multi-threading model to allow you run python scripts in parallel without lock, backed by a separate VM instance.","ComputeThread is highly designed for computational intensive tasks in games. For example, you can run game logic in main thread (VM 0) and run world generation in another thread (e.g. VM 1)."]},{"l":"main.py"},{"i":"mainpy-code-1","c":["import time\nfrom pkpy import ComputeThread\n\nthread = ComputeThread(1)\nprint(\"Game Start\")\n\n# import worldgen.py\nthread.exec('from worldgen import gen_world')\n\nprint(\"Submit WorldGen Job\")\nthread.submit_call('gen_world', 3, (100, 100), 10)\n\n# wait for worldgen to finish\nfor i in range(1, 100000):\n print('Frame:', i)\n time.sleep(1)\n if thread.is_done:\n break\n\nerror = thread.last_error()\nif error is not None:\n print(\"Error:\", error)\nelse:\n retval = thread.last_retval()\n biomes = retval['biomes']\n terrain = retval['terrain']\n creatures = retval['creatures']\n print(\"World Generation Complete\", len(biomes), len(terrain), len(creatures))"]},{"l":"worldgen.py","p":["Run main.py and you will see the result like this:","ComputeThread uses pickle module to serialize the data between threads. Parameters and return values must be supported by pickle. See pickle for more details.","Since ComputeThread is backed by a separate VM instance, it does not share any state with the main thread except for the parameters you pass to it. Therefore, common python modules will be imported twice in each thread.","If you want to identify which VM instance the module is running in, you can call pkpy.currentvm or let your ComputeThread set some special flags before importing these modules."]},{"i":"worldgenpy-code-1","c":["import time\nimport random\n\ndef gen_world(biome_count: int, terrain_size: tuple[int, int], creature_count: int) -> dict:\n # simulate a long computation\n time.sleep(3)\n\n # generate world data\n all_biomes = [\"forest\", \"desert\", \"ocean\", \"mountain\", \"swamp\"]\n all_creatures = [\"wolf\", \"bear\", \"fish\", \"bird\", \"lizard\"]\n\n width, height = terrain_size\n\n terrain_data = [\n random.randint(1, 10)\n for _ in range(width * height)\n ]\n\n creatures = [\n {\n \"name\": random.choice(all_creatures),\n \"x\": random.randint(0, width - 1),\n \"y\": random.randint(0, height - 1),\n }\n for i in range(creature_count)\n ]\n\n return {\n \"biomes\": all_biomes[:biome_count],\n \"terrain\": terrain_data,\n \"creatures\": creatures,\n }"]},{"i":"worldgenpy-code-2","c":["Game Start\nSubmit WorldGen Job\nFrame: 1\nFrame: 2\nFrame: 3\nFrame: 4\nWorld Generation Complete 3 10000 10"]}],[{"l":"Undefined Behaviour","p":["These are the undefined behaviours of pkpy. The behaviour of pkpy is undefined if you do the following things.","Delete a builtin object. For example, del int.__add__.","Call an unbound method with the wrong type of self. For example, int.__add__('1', 2).","Type T's __new__ returns an object that is not an instance of T.","Call __new__ with a type that is not a subclass of type."]}],[{"l":"Introduction","p":["All public functions in the C API are prefixed with py_ in pocketpy.h."]},{"l":"Overview","p":["pocketpy works with opaque references. py_Ref is used to reference objects in the virtual machine. It is your responsibility to ensure a reference is valid before using it. See following reference types:","You can store python objects into \"stack\" or \"register\". We provide 8 registers and you can get references to them by py_reg(). Also, py_retval() is a special register that is used to store the return value of a py_CFunction. Registers are shared so they could be overwritten easily. If you want to store python objects across function calls, you should store them into the stack via py_push() and py_pop()."]},{"i":"overview-code-1","c":["/// A generic reference to a python object.\ntypedef py_TValue* py_Ref;\n/// A reference which has the same lifespan as the python object.\ntypedef py_TValue* py_ObjectRef;\n/// A global reference which has the same lifespan as the VM.\ntypedef py_TValue* py_GlobalRef;\n/// A specific location in the value stack of the VM.\ntypedef py_TValue* py_StackRef;\n/// An item reference to a container object. It invalidates when the container is modified.\ntypedef py_TValue* py_ItemRef;\n/// An output reference for returning a value.\ntypedef py_TValue* py_OutRef;"]},{"l":"Data Types","p":["(void*)py_toint()","bool","C to Python","C type","char,short,int,long","const char*","float","float,double","int","py_newbool()","py_newfloat()","py_newint()","py_newstr()","py_tobool()","py_tofloat(), py_castfloat()","py_toint()","py_tostr()","Python to C","Python type","str","void*,intptr_t","You can do conversions between C types and python objects using the following functions:"]},{"l":"PY_RAISE macro","p":["Mark a function that can raise an exception on failure.","If the function returns bool, then false means an exception is raised.","If the function returns int, then -1 means an exception is raised."]},{"l":"PY_RETURN macro","p":["Mark a function that can store a value in py_retval() on success."]},{"l":"PY_MAYBENULL macro","p":["Mark a variable or callback function that may be NULL."]}],[{"l":"Functions"},{"l":"py_initialize"},{"i":"py_initialize-code-1","c":["/// Initialize pocketpy and the default VM.\nPK_API void py_initialize();"]},{"l":"py_finalize"},{"i":"py_finalize-code-1","c":["/// Finalize pocketpy and free all VMs. This opearation is irreversible.\n/// After this call, you cannot use any function from this header anymore.\nPK_API void py_finalize();"]},{"l":"py_currentvm"},{"i":"py_currentvm-code-1","c":["/// Get the current VM index.\nPK_API int py_currentvm();"]},{"l":"py_switchvm"},{"i":"py_switchvm-code-1","c":["/// Switch to a VM.\n/// @param index index of the VM ranging from 0 to 16 (exclusive). `0` is the default VM.\nPK_API void py_switchvm(int index);"]},{"l":"py_resetvm"},{"i":"py_resetvm-code-1","c":["/// Reset the current VM.\nPK_API void py_resetvm();"]},{"l":"py_resetallvm"},{"i":"py_resetallvm-code-1","c":["/// Reset All VMs.\nPK_API void py_resetallvm();"]},{"l":"py_getvmctx"},{"i":"py_getvmctx-code-1","c":["/// Get the current VM context. This is used for user-defined data.\nPK_API void* py_getvmctx();"]},{"l":"py_setvmctx"},{"i":"py_setvmctx-code-1","c":["/// Set the current VM context. This is used for user-defined data.\nPK_API void py_setvmctx(void* ctx);"]},{"l":"py_callbacks"},{"i":"py_callbacks-code-1","c":["/// Setup the callbacks for the current VM.\nPK_API py_Callbacks* py_callbacks();"]},{"l":"py_appcallbacks"},{"i":"py_appcallbacks-code-1","c":["/// Setup the application callbacks\nPK_API py_AppCallbacks* py_appcallbacks();"]},{"l":"py_sys_setargv"},{"i":"py_sys_setargv-code-1","c":["/// Set `sys.argv`. Used for storing command-line arguments.\nPK_API void py_sys_setargv(int argc, char** argv);"]},{"l":"py_sys_settrace"},{"i":"py_sys_settrace-code-1","c":["/// Set the trace function for the current VM.\nPK_API void py_sys_settrace(py_TraceFunc func, bool reset);"]},{"l":"py_gc_collect"},{"i":"py_gc_collect-code-1","c":["/// Invoke the garbage collector.\nPK_API int py_gc_collect();"]},{"l":"py_malloc"},{"i":"py_malloc-code-1","c":["/// Wrapper for `PK_MALLOC(size)`.\nPK_API void* py_malloc(size_t size);"]},{"l":"py_realloc"},{"i":"py_realloc-code-1","c":["/// Wrapper for `PK_REALLOC(ptr, size)`.\nPK_API void* py_realloc(void* ptr, size_t size);"]},{"l":"py_free"},{"i":"py_free-code-1","c":["/// Wrapper for `PK_FREE(ptr)`.\nPK_API void py_free(void* ptr);"]},{"l":"py_True"},{"i":"py_true-code-1","c":["/// A shorthand for `True`.\nPK_API py_GlobalRef py_True();"]},{"l":"py_False"},{"i":"py_false-code-1","c":["/// A shorthand for `False`.\nPK_API py_GlobalRef py_False();"]},{"l":"py_None"},{"i":"py_none-code-1","c":["/// A shorthand for `None`.\nPK_API py_GlobalRef py_None();"]},{"l":"py_NIL"},{"i":"py_nil-code-1","c":["/// A shorthand for `nil`. `nil` is not a valid python object.\nPK_API py_GlobalRef py_NIL();"]},{"l":"py_Frame_newglobals"},{"i":"py_frame_newglobals-code-1","c":["/// Python equivalent to `globals()` with respect to the given frame.\nPK_API void py_Frame_newglobals(py_Frame* frame, py_OutRef out);"]},{"l":"py_Frame_newlocals"},{"i":"py_frame_newlocals-code-1","c":["/// Python equivalent to `locals()` with respect to the given frame.\nPK_API void py_Frame_newlocals(py_Frame* frame, py_OutRef out);"]},{"l":"py_Frame_function"},{"i":"py_frame_function-code-1","c":["/// Get the function object of the frame.\n/// Returns `NULL` if not available.\nPK_API py_StackRef py_Frame_function(py_Frame* frame);"]},{"l":"py_compile"},{"i":"py_compile-code-1","c":["/// Compile a source string into a code object.\n/// Use python's `exec()` or `eval()` to execute it.\nPK_API bool py_compile(const char* source,\n const char* filename,\n enum py_CompileMode mode,\n bool is_dynamic);"]},{"l":"py_compilefile"},{"i":"py_compilefile-code-1","c":["/// Compile a `.py` file into a `.pyc` file.\nPK_API bool py_compilefile(const char* src_path,\n const char* dst_path);"]},{"l":"py_execo"},{"i":"py_execo-code-1","c":["/// Run a compiled code object.\nPK_API bool py_execo(const void* data, int size, const char* filename, py_Ref module);"]},{"l":"py_exec"},{"i":"py_exec-code-1","c":["/// Run a source string.\n/// @param source source string.\n/// @param filename filename (for error messages).\n/// @param mode compile mode. Use `EXEC_MODE` for statements `EVAL_MODE` for expressions.\n/// @param module target module. Use NULL for the main module.\n/// @return `true` if the execution is successful or `false` if an exception is raised.\nPK_API bool py_exec(const char* source,\n const char* filename,\n enum py_CompileMode mode,\n py_Ref module);"]},{"l":"py_eval"},{"i":"py_eval-code-1","c":["/// Evaluate a source string. Equivalent to `py_exec(source, \"<string>\", EVAL_MODE, module)`.\nPK_API bool py_eval(const char* source, py_Ref module);"]},{"l":"py_smartexec"},{"i":"py_smartexec-code-1","c":["/// Run a source string with smart interpretation.\n/// Example:\n/// `py_newstr(py_r0(), \"abc\");`\n/// `py_newint(py_r1(), 123);`\n/// `py_smartexec(\"print(_0, _1)\", NULL, py_r0(), py_r1());`\n/// `// \"abc 123\" will be printed`.\nPK_API bool py_smartexec(const char* source, py_Ref module, ...);"]},{"l":"py_smarteval"},{"i":"py_smarteval-code-1","c":["/// Evaluate a source string with smart interpretation.\n/// Example:\n/// `py_newstr(py_r0(), \"abc\");`\n/// `py_smarteval(\"len(_)\", NULL, py_r0());`\n/// `int res = py_toint(py_retval());`\n/// `// res will be 3`.\nPK_API bool py_smarteval(const char* source, py_Ref module, ...);"]},{"l":"py_newint"},{"i":"py_newint-code-1","c":["/// Create an `int` object.\nPK_API void py_newint(py_OutRef, py_i64);"]},{"l":"py_newtrivial"},{"i":"py_newtrivial-code-1","c":["/// Create a trivial value object.\nPK_API void py_newtrivial(py_OutRef out, py_Type type, void* data, int size);"]},{"l":"py_newfloat"},{"i":"py_newfloat-code-1","c":["/// Create a `float` object.\nPK_API void py_newfloat(py_OutRef, py_f64);"]},{"l":"py_newbool"},{"i":"py_newbool-code-1","c":["/// Create a `bool` object.\nPK_API void py_newbool(py_OutRef, bool);"]},{"l":"py_newstr"},{"i":"py_newstr-code-1","c":["/// Create a `str` object from a null-terminated string (utf-8).\nPK_API void py_newstr(py_OutRef, const char*);"]},{"l":"py_newstrn"},{"i":"py_newstrn-code-1","c":["/// Create a `str` object with `n` UNINITIALIZED bytes plus `'\\0'`.\nPK_API char* py_newstrn(py_OutRef, int);"]},{"l":"py_newstrv"},{"i":"py_newstrv-code-1","c":["/// Create a `str` object from a `c11_sv`.\nPK_API void py_newstrv(py_OutRef, c11_sv);"]},{"l":"py_newfstr"},{"i":"py_newfstr-code-1","c":["/// Create a formatted `str` object.\nPK_API void py_newfstr(py_OutRef, const char*, ...);"]},{"l":"py_newnone"},{"i":"py_newnone-code-1","c":["/// Create a `None` object.\nPK_API void py_newnone(py_OutRef);"]},{"l":"py_newnotimplemented"},{"i":"py_newnotimplemented-code-1","c":["/// Create a `NotImplemented` object.\nPK_API void py_newnotimplemented(py_OutRef);"]},{"l":"py_newellipsis"},{"i":"py_newellipsis-code-1","c":["/// Create a `...` object.\nPK_API void py_newellipsis(py_OutRef);"]},{"l":"py_newnil"},{"i":"py_newnil-code-1","c":["/// Create a `nil` object. `nil` is an invalid representation of an object.\n/// Don't use it unless you know what you are doing.\nPK_API void py_newnil(py_OutRef);"]},{"l":"py_newnativefunc"},{"i":"py_newnativefunc-code-1","c":["/// Create a `nativefunc` object.\nPK_API void py_newnativefunc(py_OutRef, py_CFunction);"]},{"l":"py_newfunction"},{"i":"py_newfunction-code-1","c":["/// Create a `function` object.\nPK_API py_Name py_newfunction(py_OutRef out,\n const char* sig,\n py_CFunction f,\n const char* docstring,\n int slots);"]},{"l":"py_newboundmethod"},{"i":"py_newboundmethod-code-1","c":["/// Create a `boundmethod` object.\nPK_API void py_newboundmethod(py_OutRef out, py_Ref self, py_Ref func);"]},{"l":"py_newobject"},{"i":"py_newobject-code-1","c":["/// Create a new object.\n/// @param out output reference.\n/// @param type type of the object.\n/// @param slots number of slots. Use `-1` to create a `__dict__`.\n/// @param udsize size of your userdata.\n/// @return pointer to the userdata.\nPK_API void* py_newobject(py_OutRef out, py_Type type, int slots, int udsize);"]},{"l":"py_name"},{"i":"py_name-code-1","c":["/// Convert a null-terminated string to a name.\nPK_API py_Name py_name(const char*);"]},{"l":"py_name2ref"},{"i":"py_name2ref-code-1","c":["/// Convert a name to a python `str` object with cache.\nPK_API py_GlobalRef py_name2ref(py_Name);"]},{"l":"py_namev"},{"i":"py_namev-code-1","c":["/// Convert a `c11_sv` to a name.\nPK_API py_Name py_namev(c11_sv);"]},{"l":"py_name2sv"},{"i":"py_name2sv-code-1","c":["/// Convert a name to a `c11_sv`.\nPK_API c11_sv py_name2sv(py_Name);"]},{"l":"py_bind"},{"i":"py_bind-code-1","c":["/// Bind a function to the object via \"decl-based\" style.\n/// @param obj the target object.\n/// @param sig signature of the function. e.g. `add(x, y)`.\n/// @param f function to bind.\nPK_API void py_bind(py_Ref obj, const char* sig, py_CFunction f);"]},{"l":"py_bindmethod"},{"i":"py_bindmethod-code-1","c":["/// Bind a method to type via \"argc-based\" style.\n/// @param type the target type.\n/// @param name name of the method.\n/// @param f function to bind.\nPK_API void py_bindmethod(py_Type type, const char* name, py_CFunction f);"]},{"l":"py_bindstaticmethod"},{"i":"py_bindstaticmethod-code-1","c":["/// Bind a static method to type via \"argc-based\" style.\n/// @param type the target type.\n/// @param name name of the method.\n/// @param f function to bind.\nPK_API void py_bindstaticmethod(py_Type type, const char* name, py_CFunction f);"]},{"l":"py_bindfunc"},{"i":"py_bindfunc-code-1","c":["/// Bind a function to the object via \"argc-based\" style.\n/// @param obj the target object.\n/// @param name name of the function.\n/// @param f function to bind.\nPK_API void py_bindfunc(py_Ref obj, const char* name, py_CFunction f);"]},{"l":"py_bindproperty"},{"i":"py_bindproperty-code-1","c":["/// Bind a property to type.\n/// @param type the target type.\n/// @param name name of the property.\n/// @param getter getter function.\n/// @param setter setter function. Use `NULL` if not needed.\nPK_API void py_bindproperty(py_Type type, const char* name, py_CFunction getter, py_CFunction setter);"]},{"l":"py_bindmagic"},{"i":"py_bindmagic-code-1","c":["/// Bind a magic method to type.\nPK_API void py_bindmagic(py_Type type, py_Name name, py_CFunction f);"]},{"l":"py_toint"},{"i":"py_toint-code-1","c":["/// Convert an `int` object in python to `int64_t`.\nPK_API py_i64 py_toint(py_Ref);"]},{"l":"py_totrivial"},{"i":"py_totrivial-code-1","c":["/// Get the address of the trivial value object (16 bytes).\nPK_API void* py_totrivial(py_Ref);"]},{"l":"py_tofloat"},{"i":"py_tofloat-code-1","c":["/// Convert a `float` object in python to `double`.\nPK_API py_f64 py_tofloat(py_Ref);"]},{"l":"py_castfloat"},{"i":"py_castfloat-code-1","c":["/// Cast a `int` or `float` object in python to `double`.\n/// If successful, return true and set the value to `out`.\n/// Otherwise, return false and raise `TypeError`.\nPK_API bool py_castfloat(py_Ref, py_f64* out);"]},{"l":"py_castfloat32"},{"i":"py_castfloat32-code-1","c":["/// 32-bit version of `py_castfloat`.\nPK_API bool py_castfloat32(py_Ref, float* out);"]},{"l":"py_castint"},{"i":"py_castint-code-1","c":["/// Cast a `int` object in python to `int64_t`.\nPK_API bool py_castint(py_Ref, py_i64* out);"]},{"l":"py_tobool"},{"i":"py_tobool-code-1","c":["/// Convert a `bool` object in python to `bool`.\nPK_API bool py_tobool(py_Ref);"]},{"l":"py_totype"},{"i":"py_totype-code-1","c":["/// Convert a `type` object in python to `py_Type`.\nPK_API py_Type py_totype(py_Ref);"]},{"l":"py_touserdata"},{"i":"py_touserdata-code-1","c":["/// Convert a user-defined object to its userdata.\nPK_API void* py_touserdata(py_Ref);"]},{"l":"py_tosv"},{"i":"py_tosv-code-1","c":["/// Convert a `str` object in python to `c11_sv`.\nPK_API c11_sv py_tosv(py_Ref);"]},{"l":"py_bytes_resize"},{"i":"py_bytes_resize-code-1","c":["/// Resize a `bytes` object. It can only be resized down.\nPK_API void py_bytes_resize(py_Ref, int size);"]},{"l":"py_newtype"},{"i":"py_newtype-code-1","c":["/// Create a new type.\n/// @param name name of the type.\n/// @param base base type.\n/// @param module module where the type is defined. Use `NULL` for built-in types.\n/// @param dtor destructor function. Use `NULL` if not needed.\nPK_API py_Type py_newtype(const char* name, py_Type base, const py_GlobalRef module, py_Dtor dtor);"]},{"l":"py_istype"},{"i":"py_istype-code-1","c":["/// Check if the object is exactly the given type.\nPK_API bool py_istype(py_Ref, py_Type);"]},{"l":"py_typeof"},{"i":"py_typeof-code-1","c":["/// Get the type of the object.\nPK_API py_Type py_typeof(py_Ref self);"]},{"l":"py_isinstance"},{"i":"py_isinstance-code-1","c":["/// Check if the object is an instance of the given type.\nPK_API bool py_isinstance(py_Ref obj, py_Type type);"]},{"l":"py_issubclass"},{"i":"py_issubclass-code-1","c":["/// Check if the derived type is a subclass of the base type.\nPK_API bool py_issubclass(py_Type derived, py_Type base);"]},{"l":"py_gettype"},{"i":"py_gettype-code-1","c":["/// Get type by module and name. e.g. `py_gettype(\"time\", py_name(\"struct_time\"))`.\n/// Return `0` if not found.\nPK_API py_Type py_gettype(const char* module, py_Name name);"]},{"l":"py_checktype"},{"i":"py_checktype-code-1","c":["/// Check if the object is an instance of the given type exactly.\n/// Raise `TypeError` if the check fails.\nPK_API bool py_checktype(py_Ref self, py_Type type);"]},{"l":"py_checkinstance"},{"i":"py_checkinstance-code-1","c":["/// Check if the object is an instance of the given type or its subclass.\n/// Raise `TypeError` if the check fails.\nPK_API bool py_checkinstance(py_Ref self, py_Type type);"]},{"l":"py_tpfindmagic"},{"i":"py_tpfindmagic-code-1","c":["/// Search the magic method from the given type to the base type.\n/// Return `NULL` if not found.\nPK_API py_GlobalRef py_tpfindmagic(py_Type, py_Name name);"]},{"l":"py_tpfindname"},{"i":"py_tpfindname-code-1","c":["/// Search the name from the given type to the base type.\n/// Return `NULL` if not found.\nPK_API py_ItemRef py_tpfindname(py_Type, py_Name name);"]},{"l":"py_tpbase"},{"i":"py_tpbase-code-1","c":["/// Get the base type of the given type.\nPK_API py_Type py_tpbase(py_Type type);"]},{"l":"py_tpobject"},{"i":"py_tpobject-code-1","c":["/// Get the type object of the given type.\nPK_API py_GlobalRef py_tpobject(py_Type type);"]},{"l":"py_tpsetfinal"},{"i":"py_tpsetfinal-code-1","c":["/// Disable the type for subclassing.\nPK_API void py_tpsetfinal(py_Type type);"]},{"l":"py_tphookattributes"},{"i":"py_tphookattributes-code-1","c":["/// Set attribute hooks for the given type.\nPK_API void py_tphookattributes(py_Type type,\n bool (*getattribute)(py_Ref self, py_Name name) PY_RAISE PY_RETURN,\n bool (*setattribute)(py_Ref self, py_Name name, py_Ref val)\n PY_RAISE PY_RETURN,\n bool (*delattribute)(py_Ref self, py_Name name) PY_RAISE,\n bool (*getunboundmethod)(py_Ref self, py_Name name) PY_RETURN);"]},{"l":"py_inspect_currentfunction"},{"i":"py_inspect_currentfunction-code-1","c":["/// Get the current `function` object on the stack.\n/// Return `NULL` if not available.\n/// NOTE: This function should be placed at the beginning of your decl-based bindings.\nPK_API py_StackRef py_inspect_currentfunction();"]},{"l":"py_inspect_currentmodule"},{"i":"py_inspect_currentmodule-code-1","c":["/// Get the current `module` object where the code is executed.\n/// Return `NULL` if not available.\nPK_API py_GlobalRef py_inspect_currentmodule();"]},{"l":"py_inspect_currentframe"},{"i":"py_inspect_currentframe-code-1","c":["/// Get the current frame object.\n/// Return `NULL` if not available.\nPK_API py_Frame* py_inspect_currentframe();"]},{"l":"py_newglobals"},{"i":"py_newglobals-code-1","c":["/// Python equivalent to `globals()`.\nPK_API void py_newglobals(py_OutRef);"]},{"l":"py_newlocals"},{"i":"py_newlocals-code-1","c":["/// Python equivalent to `locals()`.\nPK_API void py_newlocals(py_OutRef);"]},{"l":"py_getreg"},{"i":"py_getreg-code-1","c":["/// Get the i-th register.\n/// All registers are located in a contiguous memory.\nPK_API py_GlobalRef py_getreg(int i);"]},{"l":"py_setreg"},{"i":"py_setreg-code-1","c":["/// Set the i-th register.\nPK_API void py_setreg(int i, py_Ref val);"]},{"l":"py_retval"},{"i":"py_retval-code-1","c":["/// Get the last return value.\n/// Please note that `py_retval()` cannot be used as input argument.\nPK_API py_GlobalRef py_retval();"]},{"l":"py_getdict"},{"i":"py_getdict-code-1","c":["/// Get an item from the object's `__dict__`.\n/// Return `NULL` if not found.\nPK_API py_ItemRef py_getdict(py_Ref self, py_Name name);"]},{"l":"py_setdict"},{"i":"py_setdict-code-1","c":["/// Set an item to the object's `__dict__`.\nPK_API void py_setdict(py_Ref self, py_Name name, py_Ref val);"]},{"l":"py_deldict"},{"i":"py_deldict-code-1","c":["/// Delete an item from the object's `__dict__`.\n/// Return `true` if the deletion is successful.\nPK_API bool py_deldict(py_Ref self, py_Name name);"]},{"l":"py_emplacedict"},{"i":"py_emplacedict-code-1","c":["/// Prepare an insertion to the object's `__dict__`.\nPK_API py_ItemRef py_emplacedict(py_Ref self, py_Name name);"]},{"l":"py_applydict"},{"i":"py_applydict-code-1","c":["/// Apply a function to all items in the object's `__dict__`.\n/// Return `true` if the function is successful for all items.\n/// NOTE: Be careful if `f` modifies the object's `__dict__`.\nPK_API bool py_applydict(py_Ref self, bool (*f)(py_Name name, py_Ref val, void* ctx), void* ctx);"]},{"l":"py_cleardict"},{"i":"py_cleardict-code-1","c":["/// Clear the object's `__dict__`. This function is dangerous.\nPK_API void py_cleardict(py_Ref self);"]},{"l":"py_getslot"},{"i":"py_getslot-code-1","c":["/// Get the i-th slot of the object.\n/// The object must have slots and `i` must be in valid range.\nPK_API py_ObjectRef py_getslot(py_Ref self, int i);"]},{"l":"py_setslot"},{"i":"py_setslot-code-1","c":["/// Set the i-th slot of the object.\nPK_API void py_setslot(py_Ref self, int i, py_Ref val);"]},{"l":"py_getbuiltin"},{"i":"py_getbuiltin-code-1","c":["/// Get variable in the `builtins` module.\nPK_API py_ItemRef py_getbuiltin(py_Name name);"]},{"l":"py_getglobal"},{"i":"py_getglobal-code-1","c":["/// Get variable in the `__main__` module.\nPK_API py_ItemRef py_getglobal(py_Name name);"]},{"l":"py_setglobal"},{"i":"py_setglobal-code-1","c":["/// Set variable in the `__main__` module.\nPK_API void py_setglobal(py_Name name, py_Ref val);"]},{"l":"py_peek"},{"i":"py_peek-code-1","c":["/// Get the i-th object from the top of the stack.\n/// `i` should be negative, e.g. (-1) means TOS.\nPK_API py_StackRef py_peek(int i);"]},{"l":"py_push"},{"i":"py_push-code-1","c":["/// Push the object to the stack.\nPK_API void py_push(py_Ref src);"]},{"l":"py_pushnil"},{"i":"py_pushnil-code-1","c":["/// Push a `nil` object to the stack.\nPK_API void py_pushnil();"]},{"l":"py_pushnone"},{"i":"py_pushnone-code-1","c":["/// Push a `None` object to the stack.\nPK_API void py_pushnone();"]},{"l":"py_pushname"},{"i":"py_pushname-code-1","c":["/// Push a `py_Name` to the stack. This is used for keyword arguments.\nPK_API void py_pushname(py_Name name);"]},{"l":"py_pop"},{"i":"py_pop-code-1","c":["/// Pop an object from the stack.\nPK_API void py_pop();"]},{"l":"py_shrink"},{"i":"py_shrink-code-1","c":["/// Shrink the stack by n.\nPK_API void py_shrink(int n);"]},{"l":"py_pushtmp"},{"i":"py_pushtmp-code-1","c":["/// Get a temporary variable from the stack.\nPK_API py_StackRef py_pushtmp();"]},{"l":"py_pushmethod"},{"i":"py_pushmethod-code-1","c":["/// Get the unbound method of the object.\n/// Assume the object is located at the top of the stack.\n/// If return true: `[self] -> [unbound, self]`.\n/// If return false: `[self] -> [self]` (no change).\nPK_API bool py_pushmethod(py_Name name);"]},{"l":"py_pusheval"},{"i":"py_pusheval-code-1","c":["/// Evaluate an expression and push the result to the stack.\n/// This function is used for testing.\nPK_API bool py_pusheval(const char* expr, py_GlobalRef module);"]},{"l":"py_vectorcall"},{"i":"py_vectorcall-code-1","c":["/// Call a callable object via pocketpy's calling convention.\n/// You need to prepare the stack using the following format:\n/// `callable, self/nil, arg1, arg2, ..., k1, v1, k2, v2, ...`.\n/// `argc` is the number of positional arguments excluding `self`.\n/// `kwargc` is the number of keyword arguments.\n/// The result will be set to `py_retval()`.\n/// The stack size will be reduced by `2 + argc + kwargc * 2`.\nPK_API bool py_vectorcall(uint16_t argc, uint16_t kwargc);"]},{"l":"py_call"},{"i":"py_call-code-1","c":["/// Call a function.\n/// It prepares the stack and then performs a `vectorcall(argc, 0, false)`.\n/// The result will be set to `py_retval()`.\n/// The stack remains unchanged if successful.\nPK_API bool py_call(py_Ref f, int argc, py_Ref argv);"]},{"l":"py_tpcall"},{"i":"py_tpcall-code-1","c":["/// Call a type to create a new instance.\nPK_API bool py_tpcall(py_Type type, int argc, py_Ref argv);"]},{"l":"py_callcfunc"},{"i":"py_callcfunc-code-1","c":["/// Call a `py_CFunction` in a safe way.\n/// This function does extra checks to help you debug `py_CFunction`.\nPK_API bool py_callcfunc(py_CFunction f, int argc, py_Ref argv);"]},{"l":"py_binaryop"},{"i":"py_binaryop-code-1","c":["/// Perform a binary operation.\n/// The result will be set to `py_retval()`.\n/// The stack remains unchanged after the operation.\nPK_API bool py_binaryop(py_Ref lhs, py_Ref rhs, py_Name op, py_Name rop);"]},{"l":"py_binaryadd"},{"i":"py_binaryadd-code-1","c":["/// lhs + rhs\nPK_API bool py_binaryadd(py_Ref lhs, py_Ref rhs);"]},{"l":"py_binarysub"},{"i":"py_binarysub-code-1","c":["/// lhs - rhs\nPK_API bool py_binarysub(py_Ref lhs, py_Ref rhs);"]},{"l":"py_binarymul"},{"i":"py_binarymul-code-1","c":["/// lhs * rhs\nPK_API bool py_binarymul(py_Ref lhs, py_Ref rhs);"]},{"l":"py_binarytruediv"},{"i":"py_binarytruediv-code-1","c":["/// lhs / rhs\nPK_API bool py_binarytruediv(py_Ref lhs, py_Ref rhs);"]},{"l":"py_binaryfloordiv"},{"i":"py_binaryfloordiv-code-1","c":["/// lhs // rhs\nPK_API bool py_binaryfloordiv(py_Ref lhs, py_Ref rhs);"]},{"l":"py_binarymod"},{"i":"py_binarymod-code-1","c":["/// lhs % rhs\nPK_API bool py_binarymod(py_Ref lhs, py_Ref rhs);"]},{"l":"py_binarypow"},{"i":"py_binarypow-code-1","c":["/// lhs ** rhs\nPK_API bool py_binarypow(py_Ref lhs, py_Ref rhs);"]},{"l":"py_binarylshift"},{"i":"py_binarylshift-code-1","c":["/// lhs << rhs\nPK_API bool py_binarylshift(py_Ref lhs, py_Ref rhs);"]},{"l":"py_binaryrshift"},{"i":"py_binaryrshift-code-1","c":["/// lhs >> rhs\nPK_API bool py_binaryrshift(py_Ref lhs, py_Ref rhs);"]},{"l":"py_binaryand"},{"i":"py_binaryand-code-1","c":["/// lhs & rhs\nPK_API bool py_binaryand(py_Ref lhs, py_Ref rhs);"]},{"l":"py_binaryor"},{"i":"py_binaryor-code-1","c":["/// lhs | rhs\nPK_API bool py_binaryor(py_Ref lhs, py_Ref rhs);"]},{"l":"py_binaryxor"},{"i":"py_binaryxor-code-1","c":["/// lhs ^ rhs\nPK_API bool py_binaryxor(py_Ref lhs, py_Ref rhs);"]},{"l":"py_binarymatmul"},{"i":"py_binarymatmul-code-1","c":["/// lhs @ rhs\nPK_API bool py_binarymatmul(py_Ref lhs, py_Ref rhs);"]},{"l":"py_eq"},{"i":"py_eq-code-1","c":["/// lhs == rhs\nPK_API bool py_eq(py_Ref lhs, py_Ref rhs);"]},{"l":"py_ne"},{"i":"py_ne-code-1","c":["/// lhs != rhs\nPK_API bool py_ne(py_Ref lhs, py_Ref rhs);"]},{"l":"py_lt"},{"i":"py_lt-code-1","c":["/// lhs < rhs\nPK_API bool py_lt(py_Ref lhs, py_Ref rhs);"]},{"l":"py_le"},{"i":"py_le-code-1","c":["/// lhs <= rhs\nPK_API bool py_le(py_Ref lhs, py_Ref rhs);"]},{"l":"py_gt"},{"i":"py_gt-code-1","c":["/// lhs > rhs\nPK_API bool py_gt(py_Ref lhs, py_Ref rhs);"]},{"l":"py_ge"},{"i":"py_ge-code-1","c":["/// lhs >= rhs\nPK_API bool py_ge(py_Ref lhs, py_Ref rhs);"]},{"l":"py_isidentical"},{"i":"py_isidentical-code-1","c":["/// Python equivalent to `lhs is rhs`.\nPK_API bool py_isidentical(py_Ref, py_Ref);"]},{"l":"py_bool"},{"i":"py_bool-code-1","c":["/// Python equivalent to `bool(val)`.\n/// 1: true, 0: false, -1: error\nPK_API int py_bool(py_Ref val);"]},{"l":"py_equal"},{"i":"py_equal-code-1","c":["/// Compare two objects.\n/// 1: lhs == rhs, 0: lhs != rhs, -1: error\nPK_API int py_equal(py_Ref lhs, py_Ref rhs);"]},{"l":"py_less"},{"i":"py_less-code-1","c":["/// Compare two objects.\n/// 1: lhs < rhs, 0: lhs >= rhs, -1: error\nPK_API int py_less(py_Ref lhs, py_Ref rhs);"]},{"l":"py_callable"},{"i":"py_callable-code-1","c":["/// Python equivalent to `callable(val)`.\nPK_API bool py_callable(py_Ref val);"]},{"l":"py_hash"},{"i":"py_hash-code-1","c":["/// Get the hash value of the object.\nPK_API bool py_hash(py_Ref, py_i64* out);"]},{"l":"py_iter"},{"i":"py_iter-code-1","c":["/// Get the iterator of the object.\nPK_API bool py_iter(py_Ref);"]},{"l":"py_next"},{"i":"py_next-code-1","c":["/// Get the next element from the iterator.\n/// 1: success, 0: StopIteration, -1: error\nPK_API int py_next(py_Ref);"]},{"l":"py_str"},{"i":"py_str-code-1","c":["/// Python equivalent to `str(val)`.\nPK_API bool py_str(py_Ref val);"]},{"l":"py_repr"},{"i":"py_repr-code-1","c":["/// Python equivalent to `repr(val)`.\nPK_API bool py_repr(py_Ref val);"]},{"l":"py_len"},{"i":"py_len-code-1","c":["/// Python equivalent to `len(val)`.\nPK_API bool py_len(py_Ref val);"]},{"l":"py_getattr"},{"i":"py_getattr-code-1","c":["/// Python equivalent to `getattr(self, name)`.\nPK_API bool py_getattr(py_Ref self, py_Name name);"]},{"l":"py_setattr"},{"i":"py_setattr-code-1","c":["/// Python equivalent to `setattr(self, name, val)`.\nPK_API bool py_setattr(py_Ref self, py_Name name, py_Ref val);"]},{"l":"py_delattr"},{"i":"py_delattr-code-1","c":["/// Python equivalent to `delattr(self, name)`.\nPK_API bool py_delattr(py_Ref self, py_Name name);"]},{"l":"py_getitem"},{"i":"py_getitem-code-1","c":["/// Python equivalent to `self[key]`.\nPK_API bool py_getitem(py_Ref self, py_Ref key);"]},{"l":"py_setitem"},{"i":"py_setitem-code-1","c":["/// Python equivalent to `self[key] = val`.\nPK_API bool py_setitem(py_Ref self, py_Ref key, py_Ref val);"]},{"l":"py_delitem"},{"i":"py_delitem-code-1","c":["/// Python equivalent to `del self[key]`.\nPK_API bool py_delitem(py_Ref self, py_Ref key);"]},{"l":"py_getmodule"},{"i":"py_getmodule-code-1","c":["/// Get a module by path.\nPK_API py_GlobalRef py_getmodule(const char* path);"]},{"l":"py_newmodule"},{"i":"py_newmodule-code-1","c":["/// Create a new module.\nPK_API py_GlobalRef py_newmodule(const char* path);"]},{"l":"py_importlib_reload"},{"i":"py_importlib_reload-code-1","c":["/// Reload an existing module.\nPK_API bool py_importlib_reload(py_Ref module);"]},{"l":"py_import"},{"i":"py_import-code-1","c":["/// Import a module.\n/// The result will be set to `py_retval()`.\n/// -1: error, 0: not found, 1: success\nPK_API int py_import(const char* path);"]},{"l":"py_checkexc"},{"i":"py_checkexc-code-1","c":["/// Check if there is an unhandled exception.\nPK_API bool py_checkexc();"]},{"l":"py_matchexc"},{"i":"py_matchexc-code-1","c":["/// Check if the unhandled exception is an instance of the given type.\n/// If match, the exception will be stored in `py_retval()`.\nPK_API bool py_matchexc(py_Type type);"]},{"l":"py_clearexc"},{"i":"py_clearexc-code-1","c":["/// Clear the unhandled exception.\n/// @param p0 the unwinding point. Use `NULL` if not needed.\nPK_API void py_clearexc(py_StackRef p0);"]},{"l":"py_printexc"},{"i":"py_printexc-code-1","c":["/// Print the unhandled exception.\nPK_API void py_printexc();"]},{"l":"py_formatexc"},{"i":"py_formatexc-code-1","c":["/// Format the unhandled exception and return a null-terminated string.\n/// The returned string should be freed by the caller.\nPK_API char* py_formatexc();"]},{"l":"py_exception"},{"i":"py_exception-code-1","c":["/// Raise an exception by type and message. Always return false.\nPK_API bool py_exception(py_Type type, const char* fmt, ...);"]},{"l":"py_raise"},{"i":"py_raise-code-1","c":["/// Raise an exception object. Always return false.\nPK_API bool py_raise(py_Ref);"]},{"l":"KeyError"},{"i":"keyerror-code-1","c":["PK_API bool KeyError(py_Ref key);"]},{"l":"StopIteration"},{"i":"stopiteration-code-1","c":["PK_API bool StopIteration();"]},{"l":"py_debugger_waitforattach"},{"i":"py_debugger_waitforattach-code-1","c":["PK_API void py_debugger_waitforattach(const char* hostname, unsigned short port);"]},{"l":"py_debugger_status"},{"i":"py_debugger_status-code-1","c":["PK_API int py_debugger_status();"]},{"l":"py_debugger_exceptionbreakpoint"},{"i":"py_debugger_exceptionbreakpoint-code-1","c":["PK_API void py_debugger_exceptionbreakpoint(py_Ref exc);"]},{"l":"py_debugger_exit"},{"i":"py_debugger_exit-code-1","c":["PK_API void py_debugger_exit(int code);"]},{"l":"py_newtuple"},{"i":"py_newtuple-code-1","c":["/// Create a `tuple` with `n` UNINITIALIZED elements.\n/// You should initialize all elements before using it.\nPK_API py_ObjectRef py_newtuple(py_OutRef, int n);"]},{"l":"py_tuple_data"},{"i":"py_tuple_data-code-1","c":["PK_API py_ObjectRef py_tuple_data(py_Ref self);"]},{"l":"py_tuple_getitem"},{"i":"py_tuple_getitem-code-1","c":["PK_API py_ObjectRef py_tuple_getitem(py_Ref self, int i);"]},{"l":"py_tuple_setitem"},{"i":"py_tuple_setitem-code-1","c":["PK_API void py_tuple_setitem(py_Ref self, int i, py_Ref val);"]},{"l":"py_tuple_len"},{"i":"py_tuple_len-code-1","c":["PK_API int py_tuple_len(py_Ref self);"]},{"l":"py_newlist"},{"i":"py_newlist-code-1","c":["/// Create an empty `list`.\nPK_API void py_newlist(py_OutRef);"]},{"l":"py_newlistn"},{"i":"py_newlistn-code-1","c":["/// Create a `list` with `n` UNINITIALIZED elements.\n/// You should initialize all elements before using it.\nPK_API void py_newlistn(py_OutRef, int n);"]},{"l":"py_list_data"},{"i":"py_list_data-code-1","c":["PK_API py_ItemRef py_list_data(py_Ref self);"]},{"l":"py_list_getitem"},{"i":"py_list_getitem-code-1","c":["PK_API py_ItemRef py_list_getitem(py_Ref self, int i);"]},{"l":"py_list_setitem"},{"i":"py_list_setitem-code-1","c":["PK_API void py_list_setitem(py_Ref self, int i, py_Ref val);"]},{"l":"py_list_delitem"},{"i":"py_list_delitem-code-1","c":["PK_API void py_list_delitem(py_Ref self, int i);"]},{"l":"py_list_len"},{"i":"py_list_len-code-1","c":["PK_API int py_list_len(py_Ref self);"]},{"l":"py_list_swap"},{"i":"py_list_swap-code-1","c":["PK_API void py_list_swap(py_Ref self, int i, int j);"]},{"l":"py_list_append"},{"i":"py_list_append-code-1","c":["PK_API void py_list_append(py_Ref self, py_Ref val);"]},{"l":"py_list_emplace"},{"i":"py_list_emplace-code-1","c":["PK_API py_ItemRef py_list_emplace(py_Ref self);"]},{"l":"py_list_clear"},{"i":"py_list_clear-code-1","c":["PK_API void py_list_clear(py_Ref self);"]},{"l":"py_list_insert"},{"i":"py_list_insert-code-1","c":["PK_API void py_list_insert(py_Ref self, int i, py_Ref val);"]},{"l":"py_newdict"},{"i":"py_newdict-code-1","c":["/// Create an empty `dict`.\nPK_API void py_newdict(py_OutRef);"]},{"l":"py_dict_getitem"},{"i":"py_dict_getitem-code-1","c":["/// -1: error, 0: not found, 1: found\nPK_API int py_dict_getitem(py_Ref self, py_Ref key);"]},{"l":"py_dict_setitem"},{"i":"py_dict_setitem-code-1","c":["/// true: success, false: error\nPK_API bool py_dict_setitem(py_Ref self, py_Ref key, py_Ref val);"]},{"l":"py_dict_delitem"},{"i":"py_dict_delitem-code-1","c":["/// -1: error, 0: not found, 1: found (and deleted)\nPK_API int py_dict_delitem(py_Ref self, py_Ref key);"]},{"l":"py_dict_getitem_by_str"},{"i":"py_dict_getitem_by_str-code-1","c":["/// -1: error, 0: not found, 1: found\nPK_API int py_dict_getitem_by_str(py_Ref self, const char* key);"]},{"l":"py_dict_getitem_by_int"},{"i":"py_dict_getitem_by_int-code-1","c":["/// -1: error, 0: not found, 1: found\nPK_API int py_dict_getitem_by_int(py_Ref self, py_i64 key);"]},{"l":"py_dict_setitem_by_str"},{"i":"py_dict_setitem_by_str-code-1","c":["/// true: success, false: error\nPK_API bool py_dict_setitem_by_str(py_Ref self, const char* key, py_Ref val);"]},{"l":"py_dict_setitem_by_int"},{"i":"py_dict_setitem_by_int-code-1","c":["/// true: success, false: error\nPK_API bool py_dict_setitem_by_int(py_Ref self, py_i64 key, py_Ref val);"]},{"l":"py_dict_delitem_by_str"},{"i":"py_dict_delitem_by_str-code-1","c":["/// -1: error, 0: not found, 1: found (and deleted)\nPK_API int py_dict_delitem_by_str(py_Ref self, const char* key);"]},{"l":"py_dict_delitem_by_int"},{"i":"py_dict_delitem_by_int-code-1","c":["/// -1: error, 0: not found, 1: found (and deleted)\nPK_API int py_dict_delitem_by_int(py_Ref self, py_i64 key);"]},{"l":"py_dict_apply"},{"i":"py_dict_apply-code-1","c":["/// true: success, false: error\nPK_API bool py_dict_apply(py_Ref self, bool (*f)(py_Ref key, py_Ref val, void* ctx), void* ctx);"]},{"l":"py_dict_len"},{"i":"py_dict_len-code-1","c":["/// noexcept\nPK_API int py_dict_len(py_Ref self);"]},{"l":"py_newslice"},{"i":"py_newslice-code-1","c":["/// Create an UNINITIALIZED `slice` object.\n/// You should use `py_setslot()` to set `start`, `stop`, and `step`.\nPK_API py_ObjectRef py_newslice(py_OutRef);"]},{"l":"py_newsliceint"},{"i":"py_newsliceint-code-1","c":["/// Create a `slice` object from 3 integers.\nPK_API void py_newsliceint(py_OutRef out, py_i64 start, py_i64 stop, py_i64 step);"]},{"l":"py_newRandom"},{"i":"py_newrandom-code-1","c":["PK_API void py_newRandom(py_OutRef out);"]},{"l":"py_Random_seed"},{"i":"py_random_seed-code-1","c":["PK_API void py_Random_seed(py_Ref self, py_i64 seed);"]},{"l":"py_Random_random"},{"i":"py_random_random-code-1","c":["PK_API py_f64 py_Random_random(py_Ref self);"]},{"l":"py_Random_uniform"},{"i":"py_random_uniform-code-1","c":["PK_API py_f64 py_Random_uniform(py_Ref self, py_f64 a, py_f64 b);"]},{"l":"py_Random_randint"},{"i":"py_random_randint-code-1","c":["PK_API py_i64 py_Random_randint(py_Ref self, py_i64 a, py_i64 b);"]},{"l":"py_newarray2d"},{"i":"py_newarray2d-code-1","c":["PK_API void py_newarray2d(py_OutRef out, int width, int height);"]},{"l":"py_array2d_getwidth"},{"i":"py_array2d_getwidth-code-1","c":["PK_API int py_array2d_getwidth(py_Ref self);"]},{"l":"py_array2d_getheight"},{"i":"py_array2d_getheight-code-1","c":["PK_API int py_array2d_getheight(py_Ref self);"]},{"l":"py_array2d_getitem"},{"i":"py_array2d_getitem-code-1","c":["PK_API py_ObjectRef py_array2d_getitem(py_Ref self, int x, int y);"]},{"l":"py_array2d_setitem"},{"i":"py_array2d_setitem-code-1","c":["PK_API void py_array2d_setitem(py_Ref self, int x, int y, py_Ref val);"]},{"l":"py_newvec2"},{"i":"py_newvec2-code-1","c":["PK_API void py_newvec2(py_OutRef out, c11_vec2);"]},{"l":"py_newvec3"},{"i":"py_newvec3-code-1","c":["PK_API void py_newvec3(py_OutRef out, c11_vec3);"]},{"l":"py_newvec2i"},{"i":"py_newvec2i-code-1","c":["PK_API void py_newvec2i(py_OutRef out, c11_vec2i);"]},{"l":"py_newvec3i"},{"i":"py_newvec3i-code-1","c":["PK_API void py_newvec3i(py_OutRef out, c11_vec3i);"]},{"l":"py_newvec4i"},{"i":"py_newvec4i-code-1","c":["PK_API void py_newvec4i(py_OutRef out, c11_vec4i);"]},{"l":"py_newcolor32"},{"i":"py_newcolor32-code-1","c":["PK_API void py_newcolor32(py_OutRef out, c11_color32);"]},{"l":"py_newmat3x3"},{"i":"py_newmat3x3-code-1","c":["PK_API c11_mat3x3* py_newmat3x3(py_OutRef out);"]},{"l":"py_tovec2"},{"i":"py_tovec2-code-1","c":["PK_API c11_vec2 py_tovec2(py_Ref self);"]},{"l":"py_tovec3"},{"i":"py_tovec3-code-1","c":["PK_API c11_vec3 py_tovec3(py_Ref self);"]},{"l":"py_tovec2i"},{"i":"py_tovec2i-code-1","c":["PK_API c11_vec2i py_tovec2i(py_Ref self);"]},{"l":"py_tovec3i"},{"i":"py_tovec3i-code-1","c":["PK_API c11_vec3i py_tovec3i(py_Ref self);"]},{"l":"py_tovec4i"},{"i":"py_tovec4i-code-1","c":["PK_API c11_vec4i py_tovec4i(py_Ref self);"]},{"l":"py_tomat3x3"},{"i":"py_tomat3x3-code-1","c":["PK_API c11_mat3x3* py_tomat3x3(py_Ref self);"]},{"l":"py_tocolor32"},{"i":"py_tocolor32-code-1","c":["PK_API c11_color32 py_tocolor32(py_Ref self);"]},{"l":"py_json_dumps"},{"i":"py_json_dumps-code-1","c":["/// Python equivalent to `json.dumps(val)`.\nPK_API bool py_json_dumps(py_Ref val, int indent);"]},{"l":"py_json_loads"},{"i":"py_json_loads-code-1","c":["/// Python equivalent to `json.loads(val)`.\nPK_API bool py_json_loads(const char* source);"]},{"l":"py_pickle_dumps"},{"i":"py_pickle_dumps-code-1","c":["/// Python equivalent to `pickle.dumps(val)`.\nPK_API bool py_pickle_dumps(py_Ref val);"]},{"l":"py_pickle_loads"},{"i":"py_pickle_loads-code-1","c":["/// Python equivalent to `pickle.loads(val)`.\nPK_API bool py_pickle_loads(const unsigned char* data, int size);"]},{"l":"py_watchdog_begin"},{"i":"py_watchdog_begin-code-1","c":["/// Begin the watchdog with `timeout` in milliseconds.\n/// `PK_ENABLE_WATCHDOG` must be defined to `1` to use this feature.\n/// You need to call `py_watchdog_end()` later.\n/// If `timeout` is reached, `TimeoutError` will be raised.\nPK_API void py_watchdog_begin(py_i64 timeout);"]},{"l":"py_watchdog_end"},{"i":"py_watchdog_end-code-1","c":["/// Reset the watchdog.\nPK_API void py_watchdog_end();"]},{"l":"py_profiler_begin"},{"i":"py_profiler_begin-code-1","c":["PK_API void py_profiler_begin();"]},{"l":"py_profiler_end"},{"i":"py_profiler_end-code-1","c":["PK_API void py_profiler_end();"]},{"l":"py_profiler_reset"},{"i":"py_profiler_reset-code-1","c":["PK_API void py_profiler_reset();"]},{"l":"py_profiler_report"},{"i":"py_profiler_report-code-1","c":["PK_API char* py_profiler_report();"]},{"l":"py_replinput"},{"i":"py_replinput-code-1","c":["/// An utility function to read a line from stdin for REPL.\nPK_API int py_replinput(char* buf, int max_size);"]}],[{"l":"array2d","p":["Efficient general-purpose 2D array."]},{"l":"Source code"}],[{"l":"base64"},{"l":"base64.b64encode(b: bytes) - bytes","p":["Encode bytes-like object b using the standard Base64 alphabet."]},{"l":"base64.b64decode(b: str | bytes) - bytes","p":["Decode Base64 encoded bytes-like object b."]}],[{"l":"bisect"},{"l":"bisect.bisect_left(a, x)","p":["Return the index where to insert item x in list a, assuming a is sorted."]},{"l":"bisect.bisect_right(a, x)","p":["Return the index where to insert item x in list a, assuming a is sorted."]},{"l":"bisect.insort_left(a, x)","p":["Insert item x in list a, and keep it sorted assuming a is sorted.","If x is already in a, insert it to the left of the leftmost x."]},{"l":"bisect.insort_right(a, x)","p":["Insert item x in list a, and keep it sorted assuming a is sorted.","If x is already in a, insert it to the right of the rightmost x."]},{"l":"Source code"}],[{"l":"cmath","p":["Mathematical functions for complex numbers.","https://docs.python.org/3/library/cmath.html"]},{"l":"Source code"}],[{"l":"collections"},{"l":"collections.Counter(iterable)","p":["Return a dict containing the counts of each element in iterable."]},{"l":"collections.deque","p":["A double-ended queue."]},{"l":"collections.defaultdict","p":["A dictionary that returns a default value when a key is not found."]},{"l":"Source code"}],[{"l":"cute_png","p":["This module is optional. Set option PK_BUILD_MODULE_CUTE_PNG to ON in your CMakeLists.txt to enable it.","Wraps cute_png.h for PNG image loading and saving."]},{"l":"Source code"}],[{"l":"dataclasses"},{"l":"dataclasses.dataclass","p":["A decorator that is used to add special method to classes, including __init__, __repr__ and __eq__."]},{"l":"dataclasses.asdict(obj) - dict","p":["Convert a dataclass instance to a dictionary."]},{"l":"Source code"}],[{"l":"datetime"},{"l":"datetime.now()","p":["Returns the current date and time as a datetime object."]},{"l":"date.today()","p":["Returns the current local date as a date object."]},{"l":"Source code"}],[{"l":"easing","p":["easing.InBack(t: float) - float","easing.InBounce(t: float) - float","easing.InCirc(t: float) - float","easing.InCubic(t: float) - float","easing.InElastic(t: float) - float","easing.InExpo(t: float) - float","easing.InOutBack(t: float) - float","easing.InOutBounce(t: float) - float","easing.InOutCirc(t: float) - float","easing.InOutCubic(t: float) - float","easing.InOutElastic(t: float) - float","easing.InOutExpo(t: float) - float","easing.InOutQuad(t: float) - float","easing.InOutQuart(t: float) - float","easing.InOutQuint(t: float) - float","easing.InOutSine(t: float) - float","easing.InQuad(t: float) - float","easing.InQuart(t: float) - float","easing.InQuint(t: float) - float","easing.InSine(t: float) - float","easing.Linear(t: float) - float","easing.OutBack(t: float) - float","easing.OutBounce(t: float) - float","easing.OutCirc(t: float) - float","easing.OutCubic(t: float) - float","easing.OutElastic(t: float) - float","easing.OutExpo(t: float) - float","easing.OutQuad(t: float) - float","easing.OutQuart(t: float) - float","easing.OutQuint(t: float) - float","easing.OutSine(t: float) - float","Python wrapper for easing functions."]}],[{"l":"enum"},{"l":"enum.Enum","p":["Base class for creating enumerated constants.","Example:"]},{"i":"enumenum-code-1","c":["from enum import Enum\n\nclass Color(Enum):\n RED = 1\n GREEN = 2\n BLUE = 3\n\nprint(Color.RED) # Color.RED\nprint(Color.RED.name) # 'RED'\nprint(Color.RED.value) # 1"]}],[{"l":"functools"},{"l":"functools.cache","p":["A decorator that caches a function's return value each time it is called. If called later with the same arguments, the cached value is returned, and not re-evaluated."]},{"l":"functools.lru_cache(maxsize=128)","p":["A decorator that wraps a function with a memoizing callable that saves up to the maxsize most recent calls."]},{"l":"functools.reduce(function, sequence, initial=...)","p":["Apply a function of two arguments cumulatively to the items of a sequence, from left to right, so as to reduce the sequence to a single value. For example, functools.reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates ((((1+2)+3)+4)+5). The left argument, x, is the accumulated value and the right argument, y, is the update value from the sequence. If the optional initial is present, it is placed before the items of the sequence in the calculation, and serves as a default when the sequence is empty."]},{"l":"functools.partial(f, *args, **kwargs)","p":["Return a new partial object which when called will behave like f called with the positional arguments args and keyword arguments kwargs. If more arguments are supplied to the call, they are appended to args. If additional keyword arguments are supplied, they extend and override kwargs."]},{"l":"Source code"}],[{"l":"gc","p":["Garbage collection interface module."]},{"l":"Source code"}],[{"l":"heapq"},{"l":"heapq.heappush(heap, item)","p":["Push the value item onto the heap, maintaining the heap invariant."]},{"l":"heapq.heappop(heap)","p":["Pop and return the smallest item from the heap, maintaining the heap invariant. If the heap is empty, IndexError is raised. To access the smallest item without popping it, use heap[0]."]},{"l":"heapq.heapify(x)","p":["Transform list x into a heap, in-place, in linear time."]},{"l":"heapq.heappushpop(heap, item)","p":["Push item on the heap, then pop and return the smallest item from the heap. The combined action runs more efficiently than heappush() followed by a separate heappop()."]},{"l":"heapq.heapreplace(heap, item)","p":["Pop and return the smallest item from the heap, and also push the new item. The heap size doesn’t change. If the heap is empty, IndexError is raised."]},{"l":"Source code"}],[{"l":"importlib"},{"l":"importlib.reload(module)","p":["Reload a previously imported module. The argument must be a module object, so it must have been successfully imported before. This is useful if you have edited the module source file using an external editor and want to try out the new version without leaving the Python interpreter. The return value is the module object (the same as the argument)."]}],[{"l":"json","p":["JSON serialization and deserialization module.","This module is not safe. You may not want to use it with untrusted data. If you need a safe alternative, consider a 3rd-party library like cjson.","You can override the json functions with:"]},{"i":"json-code-1","c":["py_GlobalRef mod = py_getmodule(\"json\");\npy_bindfunc(mod, \"loads\", _safe_json_loads);\npy_bindfunc(mod, \"dumps\", _safe_json_dumps);"]},{"l":"Source code"}],[{"l":"lz4","p":["This module is optional. Set option PK_BUILD_MODULE_LZ4 to ON in your CMakeLists.txt to enable it.","LZ4 compression and decompression."]},{"l":"Source code"}],[{"l":"math"},{"l":"math.pi","p":["3.141592653589793"]},{"l":"math.e","p":["2.718281828459045"]},{"l":"math.inf","p":["The inf."]},{"l":"math.nan","p":["The nan."]},{"l":"math.ceil(x)","p":["Return the ceiling of x as a float, the smallest integer value greater than or equal to x."]},{"l":"math.fabs(x)","p":["Return the absolute value of x."]},{"l":"math.floor(x)","p":["Return the floor of x as a float, the largest integer value less than or equal to x."]},{"l":"math.fsum(iterable)","p":["Return an accurate floating point sum of values in the iterable. Avoids loss of precision by tracking multiple intermediate partial sums:"]},{"i":"mathfsumiterable-code-1","c":[">>> sum([0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1])\n0.9999999999999999\n>>> fsum([0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1])\n1.0"]},{"l":"math.gcd(a, b)","p":["Return the greatest common divisor of the integers a and b."]},{"l":"math.isfinite(x)","p":["Return True if x is neither an infinity nor a NaN, and False otherwise."]},{"l":"math.isinf(x)","p":["Return True if x is a positive or negative infinity, and False otherwise."]},{"l":"math.isnan(x)","p":["Return True if x is a NaN (not a number), and False otherwise."]},{"l":"math.isclose(a, b)","p":["Return True if the values a and b are close to each other and False otherwise."]},{"l":"math.exp(x)","p":["Return e raised to the power of x."]},{"l":"math.log(x)","p":["Return the natural logarithm of x (to base e)."]},{"l":"math.log2(x)","p":["Return the base-2 logarithm of x. This is usually more accurate than log(x, 2)."]},{"l":"math.log10(x)","p":["Return the base-10 logarithm of x. This is usually more accurate than log(x, 10)."]},{"l":"math.pow(x, y)","p":["Return x raised to the power y."]},{"l":"math.sqrt(x)","p":["Return the square root of x."]},{"l":"math.acos(x)","p":["Return the arc cosine of x, in radians."]},{"l":"math.asin(x)","p":["Return the arc sine of x, in radians."]},{"l":"math.atan(x)","p":["Return the arc tangent of x, in radians."]},{"l":"math.atan2(y, x)","p":["Return atan(y / x), in radians. The result is between -pi and pi. The vector in the plane from the origin to point (x, y) makes this angle with the positive X axis. The point of atan2() is that the signs of both inputs are known to it, so it can compute the correct quadrant for the angle. For example, atan(1) and atan2(1, 1) are both pi/4, but atan2(-1, -1) is -3*pi/4."]},{"l":"math.cos(x)","p":["Return the cosine of x radians."]},{"l":"math.sin(x)","p":["Return the sine of x radians."]},{"l":"math.tan(x)","p":["Return the tangent of x radians."]},{"l":"math.degrees(x)","p":["Convert angle x from radians to degrees."]},{"l":"math.radians(x)","p":["Convert angle x from degrees to radians."]},{"l":"math.modf(x)","p":["Return the fractional and integer parts of x. Both results carry the sign of x and are floats."]},{"l":"math.copysign(x, y)","p":["Return a float with the magnitude (absolute value) of x but the sign of y."]},{"l":"math.factorial(x)","p":["Return x factorial as an integer."]}],[{"l":"msgpack","p":["This module is optional. Set option PK_BUILD_MODULE_MSGPACK to ON in your CMakeLists.txt to enable it."]},{"l":"msgpack.loads(data: bytes)","p":["Decode a msgpack bytes into a python object."]},{"l":"msgpack.dumps(obj) - bytes","p":["Encode a python object into a msgpack bytes."]}],[{"l":"operator","p":["The operator module exports a set of efficient functions corresponding to the intrinsic operators of Python. For example, operator.add(x, y) is equivalent to the expression x+y. Many function names are those used for special methods, without the double underscores."]},{"l":"Mapping Operators to Functions","p":["-a","~a","a - b","a != b","a @ b","a * b","a ** b","a / b","a // b","a % b","a ^ b","a + b","a = b","a == b","a | b","a b","a is b","a is not b","a[b]","a[b] = c","add(a, b)","Addition","and_(a, b)","b in a","Bitwise AND","Bitwise Inversion","Bitwise OR","Bitwise XOR","bool(a)","Containment Test","contains(a, b)","del a[b]","delitem(a, b)","Division","eq(a, b)","Equality","Exponentiation","floordiv(a, b)","Function","ge(a, b)","getitem(a, b)","gt(a, b)","Identity","Index Assignment","Index Deletion","Indexing","invert(a)","is_(a, b)","is_not(a, b)","le(a, b)","Left Shift","lshift(a, b)","lt(a, b)","matmul(a, b)","Matrix Multiplication","mod(a, b)","Modulo","mul(a, b)","Multiplication","ne(a, b)","neg(a)","Negation (Arithmetic)","Negation (Logical)","not a","not_(a)","Operation","or_(a, b)","Ordering","pow(a, b)","Right Shift","rshift(a, b)","setitem(a, b, c)","sub(a, b)","Subtraction","Syntax","truediv(a, b)","Truth Test","truth(a)","xor(a, b)"]},{"l":"In-place Operators","p":["a -= b","a *= b","a //= b","a /= b","a %= b","a ^= b","a += b","a = b","a |= b","Addition","Bitwise AND","Bitwise OR","Bitwise XOR","Division","Function","iadd(a, b)","iand(a, b)","ifloordiv(a, b)","ilshift(a, b)","imod(a, b)","imul(a, b)","ior(a, b)","irshift(a, b)","isub(a, b)","itruediv(a, b)","ixor(a, b)","Left Shift","Modulo","Multiplication","Operation","Right Shift","Subtraction","Syntax"]}],[{"l":"periphery","p":["This module is optional. Set option PK_BUILD_MODULE_PERIPHERY to ON in your CMakeLists.txt to enable it."]},{"l":"Source code"}],[{"l":"pickle"},{"l":"pickle.dumps(obj) - bytes","p":["Return the pickled representation of an object as a bytes object."]},{"l":"pickle.loads(b: bytes)","p":["Return the unpickled object from a bytes object."]},{"l":"What can be pickled and unpickled?","p":["The following types can be pickled:","None, True, and False;","integers, floating-point numbers;","strings, bytes;","tuples, lists, sets, and dictionaries containing only picklable objects;","functions (user-defined) accessible from the top level of a module (using def, not lambda);","classes accessible from the top level of a module;","instances of such classes","The following magic methods are available:","__getnewargs__","__getstate__","__setstate__","__reduce__"]}],[{"l":"pkpy","p":["Provide internal access to the pocketpy interpreter."]},{"l":"Source code"}],[{"l":"random"},{"l":"random.seed(a)","p":["Set the random seed."]},{"l":"random.random()","p":["Return a random float number in the range [0.0, 1.0)."]},{"l":"random.randint(a, b)","p":["Return a random integer in the range [a, b]."]},{"l":"random.uniform(a, b)","p":["Return a random float number in the range [a, b)."]},{"l":"random.choice(seq)","p":["Return a random element from a sequence."]},{"l":"random.shuffle(seq)","p":["Shuffle a sequence inplace."]},{"l":"random.choices(population, weights=None, k=1)","p":["Return a k sized list of elements chosen from the population with replacement."]}],[{"l":"sys"},{"l":"sys.version","p":["The version of pkpy."]},{"l":"sys.platform","p":["May be one of:","win32","linux","darwin","android","ios","emscripten"]},{"l":"sys.argv","p":["The command line arguments. Set by py_sys_setargv."]},{"l":"sys.setrecursionlimit(limit: int)","p":["Set the maximum depth of the Python interpreter stack to limit. This limit prevents infinite recursion from causing an overflow of the C stack and crashing the interpreter."]},{"l":"sys.getrecursionlimit() - int","p":["Return the current value of the recursion limit."]}],[{"l":"time"},{"l":"time.time()","p":["Returns the current time in seconds since the epoch as a floating point number."]},{"l":"time.sleep(secs)","p":["Suspend execution of the calling thread for the given number of seconds."]},{"l":"time.localtime()","p":["Returns the current struct time as a struct_time object."]}],[{"l":"traceback"},{"l":"traceback.print_exc() - None","p":["Print the last exception and its traceback."]},{"l":"traceback.format_exc() - str","p":["Return the last exception and its traceback as a string."]}],[{"l":"typing","p":["Placeholder module for type hints."]},{"l":"Source code"}],[{"l":"unicodedata"},{"l":"unicodedata.east_asian_width(char: str) - str","p":["Returns the East Asian width of a Unicode character. The width is one of the following values:","F: Fullwidth","H: Halfwidth","N: Neutral","Na: Narrow","W: Wide","A: Ambiguous"]}],[{"l":"vmath","p":["Provide vector math operations."]},{"l":"Source code"}],[{"l":"Application Guide","p":["Welcome to the Google Summer of Code 2026 application guide for pocketpy. We are recruiting a student who is passionate about vibe coding and mobile game development.","See Project Ideas for more details about the project."]},{"l":"Prerequisites","p":["To apply for this project, you need to satisfy the following prerequisites:","You are a student enrolled in an accredited institution (university, college, etc.) pursuing a degree in computer science or a related field. And this is your first time participating in Google Summer of Code.","You have interest in vibe coding and mobile game development.","You are experienced in Python and backend technologies, such as FastAPI or Flask.","You are glad to learn game engines like Godot."]},{"l":"Application steps"},{"l":"Step 1","p":["If you think you meet the prerequisites, send an email to blueloveth@foxmail.com with the following information.","A brief introduction about yourself, including the most related open sourced project you have worked on before. It is highly recommended to attach your Github profile link.","Your understanding of this project and why you are capable of completing it.","Your free time during the whole GSoC period (From 2026-03-01 to 2026-08-31)."]},{"l":"Step 2","p":["After you get a positive reply from us, you need to complete 1~2 pull requests to pocketpy's repository on GitHub. This is mandatory as it demonstrates your coding skills and commitment to the project. We will provide you a few good first issues to work on."]},{"l":"Step 3","p":["Once your pull requests are merged, we will guide you to write a full proposal for the project you are going to work on during GSoC 2026. This proposal will be submitted to Google for review."]},{"l":"Build guide for pocketpy","p":["First, you need to install these tools:","Python(>= 3.8), I am sure you already have it.","A C11 compiler, such as GCC, Clang or MSVC. If you are on Linux, gcc is already installed. If you are on Windows, you can install Visual Studio with C/C++ development tools.","CMake(>= 3.10), a cross-platform build tool. You can use pip install cmake to install it.","Then, clone pocketpy sources from github and try to build:","If everything goes well, you will get a main executable (main.exe on Windows) in the root directory of pocketpy. Simply run it and you will enter pocketpy's REPL."]},{"i":"build-guide-for-pocketpy-code-1","c":["git clone https://github.com/pocketpy/pocketpy\ncd pocketpy\n\npython cmake_build.py"]},{"i":"build-guide-for-pocketpy-code-2","c":["pocketpy 2.1.7 (Jan 7 2026, 16:42:45) [64 bit] on darwin\nhttps://github.com/pocketpy/pocketpy\nType \"exit()\" to exit.\n>>> \n>>> \"Hello, world\"\n'Hello, world'"]},{"l":"Coding style guide","p":["See Coding Style Guide."]}],[{"l":"Project Ideas"},{"l":"Idea Title","p":["Build a Vibe Coding Agent in Python for Creating Games"]},{"l":"Project Size","p":["Medium"]},{"l":"Related Skills","p":["CPython","Agentic Programming","Prompt Engineering","Game Engines"]},{"l":"Description","p":["pocketpy is an organization dedicated to creating game development tools in Python language. Nowadays, vibe coding has become a popular approach for rapid game development, allowing developers to create games quickly and efficiently by leveraging language models and agentic programming techniques.","For Google Summer of Code 2026, we are looking for a student to develop a vibe coding agent that can assist developers in creating games. This agent is composed of two main components, backend and frontend.","The backend part should be developed in CPython, which is composed of the following modules:","Virtual Container. The agent needs to create a virtual linux container for each vibe coding project. This module provides management for users' sources and assets inside the container.","AI Service Provider. This module is responsible for communicating with AI service providers, such as OpenAI, to generate code and assets based on user prompts.","Persistent Memory. This module stores the state of each vibe coding project, including project progress, user preferences, and other relevant information.","Agentic Core. This module uses Persistent Memory and AI Service Provider to implement the agentic programming logic, enabling the agent to understand user prompts and generate appropriate code and assets.","Game Engine Integration.","For more details, we will discuss with the selected student during the community bonding period."]}],[{"l":"Application Guide","p":["Before starting, please read the Ideas page and choose a project you are interested in. Set up a C11 compiler, clone pocketpy sources from github and try to build. This helps you confirm that your skills and experience match the requirements of the project."]},{"l":"Build guide for beginners","p":["First, you need to install these tools:","Python(>= 3.8), I am sure you already have it.","A C11 compiler, such as GCC, Clang or MSVC. If you are on Linux, gcc is already installed. If you are on Windows, you can install Visual Studio with C/C++ development tools.","CMake(>= 3.10), a cross-platform build tool. You can use pip install cmake to install it.","Then, clone pocketpy sources from github and try to build:","If everything goes well, you will get a main executable (main.exe on Windows) in the root directory of pocketpy. Simply run it and you will enter pocketpy's REPL."]},{"i":"build-guide-for-beginners-code-1","c":["git clone https://github.com/pocketpy/pocketpy\ncd pocketpy\n\npython cmake_build.py"]},{"i":"build-guide-for-beginners-code-2","c":["pocketpy 2.0.5 (Jan 17 2025, 14:36:15) [64 bit] on darwin\nhttps://github.com/pocketpy/pocketpy\nType \"exit()\" to exit.\n>>> \n>>> \"Hello, world\"\n'Hello, world'"]},{"l":"Application guide","p":["Your need to send an email to blueloveth@foxmail.com with the following information:","A brief introduction about yourself, including the most related open sourced project you have worked on before. It is highly recommended to attach your Github profile link.","A technical proposal for the project you are interested in working on, including:","Your understanding of the project.","The technical approach/architecture you will adopt.","The challenges you might face and how you will overcome them.","A timeline for the project, including the milestones and deliverables.","Other information required by the Google Summer of Code program."]},{"l":"Coding style guide","p":["See Coding Style Guide."]},{"l":"Contact us","p":["If you have any questions, you can join our Discord or contact me via email. We are glad to help you with your application."]}],[{"l":"Project Ideas"},{"l":"VSCode plugin for debugging pocketpy applications","p":["Difficulty Level: 3/5 (Medium)","Skill: TypeScript; C","Project Length: Medium","Community users have reported that there is no convenient way to debug python applications interpreted by pocketpy. Fortunately, VSCode provides a mechanism of Debugger Extension that allows us to integrate pocketpy debugger into VSCode UI through Debug Adapter Protocol (DAP).","This project aims to develop a VSCode plugin like Python Debugger, which implements DAP for pocketpy. With this plugin, users can launch their pocketpy applications in VSCode with breakpoints, call stacks, and variable inspection. Students with experience in TypeScript will be helpful for this project."]},{"l":"Develop math operators for cTensor library","p":["Difficulty Level: 4/5 (Hard)","Skill: C; Further Mathematics","Project Length: Small or Medium","pocketpy is providing a tensor library cTensor for users who want to integrate neural networks into their applications. cTensor implements automatic differentiation and dynamic compute graph. It allows users to train and deploy neural networks on client-side devices like mobile phones and microcontrollers (e.g. ESP32-C3). We have a runable prototype located at pocketpy/cTensor. But math operators have not been implemented yet.","In this project, students will develop forward and backward math operators, as well as basic neural network layers and optimizers (e.g. SGD, Adam). The project is written in C11. We expect students to have a good understanding of further mathematics and C programming.","This year we also accept custom project ideas. If you are not interested in the above, you can propose your own idea and contact me via blueloveth@foxmail.com. We will discuss the feasibility and mentorship for your idea."]}],[{"l":"Application Guide","p":["Before starting, please read the Ideas page and choose a project you are interested in. Set up a C++ compiler, clone pocketpy sources from github and try to build. This helps you confirm that your skills and experience match the requirements of the project."]},{"l":"Build guide for beginners","p":["First, you need to install these tools:","Python(>= 3.8), I am sure you already have it.","A C++ compiler, such as GCC, Clang or MSVC. If you are on Linux, gcc and g++ are already installed. If you are on Windows, you can install Visual Studio with C++ development tools.","CMake(>= 3.10), a cross-platform build tool. You can use pip install cmake to install it.","Then, clone pocketpy sources from github and try to build:","If everything goes well, you will get a main executable (main.exe on Windows) in the root directory of pocketpy. Simply run it and you will enter pocketpy's REPL."]},{"i":"build-guide-for-beginners-code-1","c":["git clone https://github.com/pocketpy/pocketpy\ncd pocketpy\n\npython cmake_build.py"]},{"i":"build-guide-for-beginners-code-2","c":["pocketpy 1.4.0 (Jan 24 2024, 12:39:13) [32 bit] on emscripten\nhttps://github.com/pocketpy/pocketpy\nType \"exit()\" to exit.\n>>>\n>>> \"Hello, world\"\n'Hello, world'"]},{"l":"Application guide","p":["Your need to send an email to blueloveth@foxmail.com with the following information:","A brief introduction about yourself, including the most related open sourced project you have worked on before. It is highly recommended to attach your Github profile link.","A technical proposal for the project you are interested in working on, including:","Your understanding of the project.","The technical approach/architecture you will adopt.","The challenges you might face and how you will overcome them.","A timeline for the project, including the milestones and deliverables.","Other information required by the Google Summer of Code program."]},{"l":"Coding style guide","p":["See Coding Style Guide."]},{"l":"Contact us","p":["If you have any questions, you can join our Discord or contact me via email. We are glad to help you with your application."]}],[{"l":"Project Ideas"},{"l":"Implement pybind11 for bindings","p":["Difficulty Level: 5/5 (Hard)","Skill: Advanced C++ with metaprogramming; Python","Project Length: Medium (175 hours)","https://summerofcode.withgoogle.com/archive/2024/projects/Ji2Mi97o","pocketpy has provided a low-level API for creating bindings. It is fast, lightweight and easy to debug. However, it still requires a lot of boilerplate code to create bindings for complex C++ classes. The community has long expected a high-level API for creating bindings.","pybind11 is the most popular C++ library for creating Python bindings for CPython. A bunch of Python libraries are using it. pybind11 adopts a template metaprogramming approach to automatically generate bindings for C++ classes.","Our goal is to introduce a pybind11 compatible solution to pocketpy as an alternative way to create bindings for functions and classes. You can use C++17 features to implement it, instead of C++11 used in pybind11.","See https://github.com/pocketpy/pocketpy/issues/216 for more details."]},{"l":"Add numpy module","p":["Difficulty Level: 4/5 (Intermediate)","Skill: Intermediate C++; Python; Linear Algebra","Project Length: Medium (175 hours)","https://summerofcode.withgoogle.com/archive/2024/projects/sJLuASSP","Though pocketpy is designed for game scripting, some people are using it for scientific computing. It would be nice to have a numpy module in pocketpy.","numpy is a huge project. Our goal is to implement a most commonly used subset of numpy in pocketpy. You can mix C++ and Python code to simplify the overall workloads.","See https://github.com/pocketpy/pocketpy/issues/202 for more details."]}],[{"l":"Coding Style Guide"},{"l":"Indentation","p":["Use four spaces for indentation. Do not use TAB."]},{"l":"Strings"},{"i":"strings-code-1","c":["# Prefer single quotes for strings\ns = 'this is a string'\n\n# Use double quotes only if the string itself contains a single quote\ns = \"this ' is single quote\""]},{"l":"Docstrings","p":["Always use triple quotes for docstrings.","Use natural language to describe the function's purpose. Do not enumerate each parameter and return value."]},{"i":"docstrings-code-1","c":["def f():\n \"\"\"This is a multi-line docstring.\n\n Here is some content. Docstrings partially support Markdown.\n \"\"\"\n\ndef g():\n \"\"\"This is a single-line docstring.\"\"\""]},{"i":"docstrings-code-2","c":["# Correct\ndef add(a: int, b: int):\n \"\"\"Add two integers `a` and `b`.\"\"\"\n\n# Incorrect\ndef add(a: int, b: int):\n \"\"\"\n @param a, the first argument\n @param b, the second argument\n @return, the result of a + b\n \"\"\""]},{"l":"Spaces"},{"i":"spaces-code-1","c":["# Add a space after `,` or `:`\na, b = 1, 2\nc = [1, 2, 3]\nd = {'key': 'value'}\n\n# Spaces may be added around operators\nres = 1 + 2\nif res < 2: pass\n# Spaces can also be selectively added to indicate operator precedence\nx = x * 2 - 1\nhypot2 = x * x + y * y\nc = (a + b) * (a - b)\n\n# Add a space after `:` in type annotations\ndef f(a: int, b: float): ...\ndef g() -> int: ...\n\n# Add spaces around `=` when specifying default values in function parameters\ndef f(a: int = 1, b: int | None = None): ...\n# However, omit spaces if the parameter has no type annotation\ndef f(a=1, b=2): pass\n\n# Do not add spaces in keyword arguments when calling functions\nprint(1, 2, 3, end='', sep=',')\nf(a=10, b=20)"]},{"l":"Naming Conventions","p":["Classes: CapitalizedWords","Functions and variables: lower_case_with_underscores","Constants and enums: UPPER_CASE_WITH_UNDERSCORES or CapitalizedWords","Anonymous ordered variables: _0, _1, _2","Discarded variables: _","Some standard library functions: lowercase","Here are some commonly used naming conventions:","self: The first parameter of an instance method","cls: The first parameter of class methods and __new__"]},{"l":"Using Abbreviations","p":["Use abbreviations only for temporary variables and internal implementations.","Abbreviations should be well-established, include key syllables of the original word, and be immediately recognizable.","context -> ctx (✔)","temporary -> tmp (✔)","distribution -> dist (✔)","visited -> vis (❌)"]},{"i":"using-abbreviations-code-1","c":["# Incorrect: Using abbreviations in public function parameters\ndef some_pub_fn(ctx, req_id, data):\n pass\n\n# Correct\ndef some_public_function(context, request_id, data):\n pass"]},{"l":"Using Precise Terminology","p":["Naming should convey precise meanings, especially when multiple synonyms exist.","For example, count, size, and length all relate to quantity, but they have different nuances:","count: Represents a counted value","length: Represents the number of elements in a container","size: Represents the byte size of an object"]},{"i":"using-precise-terminology-code-1","c":["s = 'aaabc⭐'\ncount = s.count('a')\nlength = len(s)\nsize = len(s.encode())\n\nprint(f\"{s!r} has a length of {length}, a size of {size} bytes, and contains {count} occurrences of 'a'\")\n# 'aaabc⭐' has a length of 6, a size of 8 bytes, and contains 3 occurrences of 'a'"]},{"l":"Using Professional Terminology","p":["For item quantities in a game: quantity is better than item_count","For grid counts: area (meaning surface area) is better than grid_count"]},{"l":"Avoiding Built-in Names"},{"i":"avoiding-built-in-names-code-1","c":["# Incorrect: Overwriting `builtins.map`\nmap = [[1, 2, 3], [4, 5, 6]]\n# Incorrect: Overwriting `builtins.type`\ntype = some_thing.type"]},{"l":"Internal Functions and Classes","p":["Use a single underscore _ as a prefix for internal functions. Never use a double underscore __ (except for magic methods)."]},{"i":"internal-functions-and-classes-code-1","c":["def _internal_func():\n \"\"\"This is an internal function.\"\"\"\n\nclass _InternalClass:\n def _internal_f(self): pass"]},{"l":"Importing Modules","p":["Import standard library modules first.","Then import third-party dependencies.","Finally, import project-specific modules."]},{"i":"importing-modules-code-1","c":["from typing import Any\nfrom collections import deque\n\nfrom array2d import array2d\n\nfrom ..utils import logger"]},{"l":"Coding Practices","p":["Use is not when checking for None. Do not explicitly compare with True or False.","The if statement implicitly calls bool(), so it can be used to check if a container is empty."]},{"i":"coding-practices-code-1","c":["# Correct\nif x is not None: pass\n\n# Incorrect\nif x != None: pass\n\n# Correct\nx = True\nif x: pass\nif not x: pass\n\n# Incorrect\nif x == True: pass\nif x is True: pass\nif x != False: pass"]},{"i":"coding-practices-code-2","c":["not_empty_list = [1]\nnot_empty_string = '1'\ntruth = True\n\nif not_empty_list:\n print('true value')\n\nif not_empty_string:\n print('true value')\n\nif truth:\n print('true value')\n\n# Explicitly checking for emptiness is also valid\nif len(not_empty_list) > 0: pass"]},{"l":"References","p":["PEP 8 – Style Guide for Python Code"]}],[{"l":"Performance","p":["Currently, pkpy is as fast as cpython 3.9. Performance results for cpython 3.9 are applicable to for pkpy.","Here is a benchmark result of v1.2.6. Files are located in benchmarks/."]},{"l":"win32 64-bit cpy39"},{"i":"win32-64-bit-cpy39-code-1","c":["CPython: 3.9.13 (tags/v3.9.13:6de2ca5, May 17 2022, 16:36:42) [MSC v.1929 64 bit (AMD64)]\nSystem: 64-bit\nTesting directory: benchmarks/\n> benchmarks/fib.py\n cpython: 0.986091s (100%)\n pocketpy: 0.985427s (99.93%)\n> benchmarks/loop_0.py\n cpython: 0.515685s (100%)\n pocketpy: 0.344132s (66.73%)\n> benchmarks/loop_1.py\n cpython: 0.938407s (100%)\n pocketpy: 0.595634s (63.47%)\n> benchmarks/loop_2.py\n cpython: 1.188671s (100%)\n pocketpy: 0.735259s (61.86%)\n> benchmarks/loop_3.py\n cpython: 4.957218s (100%)\n pocketpy: 2.314210s (46.68%)\n> benchmarks/primes.py\n cpython: 9.146332s (100%)\n pocketpy: 8.507227s (93.01%)\n> benchmarks/recursive.py\n cpython: 0.044789s (100%)\n pocketpy: 0.031252s (69.78%)\n> benchmarks/simple.py\n cpython: 0.516624s (100%)\n pocketpy: 0.453159s (87.72%)\n> benchmarks/sort.py\n cpython: 0.929597s (100%)\n pocketpy: 0.406802s (43.76%)\n> benchmarks/sum.py\n cpython: 0.047151s (100%)\n pocketpy: 0.031266s (66.31%)\nALL TESTS PASSED"]},{"l":"linux 64-bit cpy38"},{"i":"linux-64-bit-cpy38-code-1","c":["CPython: 3.8.10 (default, May 26 2023, 14:05:08) [GCC 9.4.0]\nSystem: 64-bit\nTesting directory: benchmarks/\n> benchmarks/fib.py\n cpython: 0.739547s (100%)\n pocketpy: 0.613591s (82.97%)\n> benchmarks/loop_0.py\n cpython: 0.356003s (100%)\n pocketpy: 0.224396s (63.03%)\n> benchmarks/loop_1.py\n cpython: 0.661924s (100%)\n pocketpy: 0.446577s (67.47%)\n> benchmarks/loop_2.py\n cpython: 0.937243s (100%)\n pocketpy: 0.514324s (54.88%)\n> benchmarks/loop_3.py\n cpython: 3.671752s (100%)\n pocketpy: 1.876151s (51.10%)\n> benchmarks/primes.py\n cpython: 7.293947s (100%)\n pocketpy: 5.427518s (74.41%)\n> benchmarks/recursive.py\n cpython: 0.021559s (100%)\n pocketpy: 0.010227s (47.44%)\n> benchmarks/simple.py\n cpython: 0.408654s (100%)\n pocketpy: 0.265084s (64.87%)\n> benchmarks/sort.py\n cpython: 0.372539s (100%)\n pocketpy: 0.243566s (65.38%)\n> benchmarks/sum.py\n cpython: 0.021242s (100%)\n pocketpy: 0.010113s (47.61%)\nALL TESTS PASSED"]},{"l":"linux 32-bit cpy39","p":["See actions/runs."]},{"i":"linux-32-bit-cpy39-code-1","c":["CPython: 3.9.18 (main, Aug 26 2023, 11:50:23) [GCC 10.3.1 20211027]\nSystem: 32-bit\nTesting directory: benchmarks/\n> benchmarks/fib.py\n cpython: 1.967908s (100%)\n pocketpy: 0.960947s (48.83%)\n> benchmarks/loop_0.py\n cpython: 1.063461s (100%)\n pocketpy: 0.396626s (37.30%)\n> benchmarks/loop_1.py\n cpython: 1.563821s (100%)\n pocketpy: 0.639663s (40.90%)\n> benchmarks/loop_2.py\n cpython: 2.626848s (100%)\n pocketpy: 0.757444s (28.83%)\n> benchmarks/loop_3.py\n cpython: 13.428345s (100%)\n pocketpy: 2.852351s (21.24%)\n> benchmarks/primes.py\n cpython: 18.174904s (100%)\n pocketpy: 8.423515s (46.35%)\n> benchmarks/recursive.py\n cpython: 0.025673s (100%)\n pocketpy: 0.012470s (48.57%)\n> benchmarks/simple.py\n cpython: 1.042090s (100%)\n pocketpy: 0.480013s (46.06%)\n> benchmarks/sort.py\n cpython: 0.989279s (100%)\n pocketpy: 0.379171s (38.33%)\n> benchmarks/sum.py\n cpython: 0.024227s (100%)\n pocketpy: 0.012477s (51.50%)\nALL TESTS PASSED"]},{"l":"Primes benchmarks","p":["0.104s ■□□□□□□□□□□□□□□□","1.2.7","1.576s ■■■■■■■■■□□□□□□□","2.385s ■■■■■■■■■■■■■□□□","2.871s ■■■■■■■■■■■■■■■■","3.8.10","5.3.3","benchmarks/primes.cpp","benchmarks/primes.lua","benchmarks/primes.py","c++","cpython","file","gnu++11","lua","name","pkpy","These are the results of the primes benchmark on Intel i5-12400F, WSL (Ubuntu 20.04 LTS).","time","version"]},{"i":"primes-benchmarks-code-1","c":["$ time lua benchmarks/primes.lua \n\nreal 0m1.576s\nuser 0m1.514s\nsys 0m0.060s\n$ time ./main benchmarks/primes.py \n\nreal 0m2.385s\nuser 0m2.247s\nsys 0m0.100s\n$ time python benchmarks/primes.py \n\nreal 0m2.871s\nuser 0m2.798s\nsys 0m0.060s"]}],[{"l":"License","p":["pkpy is licensed under the MIT License."]},{"i":"license-code-1","c":["MIT License\n\nCopyright (c) 2026 blueloveTH\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE."]}]]
|