Skip to content

Commit

Permalink
tests pass
Browse files Browse the repository at this point in the history
  • Loading branch information
stepjam committed Feb 4, 2024
1 parent ea982b5 commit 34c1086
Show file tree
Hide file tree
Showing 19 changed files with 304 additions and 133 deletions.
17 changes: 16 additions & 1 deletion pyrep/backend/bridge.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,26 @@
import ctypes
import sys


def load():
# add coppeliaSim's pythondir to sys.path:
from pyrep.backend.lib import (
simGetStringParam,
simReleaseBuffer,
sim_stringparam_pythondir,
)

pythonDirPtr = simGetStringParam(sim_stringparam_pythondir)
pythonDir = ctypes.string_at(pythonDirPtr).decode("utf-8")
simReleaseBuffer(pythonDirPtr)
if pythonDir not in sys.path:
sys.path.append(pythonDir)

# load lua functions for call(), getObject(), etc...:
call("require", ("scriptClientBridge",))


def call(func, args):
def call(func, args, typeHints=None):
from pyrep.backend.lib import (
simCreateStack,
simCallScriptFunctionEx,
Expand Down
20 changes: 0 additions & 20 deletions pyrep/backend/callback.py

This file was deleted.

23 changes: 17 additions & 6 deletions pyrep/backend/lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,26 @@
if "COPPELIASIM_ROOT" not in os.environ:
raise PyRepError("COPPELIASIM_ROOT not defined. See installation instructions.")
coppeliasim_root = os.environ["COPPELIASIM_ROOT"]
coppeliasim_library = os.path.join(coppeliasim_root, "libcoppeliaSim.so")

coppeliasim_library = ""
plat = platform.system()
if plat == "Windows":
raise NotImplementedError()
# coppeliasim_library /= f'{defaultLibNameBase}.dll'
elif plat == "Linux":
coppeliasim_library = os.path.join(coppeliasim_root, "libcoppeliaSim.so")
elif plat == "Darwin":
raise NotImplementedError()
# coppeliasim_library /= f'../MacOS/lib{defaultLibNameBase}.dylib'
if not os.path.isfile(coppeliasim_library):
raise PyRepError(
"COPPELIASIM_ROOT was not a correct path. " "See installation instructions"
)

appDir = os.path.dirname(coppeliasim_library)
os.environ["QT_QPA_PLATFORM_PLUGIN_PATH"] = appDir

os.environ["QT_QPA_PLATFORM_PLUGIN_PATH"] = coppeliasim_root

plat = platform.system()
if plat == "Darwin":
fd = os.path.normpath(appDir + "/../Frameworks")
fd = os.path.normpath(coppeliasim_root + "/../Frameworks")
os.environ["DYLD_LIBRARY_PATH"] = fd + ":" + os.environ.get("DYLD_LIBRARY_PATH", "")
print(
f"If next step fails, do: export DYLD_LIBRARY_PATH={fd}:"
Expand Down Expand Up @@ -122,6 +129,8 @@
coppeliaSimLib.simPushDoubleTableOntoStack.restype = c_int
coppeliaSimLib.simDebugStack.argtypes = [c_int, c_int]
coppeliaSimLib.simDebugStack.restype = c_int
coppeliaSimLib.simGetStringParam.argtypes = [c_int]
coppeliaSimLib.simGetStringParam.restype = c_void_p

__all__ = []

Expand Down Expand Up @@ -167,6 +176,8 @@
const.sim_stringparam_dlgverbosity = 123
const.sim_stringparam_startupscriptstring = 125

const.sim_stringparam_pythondir = 137

for name in dir(const):
if name.startswith("sim"):
f = getattr(const, name)
Expand Down
183 changes: 138 additions & 45 deletions pyrep/backend/stack.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def read_double(stackHandle):
raise RuntimeError("expected double")


def read_string(stackHandle):
def read_string(stackHandle, encoding=None):
from pyrep.backend.lib import (
simGetStackStringValue,
simReleaseBuffer,
Expand All @@ -80,9 +80,13 @@ def read_string(stackHandle):

string_size = ctypes.c_int()
string_ptr = simGetStackStringValue(stackHandle, ctypes.byref(string_size))
string_value = ctypes.string_at(string_ptr, string_size.value)
value = ctypes.string_at(string_ptr, string_size.value)
simPopStackItem(stackHandle, 1)
value = string_value.decode("utf-8")
if encoding:
try:
value = value.decode(encoding)
except UnicodeDecodeError:
pass
simReleaseBuffer(string_ptr)
return value

Expand Down Expand Up @@ -119,33 +123,33 @@ def read_list(stackHandle):
simMoveStackItemToTop,
)

vals = list()
lst = list()
oldsz = simGetStackSize(stackHandle)
simUnfoldStackTable(stackHandle)
n = (simGetStackSize(stackHandle) - oldsz + 1) // 2
for i in range(n):
simMoveStackItemToTop(stackHandle, oldsz - 1)
read_value(stackHandle)
simMoveStackItemToTop(stackHandle, oldsz - 1)
vals.append(read_value(stackHandle))
return vals
lst.append(read_value(stackHandle))
return lst


def read_table(stackHandle):
def read_table(stackHandle, typeHint=None):
from pyrep.backend.lib import (
simGetStackTableInfo,
sim_stack_table_map,
sim_stack_table_empty,
)

sz = simGetStackTableInfo(stackHandle, 0)
if sz >= 0:
if typeHint == "list" or sz >= 0:
return read_list(stackHandle)
elif sz == sim_stack_table_map or sz == sim_stack_table_empty:
elif typeHint == "dict" or sz in (sim_stack_table_map, sim_stack_table_empty):
return read_dict(stackHandle)


def read_value(stackHandle):
def read_value(stackHandle, typeHint=None):
from pyrep.backend.lib import (
simGetStackItemType,
sim_stackitem_null,
Expand All @@ -156,25 +160,38 @@ def read_value(stackHandle):
sim_stackitem_integer,
)

item_type = simGetStackItemType(stackHandle, -1)
if item_type == sim_stackitem_null:
value = read_null(stackHandle)
elif item_type == sim_stackitem_double:
value = read_double(stackHandle)
elif item_type == sim_stackitem_bool:
value = read_bool(stackHandle)
elif item_type == sim_stackitem_string:
value = read_string(stackHandle)
elif item_type == sim_stackitem_table:
value = read_table(stackHandle)
elif item_type == sim_stackitem_integer:
value = read_long(stackHandle)
else:
raise RuntimeError(f"unexpected stack item type: {item_type}")
return value


def read(stackHandle):
match typeHint:
case "null":
return read_null(stackHandle)
case "float" | "double":
return read_double(stackHandle)
case "bool":
return read_bool(stackHandle)
case "string":
return read_string(stackHandle, encoding="utf-8")
case "buffer":
return read_string(stackHandle, encoding=None)
case "table" | "list" | "dict":
return read_table(stackHandle, typeHint)
case "int" | "long":
return read_long(stackHandle)
itemType = simGetStackItemType(stackHandle, -1)
if itemType == sim_stackitem_null:
return read_null(stackHandle)
if itemType == sim_stackitem_double:
return read_double(stackHandle)
if itemType == sim_stackitem_bool:
return read_bool(stackHandle)
if itemType == sim_stackitem_string:
return read_string(stackHandle, encoding="utf-8")
if itemType == sim_stackitem_table:
return read_table(stackHandle, typeHint)
if itemType == sim_stackitem_integer:
return read_long(stackHandle)
raise RuntimeError(f"unexpected stack item type: {itemType} ({typeHint=})")


def read(stackHandle, typeHints=None):
from pyrep.backend.lib import (
simGetStackSize,
simMoveStackItemToTop,
Expand All @@ -185,7 +202,11 @@ def read(stackHandle):
tuple_data = []
for i in range(stack_size):
simMoveStackItemToTop(stackHandle, 0)
tuple_data.append(read_value(stackHandle))
if typeHints and len(typeHints) > i:
value = read_value(stackHandle, typeHints[i])
else:
value = read_value(stackHandle)
tuple_data.append(value)
simPopStackItem(stackHandle, 0) # clear all
return tuple(tuple_data)

Expand Down Expand Up @@ -222,12 +243,22 @@ def write_int(stackHandle, value):
simPushInt32OntoStack(stackHandle, value)


def write_string(stackHandle, value):
def write_long(stackHandle, value):
from pyrep.backend.lib import (
simPushInt64OntoStack,
)

simPushInt64OntoStack(stackHandle, value)


def write_string(stackHandle, value, encoding="utf-8"):
from pyrep.backend.lib import (
simPushStringOntoStack,
)

simPushStringOntoStack(stackHandle, value.encode("utf-8"), len(value))
if encoding:
value = value.encode(encoding)
simPushStringOntoStack(stackHandle, value, len(value))


def write_dict(stackHandle, value):
Expand Down Expand Up @@ -256,28 +287,49 @@ def write_list(stackHandle, value):
simInsertDataIntoStackTable(stackHandle)


def write_value(stackHandle, value):
def write_value(stackHandle, value, typeHint=None):
match typeHint:
case "null":
return write_null(stackHandle, value)
case "float" | "double":
return write_double(stackHandle, value)
case "bool":
return write_bool(stackHandle, value)
case "int" | "long":
return write_long(stackHandle, value)
case "buffer":
return write_string(stackHandle, value, encoding=None)
case "string":
return write_string(stackHandle, value, encoding="utf-8")
case "dict":
return write_dict(stackHandle, value)
case "list":
return write_list(stackHandle, value)
if value is None:
write_null(stackHandle, value)
return write_null(stackHandle, value)
elif isinstance(value, float):
write_double(stackHandle, value)
return write_double(stackHandle, value)
elif isinstance(value, bool):
write_bool(stackHandle, value)
return write_bool(stackHandle, value)
elif isinstance(value, int):
write_int(stackHandle, value)
return write_long(stackHandle, value)
elif isinstance(value, bytes):
return write_string(stackHandle, value, encoding=None)
elif isinstance(value, str):
write_string(stackHandle, value)
return write_string(stackHandle, value, encoding="utf-8")
elif isinstance(value, dict):
write_dict(stackHandle, value)
return write_dict(stackHandle, value)
elif isinstance(value, list):
write_list(stackHandle, value)
else:
raise RuntimeError(f"unexpected type: {type(value)}")
return write_list(stackHandle, value)
raise RuntimeError(f"unexpected type: {type(value)} ({typeHint=})")


def write(stackHandle, tuple_data):
for item in tuple_data:
write_value(stackHandle, item)
def write(stackHandle, tuple_data, typeHints=None):
for i, value in enumerate(tuple_data):
if typeHints and len(typeHints) > i:
write_value(stackHandle, value, typeHints[i])
else:
write_value(stackHandle, value)


def debug(stackHandle, info=None):
Expand All @@ -293,3 +345,44 @@ def debug(stackHandle, info=None):
for i in range(simGetStackSize(stackHandle)):
simDebugStack(stackHandle, i)
print("#" * 70)


def callback(f):
def wrapper(stackHandle):
from typing import get_args

inTypes = tuple(
[
arg_type.__name__
for arg, arg_type in f.__annotations__.items()
if arg != "return"
]
)

if return_annotation := f.__annotations__.get("return"):
origin = getattr(return_annotation, "__origin__", None)
if origin in (tuple, list): # Handling built-in tuple and list
outTypes = tuple([t.__name__ for t in get_args(return_annotation)])
elif origin: # Handling other generic types like Tuple, List from typing
outTypes = (origin.__name__,)
else:
outTypes = (return_annotation.__name__,)
else:
outTypes = ()

try:
inArgs = read(stackHandle, inTypes)
outArgs = f(*inArgs)
if outArgs is None:
outArgs = ()
elif not isinstance(outArgs, tuple):
outArgs = (outArgs,)
write(stackHandle, outArgs, outTypes)
return 1
except Exception:
import traceback

traceback.print_exc()
return 0

return wrapper
1 change: 0 additions & 1 deletion pyrep/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ class ObjectType(Enum):
PROXIMITY_SENSOR = sim.sim_object_proximitysensor_type
GRAPH = sim.sim_object_graph_type
CAMERA = sim.sim_object_camera_type
PATH = sim.sim_object_dummy_type
VISION_SENSOR = sim.sim_object_visionsensor_type
VOLUME = sim.sim_object_volume_type
MILl = sim.sim_object_mill_type
Expand Down
Loading

0 comments on commit 34c1086

Please sign in to comment.