blueloveTH 1 年之前
父節點
當前提交
f7b0abff5a
共有 7 個文件被更改,包括 2 次插入622 次删除
  1. 0 185
      docs/unity/bindings.md
  2. 0 32
      docs/unity/console.md
  3. 0 166
      docs/unity/examples.md
  4. 0 3
      docs/unity/index.yml
  5. 0 82
      docs/unity/introduction.md
  6. 0 153
      docs/unity/vm.md
  7. 2 1
      scripts/build_references.py

+ 0 - 185
docs/unity/bindings.md

@@ -1,185 +0,0 @@
----
-label: Bindings
-icon: dot
-order: 10
----
-
-Bindings are methods and variables that are defined in C# and can be accessed from Python.
-We provide two types of bindings: static bindings and dynamic bindings.
-
-## Static Bindings
-
-Static bindings wrap a C# class or struct and expose its methods and variables to Python.
-This is the most common way to define bindings.
-Static bindings are initialized at compile time.
-
-### Manual Static Bindings
-
-Manual static bindings directly create a Python equivalent of `def f(a, b, *args)` in C#.
-To use it, you need to create a class that inherits from `PyTypeObject`.
-And implement some abstract methods to specify the name and type of the Python type.
-For example, to make `UnityEngine.Vector2` available in Python, you can write a `PyVector2Type`
-class like the following.
-
-```csharp
-public class PyVector2Type: PyTypeObject{
-    // The name of the type in Python
-    public override string Name => "Vector2";
-
-    // The corresponding C# type
-    public override System.Type CSType => typeof(Vector2);
-}
-```
-
-Next, you need to define each method and variable to be exposed to Python,
-by using `[PythonBinding]` attribute.
-
-!!!
-We assume that you have necessary knowledge about
-[Python's data model](https://docs.python.org/3/reference/datamodel.html).
-Such as magic methods, `__new__`, `__init__`, `__add__` and so on.
-Otherwise, you may have trouble understanding the following code.
-!!!
-
-Let's define a magic method `__add__`, it is used to implement the `+` operator in Python.
-With `__add__`, `Vector2` object in Python can be added with another `Vector2` object.
-
-```csharp
-public class PyVector2Type: PyTypeObject{
-    public override string Name => "Vector2";
-    public override System.Type CSType => typeof(Vector2);
-
-    [PythonBinding]
-    public object __add__(Vector2 self, object other){
-        // If the other object is not a Vector2, return NotImplemented
-        if(!(other is Vector2)) return VM.NotImplemented;
-        // Otherwise, return the result of addition
-        return self + (Vector2)other;
-    }
-}
-```
-
-This is easy to understand.
-Let's see another example, `__mul__`, it is used to implement the `*` operator in Python.
-`Vector2` object in C# can be multiplied with a `float` object in Python.
-The following code shows this usage.
-
-```csharp
-Vector2 a = new Vector2(1, 2);
-Vector2 b = a * 2.0f;
-Vector2 c = 2.0f * a;
-```
-
-As you can see, things are slightly different from `__add__`.
-Because the `float` operand can be on the left or right side of the `*` operator.
-In this case, you need to define `__mul__` and `__rmul__` at the same time.
-
-```csharp
-public class PyVector2Type: PyTypeObject{
-    public override string Name => "Vector2";
-    public override System.Type CSType => typeof(Vector2);
-
-    // ...
-
-    [PythonBinding]
-    public object __mul__(Vector2 self, object other){
-        if(!(other is float)) return VM.NotImplemented;
-        return self * (float)other;
-    }
-
-    [PythonBinding]
-    public object __rmul__(Vector2 self, object other){
-        if(!(other is float)) return VM.NotImplemented;
-        return self * (float)other;
-    }
-}
-```
-
-Finally, let's implement the constructor of `Vector2`.
-`__new__` magic method must be defined.
-
-```csharp
-public class PyVector2Type: PyTypeObject{
-    public override string Name => "Vector2";
-    public override System.Type CSType => typeof(Vector2);
-
-    [PythonBinding]
-    public object __new__(PyTypeObject cls, params object[] args){
-        if(args.Length == 0) return new Vector2();
-        if(args.Length == 2){
-            float x = vm.PyCast<float>(args[0]);
-            float y = vm.PyCast<float>(args[1]);
-            return new Vector2(x, y);
-        }
-        vm.TypeError("Vector2.__new__ takes 0 or 2 arguments");
-        return null;
-    }
-}
-```
-
-Here we use `params object[] args` to tell the bindings that the constructor can take any number of arguments.
-It is equivalent to `def __new__(cls, *args)` in Python.
-Note that Python does not support method overloading.
-So we manually check the number of arguments and their types to determine which constructor to call.
-
-For fields, we can form a Python property by defining a getter and a setter.
-By using `[PythonBinding(BindingType.Getter)]` and `[PythonBinding(BindingType.Setter)]` attributes.
-
-!!!
-However, this has certain limitations for value types. Because `Vector2` is a struct, it is passed by value.
-So our setter will not be able to modify the original `Vector2` object.
-!!!
-
-```csharp
-public class PyVector2Type: PyTypeObject{
-    public override string Name => "Vector2";
-    public override System.Type CSType => typeof(Vector2);
-
-    [PythonBinding(BindingType.Getter)]
-    public object x(Vector2 self) => self.x;
-
-    [PythonBinding(BindingType.Setter)]
-    public void x(Vector2 self, object value) => self.x = vm.PyCast<float>(value);
-
-    [PythonBinding(BindingType.Getter)]
-    public object y(Vector2 self) => self.y;
-
-    [PythonBinding(BindingType.Setter)]
-    public void y(Vector2 self, object value) => self.y = vm.PyCast<float>(value);
-}
-```
-
-Once you have done all the above, you must register the type to the VM.
-Here we set it into `builtins` module, so that it can be accessed from anywhere.
-
-```csharp
-vm.RegisterType(new PyVector2Type(), vm.builtins);
-```
-
-To summarize, manual static bindings provide detailed control for exposing a C# class to Python.
-You decide which methods and variables to expose, and how to expose them.
-This is our recommended way to define bindings. Also it is the most performant way.
-
-### Automatic Static Bindings
-
-Automatic static bindings use C# reflection to automatically generate bindings for a C# class.
-It is convenient for testing and prototyping, but it is slow and unsafe since the user can access any member of the class.
-
-```csharp
-vm.RegisterAutoType<Vector2>(vm.builtins);
-```
-
-That's all you need to do. The `RegisterAutoType<T>` method will automatically generate bindings for `Vector2`.
-
-
-## Dynamic Bindings
-
-Dynamic bindings allow you to add a single C# lambda function to an object at runtime.
-
-```csharp
-delegate object NativeFuncC(VM vm, object[] args);
-```
-
-+ `CSharpLambda BindFunc(PyObject obj, string name, int argc, NativeFuncC f)`
-
-It is similar to `bind_func` in [C++ API](../bindings/).

+ 0 - 32
docs/unity/console.md

@@ -1,32 +0,0 @@
----
-label: Python console
-icon: dot
-order: 5
----
-
-You can open the Python console in Unity by clicking the `Window/Python Console` menu item.
-
-By default, the console creates a unmodified `VM` instance to execute your code.
-You may want to provide an enhanced `VM` instance for the console in Unity Editor.
-For example, adding some class bindings in `UnityEngine` namespace.
-
-To do this, you need to create a class derived from `VM` and put it in `Assets/Editor/` folder.
-By adding `[EditorVM]` attribute to the class,
-the console will use it instead of the default `VM` instance.
-
-
-```csharp
-using UnityEngine;
-using PocketPython;
-
-[EditorVM]      // this attribute is required
-public class EnhancedVM: VM{
-    public EnhancedVM() {
-        RegisterAutoType<GameObject>(builtins);
-        RegisterAutoType<Transform>(builtins);
-        RegisterAutoType<Vector2>(builtins);
-        RegisterAutoType<Vector3>(builtins);
-        // ...
-    }
-}
-```

+ 0 - 166
docs/unity/examples.md

@@ -1,166 +0,0 @@
----
-label: Examples
-icon: dot
-order: 4
----
-
-See `Assets/PocketPython/Examples` after you import the plugin.
-
-
-### Primes Example
-
-```csharp
-using UnityEngine;
-
-namespace PocketPython
-{
-
-    /// <summary>
-    /// Example of using PocketPython to find prime numbers.
-    /// </summary>
-    public class PrimesExample : MonoBehaviour
-    {
-        // Start is called before the first frame update
-        void Start()
-        {
-            var vm = new VM();
-            const string source = @"
-def is_prime(x):
-  if x < 2:
-    return False
-  for i in range(2, x):
-    if x % i == 0:
-      return False
-  return True
-
-primes = [i for i in range(2, 20) if is_prime(i)]
-print(primes)
-";
-            CodeObject code = vm.Compile(source, "main.py", CompileMode.EXEC_MODE);
-            vm.Exec(code);  // [2, 3, 5, 7, 11, 13, 17, 19]
-        }
-    }
-
-}
-```
-
-
-
-### Vector2 Example
-
-```csharp
-using UnityEngine;
-
-namespace PocketPython
-{
-
-    /// <summary>
-    /// Example of making UnityEngine.Vector2 available to Python.
-    /// </summary>
-    public class Vector2Example : MonoBehaviour
-    {
-        // Start is called before the first frame update
-        void Start()
-        {
-            var vm = new VM();
-            // register UnityEngine.Vector2 type into the builtins module
-            vm.RegisterAutoType<Vector2>(vm.builtins);
-
-            vm.Exec("print(Vector2)", "main.py"); // <class 'Vector2'>
-            vm.Exec("v = Vector2(1, 2)", "main.py");
-            vm.Exec("print(v)", "main.py"); // (1.0, 2.0)
-            vm.Exec("print(v.x)", "main.py"); // 1.0
-            vm.Exec("print(v.y)", "main.py"); // 2.0
-            vm.Exec("print(v.magnitude)", "main.py"); // 2.236068
-            vm.Exec("print(v.normalized)", "main.py"); // (0.4472136, 0.8944272)
-            vm.Exec("print(Vector2.Dot(v, v))", "main.py"); // 5.0
-            vm.Exec("print(Vector2.get_up())", "main.py"); // (0.0, 1.0)
-
-            Vector2 v = (Vector2)vm.Eval("Vector2(3, 4) + v");
-            Debug.Log(v); // (4.0, 6.0)
-        }
-    }
-
-}
-```
-
-
-
-### MyClass Example
-
-```csharp
-using UnityEngine;
-using System;
-
-namespace PocketPython
-{
-
-    public class MyClass
-    {
-        public string title;
-        public string msg;
-
-        public void Print()
-        {
-            Debug.Log(title + ": " + msg);
-        }
-    }
-
-    public class PyMyclassType : PyTypeObject
-    {
-        public override string Name => "my_class";
-        public override Type CSType => typeof(MyClass);
-
-        [PythonBinding]
-        public object __new__(PyTypeObject cls)
-        {
-            return new MyClass();
-        }
-
-        [PythonBinding(BindingType.Getter)]
-        public string title(MyClass value) => value.title;
-
-        [PythonBinding(BindingType.Getter)]
-        public string msg(MyClass value) => value.msg;
-
-        [PythonBinding(BindingType.Setter)]
-        public void title(MyClass value, string title) => value.title = title;
-
-        [PythonBinding(BindingType.Setter)]
-        public void msg(MyClass value, string msg) => value.msg = msg;
-
-        [PythonBinding]
-        public void print(MyClass value) => value.Print();
-    }
-
-
-    /// <summary>
-    /// Example of binding a custom C# class to Python.
-    /// </summary>
-    public class MyClassExample : MonoBehaviour
-    {
-        // Start is called before the first frame update
-        void Start()
-        {
-            var vm = new VM();
-
-            // register MyClass type into the builtins module
-            vm.RegisterType(new PyMyclassType(), vm.builtins);
-
-            vm.Exec("print(my_class)", "main.py"); // <class 'my_class'>
-            vm.Exec("c = my_class()", "main.py");
-            vm.Exec("c.title = 'Greeting'", "main.py");
-            vm.Exec("c.msg = 'Hello, world!'", "main.py");
-
-            string title = vm.Eval("c.title").ToString();
-            string msg = vm.Eval("c.msg").ToString();
-
-            Debug.Log(title + ": " + msg); // Greeting: Hello, world!
-
-            vm.Exec("c.print()", "main.py"); // Greeting: Hello, world!
-        }
-    }
-
-}
-```
-

+ 0 - 3
docs/unity/index.yml

@@ -1,3 +0,0 @@
-label: Unity Plugin
-icon: code
-order: 0

+ 0 - 82
docs/unity/introduction.md

@@ -1,82 +0,0 @@
----
-label: Introduction
-icon: dot
-order: 30
----
-
-# Welcome to PocketPython
-
-PocketPython is a C# plugin that allows you to do Python scripting in Unity. It provides a sandboxed Python environment, which adds dynamic capabilities to your game, which can be used for dynamic game logic, modding, hot fixing, and more.
-
-The virtual machine is written in pure C#, which means you can fully control the internal state of the Python interpreter.
-
-!!!
-PocketPython is designed for game scripting, not for scientific computing.
-You cannot use it to run NumPy, OpenCV, or any other CPython extension modules.
-!!!
-
-
-## Features
-
-### Python 3.x Syntax
-
-PocketPython uses [pocketpy](https://github.com/pocketpy/pocketpy)
-as frontend to parse and compile Python source code.
-It supports most of the Python 3.x syntax.
-
-The following table shows a feature comparison of PocketPython
-with respect to the original [pocketpy](https://github.com/pocketpy/pocketpy).
-The features marked with `YES` are supported, and the features marked with `NO` are not supported.
-
-| Name            | Example                         | Cpp | Unity |
-| --------------- | ------------------------------- | --------- | --- |
-| If Else         | `if..else..elif`                | YES       | YES |
-| Loop            | `for/while/break/continue`      | YES       | YES |
-| Function        | `def f(x,*args,y=1):`           | YES       | YES |
-| Subclass        | `class A(B):`                   | YES       | YES |
-| List            | `[1, 2, 'a']`                   | YES       | YES |
-| ListComp        | `[i for i in range(5)]`         | YES       | YES |
-| Slice           | `a[1:2], a[:2], a[1:]`          | YES       | YES |
-| Tuple           | `(1, 2, 'a')`                   | YES       | YES |
-| Dict            | `{'a': 1, 'b': 2}`              | YES       | YES |
-| F-String        | `f'value is {x}'`               | YES       | YES |
-| Unpacking       | `a, b = 1, 2`                   | YES       | YES |
-| Star Unpacking  | `a, *b = [1, 2, 3]`             | YES       | YES |
-| Exception       | `raise/try..catch`              | YES       | NO |
-| Dynamic Code    | `eval()/exec()`                 | YES       | YES |
-| Reflection      | `hasattr()/getattr()/setattr()` | YES       | YES |
-| Import          | `import/from..import`           | YES       | YES |
-| Context Block   | `with <expr> as <id>:`          | YES       | NO |
-| Type Annotation | `def  f(a:int, b:float=1)`      | YES       | YES |
-| Generator       | `yield i`                       | YES       | NO |
-| Decorator       | `@cache`                        | YES       | YES |
-
-### Sandboxed Python Environment
-
-PocketPython provides a sandboxed Python environment.
-All python code is executed in a C# virtual machine.
-The user cannot access the file system, network, or any other resources of the host machine.
-
-### Seamless Interop with C#
-
-PocketPython uses `object` in C# to represent dynamic typed Python objects.
-Most of the basic Python types correspond to a C# type,
-which means passing arguments between C# and Python is extremely easy and intuitive.
-
-| Python Type | C# Type |
-| ----------- | ------- |
-| `None`      | `NoneType` |
-| `object`    | `System.Object` |
-| `bool`      | `System.Boolean` |
-| `int`       | `System.Int32` |
-| `float`     | `System.Single` |
-| `str`       | `System.String` |
-| `tuple`     | `System.Object[]` |
-| `list`      | `System.Collections.Generic.List<object>` |
-| `dict`      | `System.Collections.Generic.Dictionary<PyDictKey, object>` |
-| ...         | ... |
-
-### Python Console in Editor
-
-PocketPython provides a Python console in Unity editor,
-which allows you to do quick debugging and testing.

+ 0 - 153
docs/unity/vm.md

@@ -1,153 +0,0 @@
----
-label: Virtual machine
-icon: dot
-order: 20
----
-
-The `VM` class provides a sandboxed Python environment and a set of APIs for interacting with it.
-Using the namespace `PocketPython` before any operations.
-
-```csharp
-using PocketPython;
-```
-
-### Construction
-
-+ `VM()`
-
-    Create a new Python virtual machine.
-
-### Code Execution
-
-+ `CodeObject Compile(string source, string filename, CompileMode mode)`
-
-    Compile Python source code into a `CodeObject` that can be executed later.
-    The `filename` parameter is used for error reporting, you can set it to `main.py` if you don't need it.
-    The `mode` parameter specifies the compile mode, see [CompileMode](../quick-start/exec/#compile-mode) for details.
-
-+ `object Exec(CodeObject co, PyModule mod = null)`
-
-    Execute a `CodeObject` in the given module.
-    The `mod` parameter specifies the module in which the code will be executed.
-    If it is `null`, the code will be executed in the main module.
-
-+ `object Exec(string source, string filename, CompileMode mode = CompileMode.EXEC_MODE, PyModule mod = null)`
-
-    Compile and execute Python source code in the given module. It is equivalent to `Exec(Compile(source, filename, mode), mod)`.
-
-+ `object Eval(string source, PyModule mod = null)`
-
-    Evaluate an expression in the given module.
-
-+ `object Call(object callable, object[] args, Dictionary<string, object> kwargs)`
-
-    Call a Python callable object with the given arguments and keyword arguments. It is equivalent to `callable(*args, **kwargs)` in Python.
-
-+ `object CallMethod(object obj, string name, params object[] args)`
-
-    Call a method of a Python object with the given arguments. It is equivalent to `obj.name(*args)` in Python.
-
-
-### Attribute Access
-
-+ `object GetAttr(object obj, string name, bool throwErr = true)`
-
-    Get an attribute of a Python object. It is equivalent to `obj.name` in Python.
-    If `throwErr` is `true`, it will throw an exception if the attribute does not exist.
-    Otherwise, it will return `null`.
-
-+ `NoneType SetAttr(object obj, string name, object value)`
-
-    Set an attribute of a Python object. It is equivalent to `obj.name = value` in Python.
-
-+ `bool HasAttr(object obj, string name)`
-
-    Check if a Python object has the given attribute. It is equivalent to `hasattr(obj, name)` in Python.
-
-### Module Access
-
-+ `Dictionary<string, PyModule> modules`
-
-    A dictionary that maps module names to `PyModule` objects.
-    You can use it to access the modules that have been imported.
-
-+ `Dictionary<string, string> lazyModules`
-
-    A dictionary stores all unimported modules. You can add Python source into this dictionary.
-    It will be initialized and moved to `modules` when it is first imported.
-
-+ `PyModule NewModule(string name)`
-
-    Create a new module with the given name at runtime. The module will be added to `modules` automatically.
-
-+ `PyModule PyImport(string name)`
-
-    Import a Python module. It is equivalent to `import name` in Python. It first checks if the module has been imported, if not, it will try to load the module from `lazyModules`.
-
-
-### Type Conversion
-
-+ `T PyCast<T>(object obj)`
-
-    Convert a Python object to a C# object. It is equivalent to `obj as T` in C#.
-    Raise `TypeError` if the conversion fails.
-
-+ `bool IsInstance(object obj, PyTypeObject type)`
-
-    Check if a Python object is an instance of the given type. It is equivalent to `isinstance(obj, type)` in Python.
-
-+ `void CheckType<T>(object t)`
-
-    Check if `t is T`. Raise `TypeError` if the check fails.
-
-+ `bool PyEquals(object lhs, object rhs)`
-
-    Check if two Python objects are equal. It is equivalent to `lhs == rhs` in Python. This is different from `==` or `object.ReferenceEquals` in C#. You should always use this method to compare Python objects.
-
-+ `object PyIter(object obj)`
-
-    Get an iterator of a Python object. It is equivalent to `iter(obj)` in Python.
-
-+ `object PyNext(object obj)`
-
-    Get the next element of a Python iterator. It is equivalent to `next(obj)` in Python.
-
-+ `bool PyBool(object obj)`
-
-    Convert a Python object to a boolean value. It is equivalent to `bool(obj)` in Python.
-
-+ `string PyStr(object obj)`
-
-    Convert a Python object to a string. It is equivalent to `str(obj)` in Python.
-
-+ `string PyRepr(object obj)`
-
-    Convert a Python object to a string representation. It is equivalent to `repr(obj)` in Python.
-
-+ `int PyHash(object obj)`
-
-    Get the hash value of a Python object. It is equivalent to `hash(obj)` in Python.
-
-+ `List<object> PyList(object obj)`
-
-    Convert an `Iterable` Python object to a list. It is equivalent to `list(obj)` in Python.
-
-### Callbacks
-
-+ `System.Action<string> stdout = Debug.Log`
-
-    A callback that will be called when the Python code invokes `print` function.
-    By default, it will print the message to Unity console.
-
-+ `System.Action<string> stderr = null`
-
-    A callback that will be called when the Python code emits an error message.
-    By default, an Exception will be raised.
-    You can set it to `Debug.LogError` for printing to the Unity Console.
-
-### Debug Flag
-
-+ `bool debug = false`
-
-    A flag that controls whether to print debug messages to Unity console.
-    You can set it to `true` to enable debug messages, or `false` to disable them.

+ 2 - 1
scripts/build_references.py

@@ -28,7 +28,8 @@ for line in lines:
             output.append('```cpp\n')
 
 with open('docs/references.md', 'w', encoding='utf-8') as f:
-    f.write('''---label: References
+    f.write('''---
+label: References
 icon: code
 order: 2
 ---