mirror of
https://github.com/Relintai/gdnative_python.git
synced 2024-11-14 10:27:22 +01:00
Mass replace godot to pandemonium pt3.
This commit is contained in:
parent
9b4c18e994
commit
e8bff7346e
2
.github/workflows_off/build.yml
vendored
2
.github/workflows_off/build.yml
vendored
@ -149,7 +149,7 @@ jobs:
|
|||||||
else
|
else
|
||||||
curl https://downloads.fdossena.com/Projects/Mesa3D/Builds/MesaForWindows-20.0.7.7z -o mesa.7z
|
curl https://downloads.fdossena.com/Projects/Mesa3D/Builds/MesaForWindows-20.0.7.7z -o mesa.7z
|
||||||
fi
|
fi
|
||||||
# opengl32.dll must be extracted in the same directory than Godot binary
|
# opengl32.dll must be extracted in the same directory than Pandemonium binary
|
||||||
7z.exe x mesa.7z
|
7z.exe x mesa.7z
|
||||||
ls -lh opengl32.dll # Sanity check
|
ls -lh opengl32.dll # Sanity check
|
||||||
popd
|
popd
|
||||||
|
4
.gitignore
vendored
4
.gitignore
vendored
@ -14,11 +14,11 @@ pandemonium_headers/
|
|||||||
# mac os thumbs files
|
# mac os thumbs files
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|
||||||
# Godot import folders
|
# Pandemonium import folders
|
||||||
.import
|
.import
|
||||||
.cache
|
.cache
|
||||||
|
|
||||||
# Godot runtime logs
|
# Pandemonium runtime logs
|
||||||
logs
|
logs
|
||||||
|
|
||||||
# Scons build artefact
|
# Scons build artefact
|
||||||
|
12
README.rst
12
README.rst
@ -28,11 +28,11 @@ example:
|
|||||||
@exposed
|
@exposed
|
||||||
class Player(Node2D):
|
class Player(Node2D):
|
||||||
"""
|
"""
|
||||||
This is the file's main class which will be made available to Godot. This
|
This is the file's main class which will be made available to Pandemonium. This
|
||||||
class must inherit from `godot.Node` or any of its children (e.g.
|
class must inherit from `godot.Node` or any of its children (e.g.
|
||||||
`godot.KinematicBody`).
|
`godot.KinematicBody`).
|
||||||
|
|
||||||
Because Godot scripts only accept file paths, you can't have two `exposed` classes in the same file.
|
Because Pandemonium scripts only accept file paths, you can't have two `exposed` classes in the same file.
|
||||||
"""
|
"""
|
||||||
# Exposed class can define some attributes as export(<type>) to achieve
|
# Exposed class can define some attributes as export(<type>) to achieve
|
||||||
# similar goal than GDSscript's `export` keyword
|
# similar goal than GDSscript's `export` keyword
|
||||||
@ -48,12 +48,12 @@ example:
|
|||||||
def age(self, value):
|
def age(self, value):
|
||||||
self._age = value
|
self._age = value
|
||||||
|
|
||||||
# All methods are exposed to Godot
|
# All methods are exposed to Pandemonium
|
||||||
def talk(self, msg):
|
def talk(self, msg):
|
||||||
print(f"I'm saying {msg}")
|
print(f"I'm saying {msg}")
|
||||||
|
|
||||||
def _ready(self):
|
def _ready(self):
|
||||||
# Don't confuse `__init__` with Godot's `_ready`!
|
# Don't confuse `__init__` with Pandemonium's `_ready`!
|
||||||
self.weapon = WEAPON_RES.instance()
|
self.weapon = WEAPON_RES.instance()
|
||||||
self._age = 42
|
self._age = 42
|
||||||
# Of course you can access property & methods defined in the parent
|
# Of course you can access property & methods defined in the parent
|
||||||
@ -80,10 +80,10 @@ Building
|
|||||||
To build the project from source, first checkout the repo or download the
|
To build the project from source, first checkout the repo or download the
|
||||||
latest tarball.
|
latest tarball.
|
||||||
|
|
||||||
Godot-Python requires Python >= 3.7 and a C compiler.
|
GDNative Python requires Python >= 3.7 and a C compiler.
|
||||||
|
|
||||||
|
|
||||||
Godot GDNative header
|
Pandemonium GDNative header
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
TODO (need to be copied from the gdnative module)
|
TODO (need to be copied from the gdnative module)
|
||||||
|
@ -21,7 +21,7 @@ def pandemonium_binary_converter(val, env):
|
|||||||
file = File(val)
|
file = File(val)
|
||||||
if file.exists():
|
if file.exists():
|
||||||
# Note here `env["pandemonium_binary_download_version"]` is not defined, this is ok given
|
# Note here `env["pandemonium_binary_download_version"]` is not defined, this is ok given
|
||||||
# this variable shouldn't be needed if Godot doesn't have to be downloaded
|
# this variable shouldn't be needed if Pandemonium doesn't have to be downloaded
|
||||||
return file
|
return file
|
||||||
# Provided value is version information with format <major>.<minor>.<patch>[-<extra>]
|
# Provided value is version information with format <major>.<minor>.<patch>[-<extra>]
|
||||||
match = re.match(r"^([0-9]+)\.([0-9]+)\.([0-9]+)(?:-(\w+))?$", val)
|
match = re.match(r"^([0-9]+)\.([0-9]+)\.([0-9]+)(?:-(\w+))?$", val)
|
||||||
@ -29,7 +29,7 @@ def pandemonium_binary_converter(val, env):
|
|||||||
major, minor, patch, extra = match.groups()
|
major, minor, patch, extra = match.groups()
|
||||||
else:
|
else:
|
||||||
raise UserError(
|
raise UserError(
|
||||||
f"`{val}` is neither an existing file nor a valid <major>.<minor>.<patch>[-<extra>] Godot version format"
|
f"`{val}` is neither an existing file nor a valid <major>.<minor>.<patch>[-<extra>] Pandemonium version format"
|
||||||
)
|
)
|
||||||
env["pandemonium_binary_download_version"] = (major, minor, patch, extra or "stable")
|
env["pandemonium_binary_download_version"] = (major, minor, patch, extra or "stable")
|
||||||
# `pandemonium_binary` is set to None to indicate it should be downloaded
|
# `pandemonium_binary` is set to None to indicate it should be downloaded
|
||||||
@ -52,11 +52,11 @@ vars.Add(
|
|||||||
vars.Add("release_suffix", "Suffix to add to the release archive", extract_version())
|
vars.Add("release_suffix", "Suffix to add to the release archive", extract_version())
|
||||||
vars.Add(
|
vars.Add(
|
||||||
"pandemonium_binary",
|
"pandemonium_binary",
|
||||||
"Path to Godot binary or version of Godot to use",
|
"Path to Pandemonium binary or version of Pandemonium to use",
|
||||||
default="3.2.2",
|
default="3.2.2",
|
||||||
converter=pandemonium_binary_converter,
|
converter=pandemonium_binary_converter,
|
||||||
)
|
)
|
||||||
vars.Add("pandemonium_headers", "Path to Godot GDnative headers", "")
|
vars.Add("pandemonium_headers", "Path to Pandemonium GDnative headers", "")
|
||||||
vars.Add("debugger", "Run test with a debugger", "")
|
vars.Add("debugger", "Run test with a debugger", "")
|
||||||
vars.Add(BoolVariable("debug", "Compile with debug symbols", False))
|
vars.Add(BoolVariable("debug", "Compile with debug symbols", False))
|
||||||
vars.Add(BoolVariable("headless", "Run tests in headless mode", False))
|
vars.Add(BoolVariable("headless", "Run tests in headless mode", False))
|
||||||
|
@ -5,7 +5,7 @@ from collections import deque
|
|||||||
from threading import Thread, Lock, Event
|
from threading import Thread, Lock, Event
|
||||||
from queue import SimpleQueue
|
from queue import SimpleQueue
|
||||||
|
|
||||||
from _pandemonium import StdoutStderrCaptureToGodot, StdinCapture
|
from _pandemonium import StdoutStderrCaptureToPandemonium, StdinCapture
|
||||||
from pandemonium import exposed, export, ResourceLoader, VBoxContainer
|
from pandemonium import exposed, export, ResourceLoader, VBoxContainer
|
||||||
|
|
||||||
from .plugin import BASE_RES
|
from .plugin import BASE_RES
|
||||||
@ -14,7 +14,7 @@ from .plugin import BASE_RES
|
|||||||
FONT = ResourceLoader.load(f"{BASE_RES}/hack_regular.tres")
|
FONT = ResourceLoader.load(f"{BASE_RES}/hack_regular.tres")
|
||||||
|
|
||||||
|
|
||||||
class StdoutStderrCaptureToBufferAndPassthrough(StdoutStderrCaptureToGodot):
|
class StdoutStderrCaptureToBufferAndPassthrough(StdoutStderrCaptureToPandemonium):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self._buffer = ""
|
self._buffer = ""
|
||||||
|
@ -12,9 +12,9 @@ outside the interpretor) through numerous ways:
|
|||||||
- ...
|
- ...
|
||||||
|
|
||||||
However those functions are no longer relevant when python is embedded
|
However those functions are no longer relevant when python is embedded
|
||||||
into Godot. They can even be dangerous when opening a Godot application to
|
into Pandemonium. They can even be dangerous when opening a Pandemonium application to
|
||||||
modding given a 3rd party python code has suddently full access to the computer !
|
modding given a 3rd party python code has suddently full access to the computer !
|
||||||
|
|
||||||
Hence, those functions needs to be adapted to Godot:
|
Hence, those functions needs to be adapted to Pandemonium:
|
||||||
- ``ctype``, ``ffi`` and ``open`` disabled
|
- ``ctype``, ``ffi`` and ``open`` disabled
|
||||||
- ``stdout``, ``stderr`` and ``stdin`` redirected to Godot editor's console
|
- ``stdout``, ``stderr`` and ``stdin`` redirected to Pandemonium editor's console
|
||||||
|
@ -5,7 +5,7 @@ Object conversion model
|
|||||||
Base object types
|
Base object types
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
Godot Variant
|
Pandemonium Variant
|
||||||
- standalone: bool, int, real
|
- standalone: bool, int, real
|
||||||
- pointer to builtin type (e.g. ``Matrix32``, ``AABB``, etc.)
|
- pointer to builtin type (e.g. ``Matrix32``, ``AABB``, etc.)
|
||||||
- pointer to generic ``Object``
|
- pointer to generic ``Object``
|
||||||
@ -19,11 +19,11 @@ Python mp_obj_t
|
|||||||
needed on themselves.
|
needed on themselves.
|
||||||
|
|
||||||
Naming conventions:
|
Naming conventions:
|
||||||
- GST: Godot STandalone
|
- GST: Pandemonium STandalone
|
||||||
- GPB: Godot Pointer Builtin
|
- GPB: Pandemonium Pointer Builtin
|
||||||
- GPO: Godot Pointer Object
|
- GPO: Pandemonium Pointer Object
|
||||||
- PST: Python STandalone
|
- PST: Python STandalone
|
||||||
- PPB: Python Pointer Binding (proxy to Godot data)
|
- PPB: Python Pointer Binding (proxy to Pandemonium data)
|
||||||
- PPE: Python Pointer Exposed (defined with `@exposed` decorator)
|
- PPE: Python Pointer Exposed (defined with `@exposed` decorator)
|
||||||
- PPI: Python Pointer Internal
|
- PPI: Python Pointer Internal
|
||||||
|
|
||||||
@ -51,24 +51,24 @@ Standalone doesn't need garbage collection and doesn't hold reference on
|
|||||||
other objects. Hence conversion is trivial.
|
other objects. Hence conversion is trivial.
|
||||||
|
|
||||||
|
|
||||||
Conversion Godot -> Python
|
Conversion Pandemonium -> Python
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
Each GPB has a corresponding PPB, acting like a proxy from within the
|
Each GPB has a corresponding PPB, acting like a proxy from within the
|
||||||
Python interpreter.
|
Python interpreter.
|
||||||
|
|
||||||
GPO binding is done dynamically with the ``DynamicBinder`` using Godot
|
GPO binding is done dynamically with the ``DynamicBinder`` using Pandemonium
|
||||||
introspection (i.e. ``ObjectTypeDB``).
|
introspection (i.e. ``ObjectTypeDB``).
|
||||||
|
|
||||||
It is possible in the future that to create static proxy for core GPO and rely
|
It is possible in the future that to create static proxy for core GPO and rely
|
||||||
on dynamic method as a fall-back for unknown classes (i.g. added by 3rd party).
|
on dynamic method as a fall-back for unknown classes (i.g. added by 3rd party).
|
||||||
|
|
||||||
|
|
||||||
Conversion Python -> Godot
|
Conversion Python -> Pandemonium
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
PPB -> GPB described earlier.
|
PPB -> GPB described earlier.
|
||||||
|
|
||||||
PPI objects cannot be converted back to Godot.
|
PPI objects cannot be converted back to Pandemonium.
|
||||||
|
|
||||||
PPE instance are exposed as ``PyInstance`` (class exposed as ``PyScript``).
|
PPE instance are exposed as ``PyInstance`` (class exposed as ``PyScript``).
|
||||||
|
@ -9,7 +9,7 @@ from pandemonium.builtins cimport *
|
|||||||
from enum import IntFlag
|
from enum import IntFlag
|
||||||
|
|
||||||
|
|
||||||
__ERR_MSG_BINDING_NOT_AVAILABLE = "No Godot binding available"
|
__ERR_MSG_BINDING_NOT_AVAILABLE = "No Pandemonium binding available"
|
||||||
|
|
||||||
|
|
||||||
class Error(IntFlag):
|
class Error(IntFlag):
|
||||||
@ -138,11 +138,11 @@ class VariantOperator(IntFlag):
|
|||||||
|
|
||||||
### Class&singletons needed for Pythonscript bootstrap ###
|
### Class&singletons needed for Pythonscript bootstrap ###
|
||||||
|
|
||||||
# Godot classes&singletons are not all available when loading Pythonscript.
|
# Pandemonium classes&singletons are not all available when loading Pythonscript.
|
||||||
# Hence greedy loading is done only for items needed for Pythonscript
|
# Hence greedy loading is done only for items needed for Pythonscript
|
||||||
# bootstrap.
|
# bootstrap.
|
||||||
# The remaining loading will be achieved when loading the first python script
|
# The remaining loading will be achieved when loading the first python script
|
||||||
# (where at this point Godot should have finished it initialization).
|
# (where at this point Pandemonium should have finished it initialization).
|
||||||
|
|
||||||
{% set early_needed_bindings = ["_OS", "_ProjectSettings"] %}
|
{% set early_needed_bindings = ["_OS", "_ProjectSettings"] %}
|
||||||
cdef pandemonium_object *_ptr
|
cdef pandemonium_object *_ptr
|
||||||
|
@ -40,7 +40,7 @@ cdef class {{ cls.name }}({{ cls.base_class }}):
|
|||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
f"Use `new()` method to instantiate non-refcounted Godot object (and don't forget to free it !)"
|
f"Use `new()` method to instantiate non-refcounted Pandemonium object (and don't forget to free it !)"
|
||||||
)
|
)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
@ -101,7 +101,7 @@ cdef class {{ cls.name }}({{ cls.base_class }}):
|
|||||||
# return partial(self.call, gdname)
|
# return partial(self.call, gdname)
|
||||||
|
|
||||||
elif any(x for x in self.get_property_list() if x[gdnamefield] == gdname):
|
elif any(x for x in self.get_property_list() if x[gdnamefield] == gdname):
|
||||||
# TODO: Godot currently lacks a `has_property` method
|
# TODO: Pandemonium currently lacks a `has_property` method
|
||||||
return self.get(gdname)
|
return self.get(gdname)
|
||||||
|
|
||||||
raise AttributeError(
|
raise AttributeError(
|
||||||
@ -116,11 +116,11 @@ cdef class {{ cls.name }}({{ cls.base_class }}):
|
|||||||
PyObject_GenericSetAttr(self, name, value)
|
PyObject_GenericSetAttr(self, name, value)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Could retrieve the item inside the Godot class, try to look into
|
# Could retrieve the item inside the Pandemonium class, try to look into
|
||||||
# the attached script if it has one
|
# the attached script if it has one
|
||||||
else:
|
else:
|
||||||
if any(x for x in self.get_property_list() if x[gdnamefield] == gdname):
|
if any(x for x in self.get_property_list() if x[gdnamefield] == gdname):
|
||||||
# TODO: Godot currently lacks a `has_property` method
|
# TODO: Pandemonium currently lacks a `has_property` method
|
||||||
self.set(name, value)
|
self.set(name, value)
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -169,7 +169,7 @@ cdef class {{ cls.name }}({{ cls.base_class }}):
|
|||||||
{% if cls.name == "Reference" %}
|
{% if cls.name == "Reference" %}
|
||||||
@classmethod
|
@classmethod
|
||||||
def new(cls):
|
def new(cls):
|
||||||
raise RuntimeError(f"Refcounted Godot object must be created with `{ cls.__name__ }()`")
|
raise RuntimeError(f"Refcounted Pandemonium object must be created with `{ cls.__name__ }()`")
|
||||||
|
|
||||||
def __dealloc__(self):
|
def __dealloc__(self):
|
||||||
cdef pandemonium_bool __ret
|
cdef pandemonium_bool __ret
|
||||||
|
@ -108,7 +108,7 @@ with nogil:
|
|||||||
{% set retval_as_arg = "NULL" %}
|
{% set retval_as_arg = "NULL" %}
|
||||||
{% elif method.return_type.is_object %}
|
{% elif method.return_type.is_object %}
|
||||||
# It's important to initialize this pointer to null given
|
# It's important to initialize this pointer to null given
|
||||||
# in case of Reference, Godot will try to decrease the
|
# in case of Reference, Pandemonium will try to decrease the
|
||||||
# refcount if the pointer is valid !
|
# refcount if the pointer is valid !
|
||||||
# (see https://github.com/pandemoniumengine/pandemonium/issues/35609)
|
# (see https://github.com/pandemoniumengine/pandemonium/issues/35609)
|
||||||
cdef pandemonium_object *{{ retval }} = NULL
|
cdef pandemonium_object *{{ retval }} = NULL
|
||||||
|
@ -79,7 +79,7 @@ cdef class Dictionary:
|
|||||||
{{ force_mark_rendered("pandemonium_dictionary_operator_index") }}
|
{{ force_mark_rendered("pandemonium_dictionary_operator_index") }}
|
||||||
cdef pandemonium_variant var_key
|
cdef pandemonium_variant var_key
|
||||||
if not pyobj_to_pandemonium_variant(key, &var_key):
|
if not pyobj_to_pandemonium_variant(key, &var_key):
|
||||||
raise TypeError(f"Cannot convert `{key!r}` to Godot Variant")
|
raise TypeError(f"Cannot convert `{key!r}` to Pandemonium Variant")
|
||||||
cdef pandemonium_variant *p_var_ret = gdapi10.pandemonium_dictionary_operator_index(&self._gd_data, &var_key)
|
cdef pandemonium_variant *p_var_ret = gdapi10.pandemonium_dictionary_operator_index(&self._gd_data, &var_key)
|
||||||
gdapi10.pandemonium_variant_destroy(&var_key)
|
gdapi10.pandemonium_variant_destroy(&var_key)
|
||||||
if p_var_ret == NULL:
|
if p_var_ret == NULL:
|
||||||
@ -93,7 +93,7 @@ cdef class Dictionary:
|
|||||||
{{ force_mark_rendered("pandemonium_dictionary_erase_with_return") }}
|
{{ force_mark_rendered("pandemonium_dictionary_erase_with_return") }}
|
||||||
cdef pandemonium_variant var_key
|
cdef pandemonium_variant var_key
|
||||||
if not pyobj_to_pandemonium_variant(key, &var_key):
|
if not pyobj_to_pandemonium_variant(key, &var_key):
|
||||||
raise TypeError(f"Cannot convert `{key!r}` to Godot Variant")
|
raise TypeError(f"Cannot convert `{key!r}` to Pandemonium Variant")
|
||||||
cdef pandemonium_bool ret = gdapi11.pandemonium_dictionary_erase_with_return(&self._gd_data, &var_key)
|
cdef pandemonium_bool ret = gdapi11.pandemonium_dictionary_erase_with_return(&self._gd_data, &var_key)
|
||||||
gdapi10.pandemonium_variant_destroy(&var_key)
|
gdapi10.pandemonium_variant_destroy(&var_key)
|
||||||
if not ret:
|
if not ret:
|
||||||
|
@ -8,7 +8,7 @@ from libc.stdint cimport int8_t
|
|||||||
{{ force_mark_rendered("pandemonium_char_string_destroy") }}
|
{{ force_mark_rendered("pandemonium_char_string_destroy") }}
|
||||||
{{ force_mark_rendered("pandemonium_char_string_get_data") }}
|
{{ force_mark_rendered("pandemonium_char_string_get_data") }}
|
||||||
{{ force_mark_rendered("pandemonium_char_string_length") }}
|
{{ force_mark_rendered("pandemonium_char_string_length") }}
|
||||||
{# Those methods are present in gdnative_api.json but not in the Godot documentation... #}
|
{# Those methods are present in gdnative_api.json but not in the Pandemonium documentation... #}
|
||||||
{{ force_mark_rendered("pandemonium_string_ascii") }}
|
{{ force_mark_rendered("pandemonium_string_ascii") }}
|
||||||
{{ force_mark_rendered("pandemonium_string_ascii_extended") }}
|
{{ force_mark_rendered("pandemonium_string_ascii_extended") }}
|
||||||
{{ force_mark_rendered("pandemonium_string_begins_with_char_array") }}
|
{{ force_mark_rendered("pandemonium_string_begins_with_char_array") }}
|
||||||
|
@ -27,7 +27,7 @@ def {{ py_name or spec.py_name }}({{ spec.klass.cy_type }} self{%- if args_witho
|
|||||||
gdapi10.pandemonium_variant_destroy(&__var_{{ initialized_arg.name }})
|
gdapi10.pandemonium_variant_destroy(&__var_{{ initialized_arg.name }})
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
raise TypeError(f"Cannot convert `{ {{ arg.name}} !r}` to Godot Variant")
|
raise TypeError(f"Cannot convert `{ {{ arg.name}} !r}` to Pandemonium Variant")
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% if spec.return_type.is_variant %}
|
{% if spec.return_type.is_variant %}
|
||||||
|
@ -592,7 +592,7 @@ if __name__ == "__main__":
|
|||||||
required=True,
|
required=True,
|
||||||
metavar="API_PATH",
|
metavar="API_PATH",
|
||||||
type=argparse.FileType("r", encoding="utf8"),
|
type=argparse.FileType("r", encoding="utf8"),
|
||||||
help="Path to Godot api.json file",
|
help="Path to Pandemonium api.json file",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--output",
|
"--output",
|
||||||
|
@ -380,7 +380,7 @@ if __name__ == "__main__":
|
|||||||
required=True,
|
required=True,
|
||||||
metavar="GDNATIVE_API_PATH",
|
metavar="GDNATIVE_API_PATH",
|
||||||
type=argparse.FileType("r", encoding="utf8"),
|
type=argparse.FileType("r", encoding="utf8"),
|
||||||
help="Path to Godot gdnative_api.json file",
|
help="Path to Pandemonium gdnative_api.json file",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--output",
|
"--output",
|
||||||
|
@ -1,23 +1,23 @@
|
|||||||
# Describe all base types (i.e. scalar such as int and Godot builtins)
|
# Describe all base types (i.e. scalar such as int and Pandemonium builtins)
|
||||||
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class TypeSpec:
|
class TypeSpec:
|
||||||
# Type used within Godot api.json
|
# Type used within Pandemonium api.json
|
||||||
gdapi_type: str
|
gdapi_type: str
|
||||||
# Type used when calling C api functions
|
# Type used when calling C api functions
|
||||||
c_type: str
|
c_type: str
|
||||||
# Type used in Cython, basically similar to c_type for scalars&enums
|
# Type used in Cython, basically similar to c_type for scalars&enums
|
||||||
# and to py_type for Godot objects&builtins
|
# and to py_type for Pandemonium objects&builtins
|
||||||
cy_type: str
|
cy_type: str
|
||||||
# TODO: typing should be divided between argument and return (e.g. `Union[str, NodePath]` vs `NodePath`)
|
# TODO: typing should be divided between argument and return (e.g. `Union[str, NodePath]` vs `NodePath`)
|
||||||
# Type used for PEP 484 Python typing
|
# Type used for PEP 484 Python typing
|
||||||
py_type: str = ""
|
py_type: str = ""
|
||||||
# Type is a Godot object (i.e. defined in api.json)
|
# Type is a Pandemonium object (i.e. defined in api.json)
|
||||||
is_object: bool = False
|
is_object: bool = False
|
||||||
# Type is a Godot builtin (e.g. Vector2)
|
# Type is a Pandemonium builtin (e.g. Vector2)
|
||||||
is_builtin: bool = False
|
is_builtin: bool = False
|
||||||
# Type is a scalar (e.g. int, float) or void
|
# Type is a scalar (e.g. int, float) or void
|
||||||
is_base_type: bool = False
|
is_base_type: bool = False
|
||||||
|
@ -2,7 +2,9 @@
|
|||||||
| Godot Python |
|
| Godot Python |
|
||||||
+---------------------------------------------------------------------------+
|
+---------------------------------------------------------------------------+
|
||||||
|
|
||||||
Copyright (c) 2016 by Emmanuel Leblond.
|
Copyright (c) 2023-present Péter Magyar.
|
||||||
|
Copyright (c) 2016-2023 by Emmanuel Leblond.
|
||||||
|
|
||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
@ -23,11 +25,6 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|||||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
DEALINGS IN THE SOFTWARE.
|
DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
Godot Python Logo (C) Pinswell
|
|
||||||
Distributed under the terms of the Creative Commons Attribution License
|
|
||||||
version 3.0 (CC-BY 3.0)
|
|
||||||
https://creativecommons.org/licenses/by/3.0/legalcode.
|
|
||||||
|
|
||||||
|
|
||||||
+---------------------------------------------------------------------------+
|
+---------------------------------------------------------------------------+
|
||||||
| CPython |
|
| CPython |
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
Introduction
|
Introduction
|
||||||
------------
|
------------
|
||||||
|
|
||||||
This is a beta version of the Python module for Godot.
|
This is a beta version of the Python module for Pandemonium.
|
||||||
|
|
||||||
You are likely to encounter bugs and catastrophic crashes, if so please
|
You are likely to encounter bugs and catastrophic crashes, if so please
|
||||||
report them to https://github.com/Relintai/gdnative_python.
|
report them to https://github.com/Relintai/gdnative_python.
|
||||||
@ -19,7 +19,7 @@ report them to https://github.com/Relintai/gdnative_python.
|
|||||||
Working features
|
Working features
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
Every Godot core features are expected to work fine:
|
Every Pandemonium core features are expected to work fine:
|
||||||
- builtins (e.g. Vector2)
|
- builtins (e.g. Vector2)
|
||||||
- Objects classes (e.g. Node)
|
- Objects classes (e.g. Node)
|
||||||
- signals
|
- signals
|
||||||
|
@ -13,15 +13,15 @@ Import("env")
|
|||||||
def resolve_pandemonium_download_url(major, minor, patch, extra, platform):
|
def resolve_pandemonium_download_url(major, minor, patch, extra, platform):
|
||||||
#version = f"{major}.{minor}.{patch}" if patch != 0 else f"{major}.{minor}"
|
#version = f"{major}.{minor}.{patch}" if patch != 0 else f"{major}.{minor}"
|
||||||
#if extra == "stable":
|
#if extra == "stable":
|
||||||
# return f"https://downloads.tuxfamily.org/godotengine/{version}/Godot_v{version}-{extra}_{platform}.zip"
|
# return f"https://downloads.tuxfamily.org/godotengine/{version}/Pandemonium_v{version}-{extra}_{platform}.zip"
|
||||||
#else:
|
#else:
|
||||||
# return f"https://downloads.tuxfamily.org/godotengine/{version}/{extra}/Godot_v{version}-{extra}_{platform}.zip"
|
# return f"https://downloads.tuxfamily.org/godotengine/{version}/{extra}/Pandemonium_v{version}-{extra}_{platform}.zip"
|
||||||
returnf ""
|
returnf ""
|
||||||
|
|
||||||
|
|
||||||
def resolve_pandemonium_binary_name(major, minor, patch, extra, platform):
|
def resolve_pandemonium_binary_name(major, minor, patch, extra, platform):
|
||||||
version = f"{major}.{minor}.{patch}" if patch != 0 else f"{major}.{minor}"
|
version = f"{major}.{minor}.{patch}" if patch != 0 else f"{major}.{minor}"
|
||||||
return f"Godot_v{version}-{extra}_{platform}"
|
return f"Pandemonium_v{version}-{extra}_{platform}"
|
||||||
|
|
||||||
|
|
||||||
SConscript([f"{env['platform']}/SConscript"])
|
SConscript([f"{env['platform']}/SConscript"])
|
||||||
@ -74,7 +74,7 @@ env.AddMethod(install, "Install")
|
|||||||
env.AddMethod(install_as, "InstallAs")
|
env.AddMethod(install_as, "InstallAs")
|
||||||
|
|
||||||
|
|
||||||
### Godot binary (to run tests) ###
|
### Pandemonium binary (to run tests) ###
|
||||||
|
|
||||||
|
|
||||||
if not env["pandemonium_binary"]:
|
if not env["pandemonium_binary"]:
|
||||||
|
@ -14,7 +14,7 @@ cpython_build = Dir("cpython_build")
|
|||||||
|
|
||||||
env["bits"] = "64"
|
env["bits"] = "64"
|
||||||
env["pandemonium_binary_download_platform"] = "osx.64"
|
env["pandemonium_binary_download_platform"] = "osx.64"
|
||||||
env["pandemonium_binary_download_zip_path"] = "Godot.app/Contents/MacOS/Godot"
|
env["pandemonium_binary_download_zip_path"] = "Pandemonium.app/Contents/MacOS/Pandemonium"
|
||||||
env["cpython_build"] = cpython_build
|
env["cpython_build"] = cpython_build
|
||||||
env["cpython_build_dir"] = cpython_build
|
env["cpython_build_dir"] = cpython_build
|
||||||
env["DIST_SITE_PACKAGES"] = Dir(f"{env['DIST_PLATFORM']}/lib/python3.8/site-packages")
|
env["DIST_SITE_PACKAGES"] = Dir(f"{env['DIST_PLATFORM']}/lib/python3.8/site-packages")
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
# `_pandemoniummonium` module contains all the callbacks needed by Godot's Pluginscript
|
# `_pandemoniummonium` module contains all the callbacks needed by Pandemonium's Pluginscript
|
||||||
# system to expose Python as a language to Godot (see pythonscript.c for
|
# system to expose Python as a language to Pandemonium (see pythonscript.c for
|
||||||
# more on this).
|
# more on this).
|
||||||
# Hence there is no point of importing this module from Python given it
|
# Hence there is no point of importing this module from Python given it
|
||||||
# only expose C functions.
|
# only expose C functions.
|
||||||
@ -45,10 +45,10 @@ cdef api pandemonium_pluginscript_language_data *pythonscript_init() with gil:
|
|||||||
p = ProjectSettings.globalize_path(GDString(p))
|
p = ProjectSettings.globalize_path(GDString(p))
|
||||||
sys.path.insert(0, str(p))
|
sys.path.insert(0, str(p))
|
||||||
|
|
||||||
# Redirect stdout/stderr to have it in the Godot editor console
|
# Redirect stdout/stderr to have it in the Pandemonium editor console
|
||||||
if _setup_config_entry("python_script/io_streams_capture", True):
|
if _setup_config_entry("python_script/io_streams_capture", True):
|
||||||
# Note we don't have to remove the stream capture in `pythonscript_finish` given
|
# Note we don't have to remove the stream capture in `pythonscript_finish` given
|
||||||
# Godot print API is available until after the Python interpreter is teardown
|
# Pandemonium print API is available until after the Python interpreter is teardown
|
||||||
install_io_streams_capture()
|
install_io_streams_capture()
|
||||||
|
|
||||||
# Enable verbose output from pythonscript framework
|
# Enable verbose output from pythonscript framework
|
||||||
|
@ -149,7 +149,7 @@ cdef api void pythonscript_add_global_constant(
|
|||||||
const pandemonium_string *p_variable,
|
const pandemonium_string *p_variable,
|
||||||
const pandemonium_variant *p_value
|
const pandemonium_variant *p_value
|
||||||
) with gil:
|
) with gil:
|
||||||
# However, Godot add global constants very early (first as an empty variant
|
# However, Pandemonium add global constants very early (first as an empty variant
|
||||||
# placeholder before any script is loaded, then as a proper loaded script).
|
# placeholder before any script is loaded, then as a proper loaded script).
|
||||||
# So it's possible this function get called before `pythonscript_script_init`
|
# So it's possible this function get called before `pythonscript_script_init`
|
||||||
# (which is supposed to do the lazy `_initialize_bindings`).
|
# (which is supposed to do the lazy `_initialize_bindings`).
|
||||||
|
@ -51,7 +51,7 @@ cdef api pandemonium_bool pythonscript_instance_set_prop(
|
|||||||
cdef str key = pandemonium_string_to_pyobj(p_name)
|
cdef str key = pandemonium_string_to_pyobj(p_name)
|
||||||
|
|
||||||
# Should look among properties added by the script and it parents,
|
# Should look among properties added by the script and it parents,
|
||||||
# not Godot native properties that are handled by the caller
|
# not Pandemonium native properties that are handled by the caller
|
||||||
try:
|
try:
|
||||||
field = instance.__exported[key]
|
field = instance.__exported[key]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
@ -78,7 +78,7 @@ cdef api pandemonium_bool pythonscript_instance_get_prop(
|
|||||||
cdef str key = pandemonium_string_to_pyobj(p_name)
|
cdef str key = pandemonium_string_to_pyobj(p_name)
|
||||||
|
|
||||||
# Should look among properties added by the script and it parents,
|
# Should look among properties added by the script and it parents,
|
||||||
# not Godot native properties that are handled by the caller
|
# not Pandemonium native properties that are handled by the caller
|
||||||
try:
|
try:
|
||||||
field = instance.__exported[key]
|
field = instance.__exported[key]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
@ -155,7 +155,7 @@ cdef api void pythonscript_instance_notification(
|
|||||||
int p_notification
|
int p_notification
|
||||||
) with gil:
|
) with gil:
|
||||||
cdef object instance = <object>p_data
|
cdef object instance = <object>p_data
|
||||||
# Godot's notification should call all parent `_notification`
|
# Pandemonium's notification should call all parent `_notification`
|
||||||
# methods (better not use `super()._notification` in those methods...)
|
# methods (better not use `super()._notification` in those methods...)
|
||||||
# TODO: cache the methods to call ?
|
# TODO: cache the methods to call ?
|
||||||
for parentcls in instance.__class__.__mro__:
|
for parentcls in instance.__class__.__mro__:
|
||||||
|
@ -88,7 +88,7 @@ class StdoutStderrCapture(TextIOBase):
|
|||||||
self._enabled = False
|
self._enabled = False
|
||||||
|
|
||||||
|
|
||||||
class StdoutStderrCaptureToGodot(StdoutStderrCapture):
|
class StdoutStderrCaptureToPandemonium(StdoutStderrCapture):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.buffer = ""
|
self.buffer = ""
|
||||||
@ -125,5 +125,5 @@ cdef _capture_io_streams = None
|
|||||||
cdef install_io_streams_capture():
|
cdef install_io_streams_capture():
|
||||||
global _capture_io_streams
|
global _capture_io_streams
|
||||||
assert _capture_io_streams is None
|
assert _capture_io_streams is None
|
||||||
_capture_io_streams = StdoutStderrCaptureToGodot()
|
_capture_io_streams = StdoutStderrCaptureToPandemonium()
|
||||||
_capture_io_streams.install()
|
_capture_io_streams.install()
|
||||||
|
@ -115,7 +115,7 @@ cdef pandemonium_pluginscript_script_manifest _build_script_manifest(object cls)
|
|||||||
gdapi10.pandemonium_dictionary_new(&manifest.member_lines)
|
gdapi10.pandemonium_dictionary_new(&manifest.member_lines)
|
||||||
|
|
||||||
if cls.__bases__:
|
if cls.__bases__:
|
||||||
# Only one Godot parent class (checked at class definition time)
|
# Only one Pandemonium parent class (checked at class definition time)
|
||||||
pandemonium_parent_class = next(
|
pandemonium_parent_class = next(
|
||||||
(b for b in cls.__bases__ if issubclass(b, Object))
|
(b for b in cls.__bases__ if issubclass(b, Object))
|
||||||
)
|
)
|
||||||
@ -150,7 +150,7 @@ cdef api pandemonium_pluginscript_script_manifest pythonscript_script_init(
|
|||||||
const pandemonium_string *p_source,
|
const pandemonium_string *p_source,
|
||||||
pandemonium_error *r_error
|
pandemonium_error *r_error
|
||||||
) with gil:
|
) with gil:
|
||||||
# Godot class&singleton are not all available at Pythonscript bootstrap.
|
# Pandemonium class&singleton are not all available at Pythonscript bootstrap.
|
||||||
# Hence we wait until the Pythonscript start being actually used (i.e. until
|
# Hence we wait until the Pythonscript start being actually used (i.e. until
|
||||||
# the first Python script is loaded) before initializing the bindings.
|
# the first Python script is loaded) before initializing the bindings.
|
||||||
_initialize_bindings()
|
_initialize_bindings()
|
||||||
@ -182,7 +182,7 @@ cdef api pandemonium_pluginscript_script_manifest pythonscript_script_init(
|
|||||||
cls = get_exposed_class(modname)
|
cls = get_exposed_class(modname)
|
||||||
|
|
||||||
# If the module has no exported class, it has no real connection with
|
# If the module has no exported class, it has no real connection with
|
||||||
# Godot and doesn't need to be reloaded
|
# Pandemonium and doesn't need to be reloaded
|
||||||
if cls:
|
if cls:
|
||||||
if get_pythonscript_verbose():
|
if get_pythonscript_verbose():
|
||||||
print(f"Reloading python script from {path} ({modname})")
|
print(f"Reloading python script from {path} ({modname})")
|
||||||
@ -205,13 +205,13 @@ cdef api pandemonium_pluginscript_script_manifest pythonscript_script_init(
|
|||||||
|
|
||||||
if cls is None:
|
if cls is None:
|
||||||
print(
|
print(
|
||||||
f"Cannot load {path} ({modname}) because it doesn't expose any class to Godot"
|
f"Cannot load {path} ({modname}) because it doesn't expose any class to Pandemonium"
|
||||||
)
|
)
|
||||||
r_error[0] = GODOT_ERR_PARSE_ERROR
|
r_error[0] = GODOT_ERR_PARSE_ERROR
|
||||||
return _build_empty_script_manifest()
|
return _build_empty_script_manifest()
|
||||||
|
|
||||||
if is_reload:
|
if is_reload:
|
||||||
# During reloading, Godot calls the new class init before the old class finish (so
|
# During reloading, Pandemonium calls the new class init before the old class finish (so
|
||||||
# `pythonscript_script_finish` is going to be called after this function returns).
|
# `pythonscript_script_finish` is going to be called after this function returns).
|
||||||
# Hence we must manually increase the refcount to prevent finish to remove
|
# Hence we must manually increase the refcount to prevent finish to remove
|
||||||
# the class.
|
# the class.
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# Start with a sanity check to ensure the loading is done from Godot-Python
|
# Start with a sanity check to ensure the loading is done from Pandemonium-Python
|
||||||
# (and not from a regular Python interpreter which would lead to a segfault).
|
# (and not from a regular Python interpreter which would lead to a segfault).
|
||||||
# The idea is we should have the following loading order:
|
# The idea is we should have the following loading order:
|
||||||
# pandemonium binary -> pythonscript.so -> _pandemonium.so -> pandemonium/__init__.py
|
# pandemonium binary -> pythonscript.so -> _pandemonium.so -> pandemonium/__init__.py
|
||||||
@ -6,10 +6,10 @@ import sys
|
|||||||
|
|
||||||
if "_pandemonium" not in sys.modules:
|
if "_pandemonium" not in sys.modules:
|
||||||
raise ImportError(
|
raise ImportError(
|
||||||
"Cannot initialize pandemonium module given Godot GDNative API not available.\n"
|
"Cannot initialize pandemonium module given Pandemonium GDNative API not available.\n"
|
||||||
"This is most likely because you are running code from a regular Python interpreter"
|
"This is most likely because you are running code from a regular Python interpreter"
|
||||||
" (i.e. doing something like `python my_script.py`) while pandemonium module is only available"
|
" (i.e. doing something like `python my_script.py`) while pandemonium module is only available"
|
||||||
" to Python code loaded from Godot through Godot-Python plugin."
|
" to Python code loaded from Pandemonium through Pandemonium-Python plugin."
|
||||||
)
|
)
|
||||||
del sys
|
del sys
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ from pandemonium._hazmat.gdnative_api_struct cimport (
|
|||||||
from pandemonium.builtins cimport GDString, NodePath
|
from pandemonium.builtins cimport GDString, NodePath
|
||||||
|
|
||||||
|
|
||||||
# Godot string are basically a vector of wchar_t, each wchar_t representing
|
# Pandemonium string are basically a vector of wchar_t, each wchar_t representing
|
||||||
# a single unicode character (i.e. there is no surrogates support).
|
# a single unicode character (i.e. there is no surrogates support).
|
||||||
# The sad part is wchar_t is not portable: it is 16bits long on Windows and
|
# The sad part is wchar_t is not portable: it is 16bits long on Windows and
|
||||||
# 32bits long on Linux and MacOS...
|
# 32bits long on Linux and MacOS...
|
||||||
|
@ -92,7 +92,7 @@ cdef bint is_pytype_compatible_with_pandemonium_variant(object pytype):
|
|||||||
cdef object pandemonium_type_to_pytype(pandemonium_variant_type gdtype):
|
cdef object pandemonium_type_to_pytype(pandemonium_variant_type gdtype):
|
||||||
cdef pytype = next((py for gd, py in GD_PY_TYPES if gd == gdtype), None)
|
cdef pytype = next((py for gd, py in GD_PY_TYPES if gd == gdtype), None)
|
||||||
if pytype is None:
|
if pytype is None:
|
||||||
warn(f"No Python equivalent for Godot type `{gdtype}`")
|
warn(f"No Python equivalent for Pandemonium type `{gdtype}`")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return pytype
|
return pytype
|
||||||
@ -104,7 +104,7 @@ cdef pandemonium_variant_type pytype_to_pandemonium_type(object pytype):
|
|||||||
if issubclass(pytype, Object):
|
if issubclass(pytype, Object):
|
||||||
return pandemonium_variant_type.GODOT_VARIANT_TYPE_OBJECT
|
return pandemonium_variant_type.GODOT_VARIANT_TYPE_OBJECT
|
||||||
else:
|
else:
|
||||||
warn(f"No Godot equivalent for Python type `{pytype}`")
|
warn(f"No Pandemonium equivalent for Python type `{pytype}`")
|
||||||
return pandemonium_variant_type.GODOT_VARIANT_TYPE_NIL
|
return pandemonium_variant_type.GODOT_VARIANT_TYPE_NIL
|
||||||
|
|
||||||
return gdtype
|
return gdtype
|
||||||
@ -396,7 +396,7 @@ cdef bint pyobj_to_pandemonium_variant(object pyobj, pandemonium_variant *p_var)
|
|||||||
elif isinstance(pyobj, Object):
|
elif isinstance(pyobj, Object):
|
||||||
gdapi10.pandemonium_variant_new_object(p_var, (<Object>pyobj)._gd_ptr)
|
gdapi10.pandemonium_variant_new_object(p_var, (<Object>pyobj)._gd_ptr)
|
||||||
else:
|
else:
|
||||||
warn(f"Cannot convert `{type(pyobj)}` to Godot's Variant")
|
warn(f"Cannot convert `{type(pyobj)}` to Pandemonium's Variant")
|
||||||
gdapi10.pandemonium_variant_new_nil(p_var)
|
gdapi10.pandemonium_variant_new_nil(p_var)
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
@ -16,7 +16,7 @@ cdef class ModExposedClass:
|
|||||||
|
|
||||||
|
|
||||||
# /!\ Those containers are strictly private /!\
|
# /!\ Those containers are strictly private /!\
|
||||||
# They contain class objects that are referenced from Godot without refcounting,
|
# They contain class objects that are referenced from Pandemonium without refcounting,
|
||||||
# so droping an item from there will likely cause a segfault !
|
# so droping an item from there will likely cause a segfault !
|
||||||
cdef dict __modules_with_exposed_class = {}
|
cdef dict __modules_with_exposed_class = {}
|
||||||
cdef list __all_exposed_classes = []
|
cdef list __all_exposed_classes = []
|
||||||
@ -40,25 +40,25 @@ cdef void set_exposed_class(object cls):
|
|||||||
|
|
||||||
# We must keep track of reference counts for the module when reloading a script,
|
# We must keep track of reference counts for the module when reloading a script,
|
||||||
# pandemonium calls pythonscript_script_init BEFORE pythonscript_script_finish
|
# pandemonium calls pythonscript_script_init BEFORE pythonscript_script_finish
|
||||||
# this happens because Godot can make multiple PluginScript instances for the same resource.
|
# this happens because Pandemonium can make multiple PluginScript instances for the same resource.
|
||||||
|
|
||||||
# Godot calls
|
# Pandemonium calls
|
||||||
try:
|
try:
|
||||||
mod = __modules_with_exposed_class[modname]
|
mod = __modules_with_exposed_class[modname]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
__modules_with_exposed_class[modname] = ModExposedClass(cls)
|
__modules_with_exposed_class[modname] = ModExposedClass(cls)
|
||||||
else:
|
else:
|
||||||
# When reloading a script, Godot calls `pythonscript_script_init` BEFORE
|
# When reloading a script, Pandemonium calls `pythonscript_script_init` BEFORE
|
||||||
# `pythonscript_script_finish`. Hence we drop replace the old class
|
# `pythonscript_script_finish`. Hence we drop replace the old class
|
||||||
# here but have to increase the refcount so
|
# here but have to increase the refcount so
|
||||||
mod.kls = cls
|
mod.kls = cls
|
||||||
mod.refcount += 1
|
mod.refcount += 1
|
||||||
|
|
||||||
# Sometimes Godot fails to reload a script, and when this happens we end
|
# Sometimes Pandemonium fails to reload a script, and when this happens we end
|
||||||
# up with a stale PyObject* for the class, which is then garbage collected by Python
|
# up with a stale PyObject* for the class, which is then garbage collected by Python
|
||||||
# so next time a script is instantiated from Godot we end up with a sefault :(
|
# so next time a script is instantiated from Pandemonium we end up with a sefault :(
|
||||||
# To avoid this we keep reference forever to all the classes.
|
# To avoid this we keep reference forever to all the classes.
|
||||||
# TODO: This may be troublesome when running the Godot editor given the classes are
|
# TODO: This may be troublesome when running the Pandemonium editor given the classes are
|
||||||
# reloaded each time they are modified, hence leading to a small memory leak...
|
# reloaded each time they are modified, hence leading to a small memory leak...
|
||||||
__all_exposed_classes.append(cls)
|
__all_exposed_classes.append(cls)
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# Public low-level APIs are exposed here
|
# Public low-level APIs are exposed here
|
||||||
|
|
||||||
from pandemoniummonium._hazmat cimport gdnative_api_struct
|
from pandemoniummonium._hazmat cimport gdnative_api_struct
|
||||||
# Re-expose Godot API with better names
|
# Re-expose Pandemonium API with better names
|
||||||
from pandemoniummonium._hazmat.gdapi cimport (
|
from pandemoniummonium._hazmat.gdapi cimport (
|
||||||
pythonscript_gdapi10 as gdapi10,
|
pythonscript_gdapi10 as gdapi10,
|
||||||
pythonscript_gdapi11 as gdapi11,
|
pythonscript_gdapi11 as gdapi11,
|
||||||
|
@ -19,7 +19,7 @@ from pandemonium.builtins cimport Array, Dictionary, GDString
|
|||||||
from pandemonium.bindings cimport Object, Resource
|
from pandemonium.bindings cimport Object, Resource
|
||||||
|
|
||||||
|
|
||||||
# Make Godot enums accesible from Python at runtime
|
# Make Pandemonium enums accesible from Python at runtime
|
||||||
|
|
||||||
|
|
||||||
class MethodRPCMode(enum.IntEnum):
|
class MethodRPCMode(enum.IntEnum):
|
||||||
@ -162,14 +162,14 @@ class ExportedField:
|
|||||||
type = Dictionary if type == dict else type
|
type = Dictionary if type == dict else type
|
||||||
|
|
||||||
if not is_pytype_compatible_with_pandemonium_variant(type):
|
if not is_pytype_compatible_with_pandemonium_variant(type):
|
||||||
raise ValueError(f"{type!r} type value not compatible with Godot")
|
raise ValueError(f"{type!r} type value not compatible with Pandemonium")
|
||||||
|
|
||||||
cdef pandemonium_variant gd_default
|
cdef pandemonium_variant gd_default
|
||||||
if default is not None:
|
if default is not None:
|
||||||
# Convert `default` to a Godot-compatible value (e.g. str -> GDString)
|
# Convert `default` to a Pandemonium-compatible value (e.g. str -> GDString)
|
||||||
if not pyobj_to_pandemonium_variant(default, &gd_default):
|
if not pyobj_to_pandemonium_variant(default, &gd_default):
|
||||||
gdapi10.pandemonium_variant_destroy(&gd_default)
|
gdapi10.pandemonium_variant_destroy(&gd_default)
|
||||||
raise ValueError(f"{default!r} default value not compatible with Godot")
|
raise ValueError(f"{default!r} default value not compatible with Pandemonium")
|
||||||
default = pandemonium_variant_to_pyobj(&gd_default)
|
default = pandemonium_variant_to_pyobj(&gd_default)
|
||||||
gdapi10.pandemonium_variant_destroy(&gd_default)
|
gdapi10.pandemonium_variant_destroy(&gd_default)
|
||||||
|
|
||||||
@ -245,8 +245,8 @@ def export(
|
|||||||
rpc: MethodRPCMode=MethodRPCMode.DISABLED
|
rpc: MethodRPCMode=MethodRPCMode.DISABLED
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Decorator used to mark a class attribute as beeing exported to Godot
|
Decorator used to mark a class attribute as beeing exported to Pandemonium
|
||||||
(hence making it readable/writable from Godot)
|
(hence making it readable/writable from Pandemonium)
|
||||||
|
|
||||||
usage::
|
usage::
|
||||||
@exposed
|
@exposed
|
||||||
@ -276,9 +276,9 @@ def export(
|
|||||||
|
|
||||||
def exposed(cls=None, tool=False):
|
def exposed(cls=None, tool=False):
|
||||||
"""
|
"""
|
||||||
Decorator used to mark a class as beeing exposed to Godot (hence making
|
Decorator used to mark a class as beeing exposed to Pandemonium (hence making
|
||||||
it available from other Godot languages and the Godot IDE).
|
it available from other Pandemonium languages and the Pandemonium IDE).
|
||||||
Due to how Godot identifiest classes by their file pathes, only a single
|
Due to how Pandemonium identifiest classes by their file pathes, only a single
|
||||||
class can be marked with this decorator per file.
|
class can be marked with this decorator per file.
|
||||||
|
|
||||||
usage::
|
usage::
|
||||||
@ -290,7 +290,7 @@ def exposed(cls=None, tool=False):
|
|||||||
def wrapper(cls):
|
def wrapper(cls):
|
||||||
if not issubclass(cls, Object):
|
if not issubclass(cls, Object):
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
f"{cls!r} must inherit from a Godot (e.g. `pandemonium.bindings.Node`) "
|
f"{cls!r} must inherit from a Pandemonium (e.g. `pandemonium.bindings.Node`) "
|
||||||
"class to be marked as @exposed"
|
"class to be marked as @exposed"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -333,15 +333,15 @@ def exposed(cls=None, tool=False):
|
|||||||
elif callable(v):
|
elif callable(v):
|
||||||
cls.__exported[k] = v
|
cls.__exported[k] = v
|
||||||
|
|
||||||
# Overwrite parent __init__ to avoid creating a Godot object given
|
# Overwrite parent __init__ to avoid creating a Pandemonium object given
|
||||||
# exported script are always initialized with an existing Godot object
|
# exported script are always initialized with an existing Pandemonium object
|
||||||
# On top of that, we must initialize the attributes defined in the class
|
# On top of that, we must initialize the attributes defined in the class
|
||||||
# and it parents
|
# and it parents
|
||||||
g = {}
|
g = {}
|
||||||
exec(init_func_code, g)
|
exec(init_func_code, g)
|
||||||
cls.__init__ = g["__init__"]
|
cls.__init__ = g["__init__"]
|
||||||
# Also overwrite parent new otherwise we would return an instance
|
# Also overwrite parent new otherwise we would return an instance
|
||||||
# of a Godot class without our script attached to it...
|
# of a Pandemonium class without our script attached to it...
|
||||||
@classmethod
|
@classmethod
|
||||||
def new(cls):
|
def new(cls):
|
||||||
raise NotImplementedError("Instantiating Python script from Python is not implemented yet :'(")
|
raise NotImplementedError("Instantiating Python script from Python is not implemented yet :'(")
|
||||||
@ -350,7 +350,7 @@ def exposed(cls=None, tool=False):
|
|||||||
# except AttributeError:
|
# except AttributeError:
|
||||||
# # It's also possible we try to instantiate a singleton, but a better
|
# # It's also possible we try to instantiate a singleton, but a better
|
||||||
# # message will be provided anyway if the user try the provided hint
|
# # message will be provided anyway if the user try the provided hint
|
||||||
# raise RuntimeError(f"Refcounted Godot object must be created with `{ cls.__name__ }()`")
|
# raise RuntimeError(f"Refcounted Pandemonium object must be created with `{ cls.__name__ }()`")
|
||||||
# instance = cls._from_ptr(ptr)
|
# instance = cls._from_ptr(ptr)
|
||||||
# # TODO: We should generate a Resource instance containing the script
|
# # TODO: We should generate a Resource instance containing the script
|
||||||
# # and attach it to the main class here.
|
# # and attach it to the main class here.
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
/*
|
/*
|
||||||
* This file gets compiled as a shared library that act as the entry point
|
* This file gets compiled as a shared library that act as the entry point
|
||||||
* to the pythonscript plugin.
|
* to the pythonscript plugin.
|
||||||
* It should be loaded by Godot's GDNative system (see the `pythonscript.gdnlib`
|
* It should be loaded by Pandemonium's GDNative system (see the `pythonscript.gdnlib`
|
||||||
* file in the example/test projects).
|
* file in the example/test projects).
|
||||||
* As part of the loading, GDNative will call the `pandemonium_gdnative_init`
|
* As part of the loading, GDNative will call the `pandemonium_gdnative_init`
|
||||||
* function which will in turn initialize the CPython interpreter then register
|
* function which will in turn initialize the CPython interpreter then register
|
||||||
* Python as a new language using Godot's Pluginscript system.
|
* Python as a new language using Pandemonium's Pluginscript system.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define PY_SSIZE_T_CLEAN
|
#define PY_SSIZE_T_CLEAN
|
||||||
@ -65,7 +65,7 @@ static PyThreadState *gilstate = NULL;
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Global variables exposing Godot API to the pandemonium.hazmat cython module.
|
* Global variables exposing Pandemonium API to the pandemonium.hazmat cython module.
|
||||||
* Hence we must initialized them before loading `_pandemonium`/`pandemonium` modules
|
* Hence we must initialized them before loading `_pandemonium`/`pandemonium` modules
|
||||||
* (which both depend on `pandemonium.hazmat`).
|
* (which both depend on `pandemonium.hazmat`).
|
||||||
*/
|
*/
|
||||||
@ -135,7 +135,7 @@ GDN_EXPORT void pandemonium_gdnative_init(pandemonium_gdnative_init_options *opt
|
|||||||
// Check for mandatory plugins
|
// Check for mandatory plugins
|
||||||
|
|
||||||
if (!pythonscript_gdapi10 || !pythonscript_gdapi11 || !pythonscript_gdapi12) {
|
if (!pythonscript_gdapi10 || !pythonscript_gdapi11 || !pythonscript_gdapi12) {
|
||||||
GD_ERROR_PRINT("Godot-Python requires GDNative API >= v1.2");
|
GD_ERROR_PRINT("Pandemonium-Python requires GDNative API >= v1.2");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!pythonscript_gdapi_ext_pluginscript) {
|
if (!pythonscript_gdapi_ext_pluginscript) {
|
||||||
|
@ -182,7 +182,7 @@ def test_access_property(generate_obj):
|
|||||||
def test_new_on_overloaded_class(generate_obj):
|
def test_new_on_overloaded_class(generate_obj):
|
||||||
node = generate_obj(virtualtestbedcls)
|
node = generate_obj(virtualtestbedcls)
|
||||||
# Make sure doing MyClass.new() doesn't return an instance of the
|
# Make sure doing MyClass.new() doesn't return an instance of the
|
||||||
# Godot class we inherit from
|
# Pandemonium class we inherit from
|
||||||
assert isinstance(node, virtualtestbedcls)
|
assert isinstance(node, virtualtestbedcls)
|
||||||
|
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ def test_getitem():
|
|||||||
assert v[0.5] == Vector2()
|
assert v[0.5] == Vector2()
|
||||||
# Missing items are stored as None
|
# Missing items are stored as None
|
||||||
assert v["dummy"] is None
|
assert v["dummy"] is None
|
||||||
# Cannot store non Godot types
|
# Cannot store non Pandemonium types
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
v[object()]
|
v[object()]
|
||||||
|
|
||||||
@ -82,7 +82,7 @@ def test_setitem():
|
|||||||
v["a"] = 4
|
v["a"] = 4
|
||||||
assert len(v) == 4
|
assert len(v) == 4
|
||||||
assert v["a"] == 4
|
assert v["a"] == 4
|
||||||
# Cannot store non Godot types
|
# Cannot store non Pandemonium types
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
v[object()] = 4
|
v[object()] = 4
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
@ -99,7 +99,7 @@ def test_delitem():
|
|||||||
# Delete on missing items should raise error
|
# Delete on missing items should raise error
|
||||||
with pytest.raises(KeyError):
|
with pytest.raises(KeyError):
|
||||||
del v["missing"]
|
del v["missing"]
|
||||||
# Cannot store non Godot types
|
# Cannot store non Pandemonium types
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
del v[object()]
|
del v[object()]
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
# assert isinstance(KEY_ESCAPE, int)
|
# assert isinstance(KEY_ESCAPE, int)
|
||||||
|
|
||||||
# def test_objects_unicity(self):
|
# def test_objects_unicity(self):
|
||||||
# # Main loop object is a Godot Object, calling `get_main_loop` from
|
# # Main loop object is a Pandemonium Object, calling `get_main_loop` from
|
||||||
# # python returns a different python wrapper on the same object each time.
|
# # python returns a different python wrapper on the same object each time.
|
||||||
# # However those wrappers should feel like they are the same object.
|
# # However those wrappers should feel like they are the same object.
|
||||||
# ml = Engine.get_main_loop()
|
# ml = Engine.get_main_loop()
|
||||||
@ -40,7 +40,7 @@
|
|||||||
# assert ml != None # noqa
|
# assert ml != None # noqa
|
||||||
# assert ml != ""
|
# assert ml != ""
|
||||||
# assert ml != 42
|
# assert ml != 42
|
||||||
# # Don't forget to free the Godot Object
|
# # Don't forget to free the Pandemonium Object
|
||||||
# obj.free()
|
# obj.free()
|
||||||
|
|
||||||
# def test_class(self):
|
# def test_class(self):
|
||||||
|
@ -8,7 +8,7 @@ def environment_factory():
|
|||||||
# Environment objects are stubbed on headless server, hence
|
# Environment objects are stubbed on headless server, hence
|
||||||
# their corresponding RID is always the same default value
|
# their corresponding RID is always the same default value
|
||||||
if OS.has_feature("Server"):
|
if OS.has_feature("Server"):
|
||||||
pytest.skip("Not available on headless Godot")
|
pytest.skip("Not available on headless Pandemonium")
|
||||||
|
|
||||||
def _factory():
|
def _factory():
|
||||||
return Environment()
|
return Environment()
|
||||||
|
@ -29,7 +29,7 @@ def test_base():
|
|||||||
|
|
||||||
@pytest.mark.parametrize("char", ["e", "é", "€", "蛇", "🐍"])
|
@pytest.mark.parametrize("char", ["e", "é", "€", "蛇", "🐍"])
|
||||||
def test_unicode(char):
|
def test_unicode(char):
|
||||||
# Godot supports UCS2 on Windows and UCS4 on other platforms
|
# Pandemonium supports UCS2 on Windows and UCS4 on other platforms
|
||||||
if len(char.encode("utf8")) > 2 and sys.platform == "win32":
|
if len(char.encode("utf8")) > 2 and sys.platform == "win32":
|
||||||
pytest.skip("Windows only supports UCS2")
|
pytest.skip("Windows only supports UCS2")
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ test_factory(
|
|||||||
try:
|
try:
|
||||||
import pandemonium
|
import pandemonium
|
||||||
except ImportError as exc:
|
except ImportError as exc:
|
||||||
assert "Cannot initialize pandemonium module given Godot GDNative API not available." in str(exc)
|
assert "Cannot initialize pandemonium module given Pandemonium GDNative API not available." in str(exc)
|
||||||
""",
|
""",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user