convert spaces to tabs

This commit is contained in:
Izalia Mae 2023-01-08 23:05:32 -05:00
parent d1145c5995
commit d082438777
76 changed files with 2039 additions and 2039 deletions

View file

@ -1,6 +1,6 @@
class LuaException(Exception): class LuaException(Exception):
@property @property
def message(self): def message(self):
if len(self.args) < 1: if len(self.args) < 1:
return None return None
return self.args[0] return self.args[0]

View file

@ -8,28 +8,28 @@ LuaNum = Union[int, float]
class LuaExpr: class LuaExpr:
def get_expr_code(self): def get_expr_code(self):
raise NotImplementedError raise NotImplementedError
_tmap = { _tmap = {
'\\': '\\\\', '\\': '\\\\',
'\a': '\\a', '\a': '\\a',
'\b': '\\b', '\b': '\\b',
'\f': '\\f', '\f': '\\f',
'\n': '\\n', '\n': '\\n',
'\r': '\\r', '\r': '\\r',
'\t': '\\t', '\t': '\\t',
'\v': '\\v', '\v': '\\v',
'"': '\\"', '"': '\\"',
"'": "\\'", "'": "\\'",
'[': '\\[', '[': '\\[',
']': '\\]', ']': '\\]',
} }
_tmap = {ord(c): r for c, r in _tmap.items()} _tmap = {ord(c): r for c, r in _tmap.items()}
def lua_string(v): def lua_string(v):
if isinstance(v, bytes): if isinstance(v, bytes):
v = ser.decode(v) v = ser.decode(v)
return '"{}"'.format(v.translate(_tmap)) return '"{}"'.format(v.translate(_tmap))

View file

@ -3,136 +3,136 @@ from .errors import LuaException
def lua_table_to_list(x, length: int = None, low_index: int = 1): def lua_table_to_list(x, length: int = None, low_index: int = 1):
if not x: if not x:
return [] if length is None else [None] * length return [] if length is None else [None] * length
assert all(map(lambda k: isinstance(k, int), x.keys())) assert all(map(lambda k: isinstance(k, int), x.keys()))
assert min(x.keys()) >= low_index assert min(x.keys()) >= low_index
dlen = max(x.keys()) - low_index + 1 dlen = max(x.keys()) - low_index + 1
if length is not None: if length is not None:
assert dlen <= length assert dlen <= length
else: else:
length = dlen length = dlen
return [x.get(i + low_index) for i in range(length)] return [x.get(i + low_index) for i in range(length)]
class ResultProc: class ResultProc:
def __init__(self, result): def __init__(self, result):
self._v = result self._v = result
self._i = 1 self._i = 1
def forward(self): def forward(self):
self._i += 1 self._i += 1
def back(self): def back(self):
self._i -= 1 self._i -= 1
def peek(self): def peek(self):
return self._v.get(self._i) return self._v.get(self._i)
def take(self): def take(self):
r = self.peek() r = self.peek()
self.forward() self.forward()
return r return r
def take_none(self): def take_none(self):
x = self.take() x = self.take()
assert x is None assert x is None
return x return x
def take_bool(self): def take_bool(self):
x = self.take() x = self.take()
assert x is True or x is False assert x is True or x is False
return x return x
def take_int(self): def take_int(self):
x = self.take() x = self.take()
assert isinstance(x, int) assert isinstance(x, int)
assert not isinstance(x, bool) assert not isinstance(x, bool)
return x return x
def take_number(self): def take_number(self):
x = self.take() x = self.take()
assert isinstance(x, (int, float)) assert isinstance(x, (int, float))
assert not isinstance(x, bool) assert not isinstance(x, bool)
return x return x
def take_bytes(self): def take_bytes(self):
x = self.take() x = self.take()
assert isinstance(x, bytes) assert isinstance(x, bytes)
return x return x
def take_string(self): def take_string(self):
return self.take_bytes().decode('latin1') return self.take_bytes().decode('latin1')
def take_unicode(self): def take_unicode(self):
return self.take_bytes().decode('utf-8') return self.take_bytes().decode('utf-8')
def take_dict(self, keys=None): def take_dict(self, keys=None):
x = self.take() x = self.take()
assert isinstance(x, dict) assert isinstance(x, dict)
if keys is None: if keys is None:
return x return x
return TableProc(x, keys) return TableProc(x, keys)
def take_list(self, length: int = None): def take_list(self, length: int = None):
return lua_table_to_list(self.take_dict(), length) return lua_table_to_list(self.take_dict(), length)
def check_bool_error(self): def check_bool_error(self):
success = self.take_bool() success = self.take_bool()
if not success: if not success:
raise LuaException(self.take_string()) raise LuaException(self.take_string())
def check_nil_error(self): def check_nil_error(self):
if self.peek() is None: if self.peek() is None:
self.forward() self.forward()
raise LuaException(self.take_string()) raise LuaException(self.take_string())
def take_option_int(self): def take_option_int(self):
if self.peek() is None: if self.peek() is None:
return self.take_none() return self.take_none()
return self.take_int() return self.take_int()
def take_option_bytes(self): def take_option_bytes(self):
if self.peek() is None: if self.peek() is None:
return self.take_none() return self.take_none()
return self.take_bytes() return self.take_bytes()
def take_option_string(self): def take_option_string(self):
if self.peek() is None: if self.peek() is None:
return self.take_none() return self.take_none()
return self.take_string() return self.take_string()
def take_option_unicode(self): def take_option_unicode(self):
if self.peek() is None: if self.peek() is None:
return self.take_none() return self.take_none()
return self.take_unicode() return self.take_unicode()
def take_option_string_bool(self): def take_option_string_bool(self):
p = self.peek() p = self.peek()
if p is None or p is True or p is False: if p is None or p is True or p is False:
self.forward() self.forward()
return p return p
return self.take_string() return self.take_string()
def take_list_of_strings(self, length: int = None): def take_list_of_strings(self, length: int = None):
x = self.take_list(length) x = self.take_list(length)
assert all(map(lambda v: isinstance(v, bytes), x)) assert all(map(lambda v: isinstance(v, bytes), x))
return [ser.decode(v) for v in x] return [ser.decode(v) for v in x]
def take_2d_int(self): def take_2d_int(self):
x = self.take_list() x = self.take_list()
x = [lua_table_to_list(item) for item in x] x = [lua_table_to_list(item) for item in x]
for row in x: for row in x:
for item in row: for item in row:
assert isinstance(item, int) assert isinstance(item, int)
return x return x
class TableProc(ResultProc): class TableProc(ResultProc):
def __init__(self, result, keys): def __init__(self, result, keys):
self._v = result self._v = result
self._keys = keys self._keys = keys
self._i = 0 self._i = 0
def peek(self): def peek(self):
return self._v.get(self._keys[self._i]) return self._v.get(self._keys[self._i])

View file

@ -4,8 +4,8 @@ from . import lua
__all__ = ( __all__ = (
'serialize', 'serialize',
'deserialize', 'deserialize',
) )
@ -15,94 +15,94 @@ assert [bytes([i]) for i in range(256)] == [chr(i).encode(_ENC) for i in range(2
def encode(s: str) -> bytes: def encode(s: str) -> bytes:
return s.encode(_ENC) return s.encode(_ENC)
def nil_encode(s): def nil_encode(s):
if s is None: if s is None:
return None return None
return encode(s) return encode(s)
def dirty_encode(s: str) -> bytes: def dirty_encode(s: str) -> bytes:
return s.encode(_ENC, errors='replace') return s.encode(_ENC, errors='replace')
def decode(b): def decode(b):
return b.decode(_ENC) return b.decode(_ENC)
def serialize(v: Any) -> bytes: def serialize(v: Any) -> bytes:
if v is None: if v is None:
return b'N' return b'N'
elif v is False: elif v is False:
return b'F' return b'F'
elif v is True: elif v is True:
return b'T' return b'T'
elif isinstance(v, (int, float)): elif isinstance(v, (int, float)):
return '[{}]'.format(v).encode(_ENC) return '[{}]'.format(v).encode(_ENC)
elif isinstance(v, bytes): elif isinstance(v, bytes):
return '<{}>'.format(len(v)).encode(_ENC) + v return '<{}>'.format(len(v)).encode(_ENC) + v
elif isinstance(v, str): elif isinstance(v, str):
raise ValueError('Strings are not allowed for serialization') raise ValueError('Strings are not allowed for serialization')
elif isinstance(v, (list, tuple)): elif isinstance(v, (list, tuple)):
items = [] items = []
for k, x in enumerate(v, start=1): for k, x in enumerate(v, start=1):
items.append(b':' + serialize(k) + serialize(x)) items.append(b':' + serialize(k) + serialize(x))
return b'{' + b''.join(items) + b'}' return b'{' + b''.join(items) + b'}'
elif isinstance(v, dict): elif isinstance(v, dict):
items = [] items = []
for k, x in v.items(): for k, x in v.items():
items.append(b':' + serialize(k) + serialize(x)) items.append(b':' + serialize(k) + serialize(x))
return b'{' + b''.join(items) + b'}' return b'{' + b''.join(items) + b'}'
elif isinstance(v, lua.LuaExpr): elif isinstance(v, lua.LuaExpr):
e = 'return ' + v.get_expr_code() e = 'return ' + v.get_expr_code()
return 'E{}>'.format(len(e)).encode(_ENC) + e.encode(_ENC) return 'E{}>'.format(len(e)).encode(_ENC) + e.encode(_ENC)
else: else:
raise ValueError('Value can\'t be serialized: {}'.format(repr(v))) raise ValueError('Value can\'t be serialized: {}'.format(repr(v)))
def _deserialize(b: bytes, _idx: int) -> Tuple[Any, int]: def _deserialize(b: bytes, _idx: int) -> Tuple[Any, int]:
tok = b[_idx] tok = b[_idx]
_idx += 1 _idx += 1
if tok == 78: # N if tok == 78: # N
return None, _idx return None, _idx
elif tok == 70: # F elif tok == 70: # F
return False, _idx return False, _idx
elif tok == 84: # T elif tok == 84: # T
return True, _idx return True, _idx
elif tok == 91: # [ elif tok == 91: # [
newidx = b.index(b']', _idx) newidx = b.index(b']', _idx)
f = float(b[_idx:newidx]) f = float(b[_idx:newidx])
if f.is_integer(): if f.is_integer():
f = int(f) f = int(f)
return f, newidx + 1 return f, newidx + 1
elif tok == 60: # < elif tok == 60: # <
newidx = b.index(b'>', _idx) newidx = b.index(b'>', _idx)
ln = int(b[_idx:newidx]) ln = int(b[_idx:newidx])
return b[newidx + 1:newidx + 1 + ln], newidx + 1 + ln return b[newidx + 1:newidx + 1 + ln], newidx + 1 + ln
elif tok == 123: # { elif tok == 123: # {
r = {} r = {}
while True: while True:
tok = b[_idx] tok = b[_idx]
_idx += 1 _idx += 1
if tok == 125: # } if tok == 125: # }
break break
key, _idx = _deserialize(b, _idx) key, _idx = _deserialize(b, _idx)
value, _idx = _deserialize(b, _idx) value, _idx = _deserialize(b, _idx)
r[key] = value r[key] = value
return r, _idx return r, _idx
else: else:
raise ValueError raise ValueError
def deserialize(b: bytes) -> Any: def deserialize(b: bytes) -> Any:
return _deserialize(b, 0)[0] return _deserialize(b, 0)[0]
def dcmditer(b: bytes): def dcmditer(b: bytes):
yield b[0:1] yield b[0:1]
idx = 1 idx = 1
while idx < len(b): while idx < len(b):
chunk, idx = _deserialize(b, idx) chunk, idx = _deserialize(b, idx)
yield chunk yield chunk

View file

@ -18,111 +18,111 @@ DEBUG_PROTO = False
class CCApplication(web.Application): class CCApplication(web.Application):
@staticmethod @staticmethod
async def _bin_messages(ws): async def _bin_messages(ws):
async for msg in ws: async for msg in ws:
if msg.type != WSMsgType.BINARY: if msg.type != WSMsgType.BINARY:
continue continue
if DEBUG_PROTO: if DEBUG_PROTO:
sys.__stdout__.write('ws received ' + repr(msg.data) + '\n') sys.__stdout__.write('ws received ' + repr(msg.data) + '\n')
yield msg.data yield msg.data
@staticmethod @staticmethod
async def _send(ws, data): async def _send(ws, data):
if DEBUG_PROTO: if DEBUG_PROTO:
sys.__stdout__.write('ws send ' + repr(data) + '\n') sys.__stdout__.write('ws send ' + repr(data) + '\n')
await ws.send_bytes(data) await ws.send_bytes(data)
async def _launch_program(self, ws): async def _launch_program(self, ws):
async for msg in self._bin_messages(ws): async for msg in self._bin_messages(ws):
msg = ser.dcmditer(msg) msg = ser.dcmditer(msg)
action = next(msg) action = next(msg)
if action != b'0': if action != b'0':
await self._send(ws, PROTO_ERROR) await self._send(ws, PROTO_ERROR)
return None return None
version = next(msg) version = next(msg)
if version != LUA_FILE_VERSION: if version != LUA_FILE_VERSION:
await self._send(ws, b'C' + ser.serialize(ser.encode( await self._send(ws, b'C' + ser.serialize(ser.encode(
'protocol version mismatch (expected {}, got {}), redownload py'.format( 'protocol version mismatch (expected {}, got {}), redownload py'.format(
LUA_FILE_VERSION, version, LUA_FILE_VERSION, version,
)))) ))))
return None return None
computer_id = next(msg) computer_id = next(msg)
args = lua_table_to_list(next(msg), low_index=0) args = lua_table_to_list(next(msg), low_index=0)
def sender(data): def sender(data):
asyncio.create_task(self._send(ws, data)) asyncio.create_task(self._send(ws, data))
sess = CCSession(computer_id, sender) sess = CCSession(computer_id, sender)
if len(args) >= 2: if len(args) >= 2:
sess.run_program(args[1], [ser.decode(x) for x in args[2:]]) sess.run_program(args[1], [ser.decode(x) for x in args[2:]])
else: else:
sess.run_repl() sess.run_repl()
return sess return sess
async def ws(self, request): async def ws(self, request):
ws = web.WebSocketResponse() ws = web.WebSocketResponse()
await ws.prepare(request) await ws.prepare(request)
sess = await self._launch_program(ws) sess = await self._launch_program(ws)
if sess is not None: if sess is not None:
async for msg in self._bin_messages(ws): async for msg in self._bin_messages(ws):
msg = ser.dcmditer(msg) msg = ser.dcmditer(msg)
action = next(msg) action = next(msg)
if action == b'E': if action == b'E':
sess.on_event( sess.on_event(
next(msg), next(msg),
lua_table_to_list(next(msg)), lua_table_to_list(next(msg)),
) )
elif action == b'T': elif action == b'T':
sess.on_task_result( sess.on_task_result(
next(msg), next(msg),
next(msg), next(msg),
) )
else: else:
await self._send(ws, PROTO_ERROR) await self._send(ws, PROTO_ERROR)
break break
return ws return ws
@staticmethod @staticmethod
def backdoor(request): def backdoor(request):
with open(LUA_FILE, 'r') as f: with open(LUA_FILE, 'r') as f:
fcont = f.read() fcont = f.read()
h = request.host h = request.host
if ':' not in h: if ':' not in h:
# fix for malformed Host header # fix for malformed Host header
h += ':{}'.format(request.app['port']) h += ':{}'.format(request.app['port'])
fcont = fcont.replace( fcont = fcont.replace(
"local url = 'http://127.0.0.1:4343/'", "local url = 'http://127.0.0.1:4343/'",
"local url = '{}://{}/'".format('ws', h) "local url = '{}://{}/'".format('ws', h)
) )
return web.Response(text=fcont) return web.Response(text=fcont)
def initialize(self): def initialize(self):
self.router.add_get('/', self.backdoor) self.router.add_get('/', self.backdoor)
self.router.add_get('/ws/', self.ws) self.router.add_get('/ws/', self.ws)
def main(): def main():
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument('--host') parser.add_argument('--host')
parser.add_argument('--port', type=int, default=8080) parser.add_argument('--port', type=int, default=8080)
args = parser.parse_args() args = parser.parse_args()
app_kw = {} app_kw = {}
if args.host is not None: if args.host is not None:
app_kw['host'] = args.host app_kw['host'] = args.host
app_kw['port'] = args.port app_kw['port'] = args.port
app = CCApplication() app = CCApplication()
app['port'] = args.port app['port'] = args.port
app.initialize() app.initialize()
web.run_app(app, **app_kw) web.run_app(app, **app_kw)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -20,114 +20,114 @@ from . import rproc, ser
__all__ = ( __all__ = (
'CCSession', 'CCSession',
'get_current_session', 'get_current_session',
'eval_lua', 'eval_lua',
'lua_context_object', 'lua_context_object',
) )
def debug(*args): def debug(*args):
sys.__stdout__.write(' '.join(map(str, args)) + '\n') sys.__stdout__.write(' '.join(map(str, args)) + '\n')
sys.__stdout__.flush() sys.__stdout__.flush()
DIGITS = string.digits + string.ascii_lowercase DIGITS = string.digits + string.ascii_lowercase
def base36(n): def base36(n):
r = '' r = ''
while n: while n:
r += DIGITS[n % 36] r += DIGITS[n % 36]
n //= 36 n //= 36
return ser.encode(r[::-1]) return ser.encode(r[::-1])
def _is_global_greenlet(): def _is_global_greenlet():
return not hasattr(get_current_greenlet(), 'cc_greenlet') return not hasattr(get_current_greenlet(), 'cc_greenlet')
def get_current_session(): def get_current_session():
try: try:
return get_current_greenlet().cc_greenlet._sess return get_current_greenlet().cc_greenlet._sess
except AttributeError: except AttributeError:
raise RuntimeError('Computercraft function was called outside context') raise RuntimeError('Computercraft function was called outside context')
class StdFileProxy: class StdFileProxy:
def __init__(self, native, err): def __init__(self, native, err):
self._native = native self._native = native
self._err = err self._err = err
def read(self, size=-1): def read(self, size=-1):
if _is_global_greenlet(): if _is_global_greenlet():
return self._native.read(size) return self._native.read(size)
else: else:
raise RuntimeError( raise RuntimeError(
"Computercraft environment doesn't support stdin read method") "Computercraft environment doesn't support stdin read method")
def readline(self, size=-1): def readline(self, size=-1):
if _is_global_greenlet(): if _is_global_greenlet():
return self._native.readline(size) return self._native.readline(size)
else: else:
if size is not None and size >= 0: if size is not None and size >= 0:
raise RuntimeError( raise RuntimeError(
"Computercraft environment doesn't support " "Computercraft environment doesn't support "
"stdin readline method with parameter") "stdin readline method with parameter")
return eval_lua('return io.read()').take_string() + '\n' return eval_lua('return io.read()').take_string() + '\n'
def write(self, s): def write(self, s):
if _is_global_greenlet(): if _is_global_greenlet():
return self._native.write(s) return self._native.write(s)
else: else:
s = ser.dirty_encode(s) s = ser.dirty_encode(s)
if self._err: if self._err:
return eval_lua('io.stderr:write(...)', s).take_none() return eval_lua('io.stderr:write(...)', s).take_none()
else: else:
return eval_lua('io.write(...)', s).take_none() return eval_lua('io.write(...)', s).take_none()
def fileno(self): def fileno(self):
if _is_global_greenlet(): if _is_global_greenlet():
return self._native.fileno() return self._native.fileno()
else: else:
# preventing use of gnu readline here # preventing use of gnu readline here
# https://github.com/python/cpython/blob/master/Python/bltinmodule.c#L1970 # https://github.com/python/cpython/blob/master/Python/bltinmodule.c#L1970
raise AttributeError raise AttributeError
def __getattr__(self, name): def __getattr__(self, name):
return getattr(self._native, name) return getattr(self._native, name)
class ComputerCraftFinder(MetaPathFinder): class ComputerCraftFinder(MetaPathFinder):
@staticmethod @staticmethod
def find_spec(fullname, path, target=None): def find_spec(fullname, path, target=None):
if fullname == 'cc': if fullname == 'cc':
return ModuleSpec(fullname, ComputerCraftLoader, is_package=True) return ModuleSpec(fullname, ComputerCraftLoader, is_package=True)
if fullname.startswith('cc.'): if fullname.startswith('cc.'):
return ModuleSpec(fullname, ComputerCraftLoader, is_package=False) return ModuleSpec(fullname, ComputerCraftLoader, is_package=False)
class ComputerCraftLoader(Loader): class ComputerCraftLoader(Loader):
@staticmethod @staticmethod
def create_module(spec): def create_module(spec):
sn = spec.name.split('.', 1) sn = spec.name.split('.', 1)
assert sn[0] == 'cc' assert sn[0] == 'cc'
if len(sn) == 1: if len(sn) == 1:
sn.append('_pkg') sn.append('_pkg')
rawmod = import_module('.' + sn[1], 'computercraft.subapis') rawmod = import_module('.' + sn[1], 'computercraft.subapis')
mod = ModuleType(spec.name) mod = ModuleType(spec.name)
for k in rawmod.__all__: for k in rawmod.__all__:
setattr(mod, k, getattr(rawmod, k)) setattr(mod, k, getattr(rawmod, k))
return mod return mod
@staticmethod @staticmethod
def exec_module(module): def exec_module(module):
pass pass
def install_import_hook(): def install_import_hook():
import sys import sys
sys.meta_path.append(ComputerCraftFinder) sys.meta_path.append(ComputerCraftFinder)
install_import_hook() install_import_hook()
@ -137,208 +137,208 @@ sys.stderr = StdFileProxy(sys.__stderr__, True)
def eval_lua(lua_code, *params, immediate=False): def eval_lua(lua_code, *params, immediate=False):
if isinstance(lua_code, str): if isinstance(lua_code, str):
lua_code = ser.encode(lua_code) lua_code = ser.encode(lua_code)
request = ( request = (
(b'I' if immediate else b'T') (b'I' if immediate else b'T')
+ ser.serialize(lua_code) + ser.serialize(lua_code)
+ ser.serialize(params) + ser.serialize(params)
) )
result = get_current_session()._server_greenlet.switch(request) result = get_current_session()._server_greenlet.switch(request)
rp = rproc.ResultProc(ser.deserialize(result)) rp = rproc.ResultProc(ser.deserialize(result))
if not immediate: if not immediate:
rp.check_bool_error() rp.check_bool_error()
return rp return rp
@contextmanager @contextmanager
def lua_context_object(create_expr: str, create_params: tuple, finalizer_template: str = ''): def lua_context_object(create_expr: str, create_params: tuple, finalizer_template: str = ''):
sess = get_current_session() sess = get_current_session()
fid = sess.create_task_id() fid = sess.create_task_id()
var = 'temp[{}]'.format(lua_string(fid)) var = 'temp[{}]'.format(lua_string(fid))
eval_lua('{} = {}'.format(var, create_expr), *create_params) eval_lua('{} = {}'.format(var, create_expr), *create_params)
try: try:
yield var yield var
finally: finally:
finalizer_template += '; {e} = nil' finalizer_template += '; {e} = nil'
finalizer_template = finalizer_template.lstrip(' ;') finalizer_template = finalizer_template.lstrip(' ;')
eval_lua(finalizer_template.format(e=var)) eval_lua(finalizer_template.format(e=var))
def eval_lua_method_factory(obj): def eval_lua_method_factory(obj):
def method(name, *params): def method(name, *params):
code = 'return ' + obj + name + '(...)' code = 'return ' + obj + name + '(...)'
return eval_lua(code, *params) return eval_lua(code, *params)
return method return method
class CCGreenlet: class CCGreenlet:
def __init__(self, body_fn, sess=None): def __init__(self, body_fn, sess=None):
if sess is None: if sess is None:
self._sess = get_current_session() self._sess = get_current_session()
else: else:
self._sess = sess self._sess = sess
self._task_id = self._sess.create_task_id() self._task_id = self._sess.create_task_id()
self._sess._greenlets[self._task_id] = self self._sess._greenlets[self._task_id] = self
parent_g = get_current_greenlet() parent_g = get_current_greenlet()
if parent_g is self._sess._server_greenlet: if parent_g is self._sess._server_greenlet:
self._parent = None self._parent = None
else: else:
self._parent = parent_g.cc_greenlet self._parent = parent_g.cc_greenlet
self._parent._children.add(self._task_id) self._parent._children.add(self._task_id)
self._children = set() self._children = set()
self._g = greenlet(body_fn) self._g = greenlet(body_fn)
self._g.cc_greenlet = self self._g.cc_greenlet = self
def detach_children(self): def detach_children(self):
if self._children: if self._children:
ch = list(self._children) ch = list(self._children)
self._children.clear() self._children.clear()
self._sess.drop(ch) self._sess.drop(ch)
def _on_death(self, error=None): def _on_death(self, error=None):
self._sess._greenlets.pop(self._task_id, None) self._sess._greenlets.pop(self._task_id, None)
self.detach_children() self.detach_children()
if error is not None: if error is not None:
if error is True: if error is True:
error = None error = None
else: else:
error = ser.dirty_encode(error) error = ser.dirty_encode(error)
self._sess._sender(b'C' + ser.serialize(error)) self._sess._sender(b'C' + ser.serialize(error))
if self._parent is not None: if self._parent is not None:
self._parent._children.discard(self._task_id) self._parent._children.discard(self._task_id)
def defer_switch(self, *args, **kwargs): def defer_switch(self, *args, **kwargs):
asyncio.get_running_loop().call_soon( asyncio.get_running_loop().call_soon(
partial(self.switch, *args, **kwargs)) partial(self.switch, *args, **kwargs))
def switch(self, *args, **kwargs): def switch(self, *args, **kwargs):
# switch must be called from server greenlet # switch must be called from server greenlet
assert get_current_greenlet() is self._sess._server_greenlet assert get_current_greenlet() is self._sess._server_greenlet
try: try:
task = self._g.switch(*args, **kwargs) task = self._g.switch(*args, **kwargs)
except SystemExit: except SystemExit:
self._on_death(True) self._on_death(True)
return return
except Exception: except Exception:
self._on_death(format_exc(limit=None, chain=False)) self._on_death(format_exc(limit=None, chain=False))
return return
# lua_eval call or simply idle # lua_eval call or simply idle
if isinstance(task, bytes): if isinstance(task, bytes):
x = self x = self
while x._g.dead: while x._g.dead:
x = x._parent x = x._parent
self._sess._sender(task[0:1] + ser.serialize(x._task_id) + task[1:]) self._sess._sender(task[0:1] + ser.serialize(x._task_id) + task[1:])
if self._g.dead: if self._g.dead:
if self._parent is None: if self._parent is None:
self._on_death(True) self._on_death(True)
else: else:
self._on_death() self._on_death()
class CCEventRouter: class CCEventRouter:
def __init__(self, on_first_sub, on_last_unsub, resume_task): def __init__(self, on_first_sub, on_last_unsub, resume_task):
self._stacks = {} self._stacks = {}
self._active = {} self._active = {}
self._on_first_sub = on_first_sub self._on_first_sub = on_first_sub
self._on_last_unsub = on_last_unsub self._on_last_unsub = on_last_unsub
self._resume_task = resume_task self._resume_task = resume_task
def sub(self, task_id, event): def sub(self, task_id, event):
if event not in self._stacks: if event not in self._stacks:
self._stacks[event] = {} self._stacks[event] = {}
self._on_first_sub(event) self._on_first_sub(event)
se = self._stacks[event] se = self._stacks[event]
if task_id in se: if task_id in se:
raise Exception('Same task subscribes to the same event twice') raise Exception('Same task subscribes to the same event twice')
se[task_id] = deque() se[task_id] = deque()
def unsub(self, task_id, event): def unsub(self, task_id, event):
if event not in self._stacks: if event not in self._stacks:
return return
self._stacks[event].pop(task_id, None) self._stacks[event].pop(task_id, None)
if len(self._stacks[event]) == 0: if len(self._stacks[event]) == 0:
self._on_last_unsub(event) self._on_last_unsub(event)
del self._stacks[event] del self._stacks[event]
def on_event(self, event, params): def on_event(self, event, params):
if event not in self._stacks: if event not in self._stacks:
self._on_last_unsub(event) self._on_last_unsub(event)
return return
for task_id, queue in self._stacks[event].items(): for task_id, queue in self._stacks[event].items():
queue.append(params) queue.append(params)
if self._active.get(task_id) == event: if self._active.get(task_id) == event:
self._set_task_status(task_id, event, False) self._set_task_status(task_id, event, False)
self._resume_task(task_id) self._resume_task(task_id)
def get_from_stack(self, task_id, event): def get_from_stack(self, task_id, event):
queue = self._stacks[event][task_id] queue = self._stacks[event][task_id]
try: try:
return queue.popleft() return queue.popleft()
except IndexError: except IndexError:
self._set_task_status(task_id, event, True) self._set_task_status(task_id, event, True)
return None return None
def _set_task_status(self, task_id, event, waits: bool): def _set_task_status(self, task_id, event, waits: bool):
if waits: if waits:
self._active[task_id] = event self._active[task_id] = event
else: else:
self._active.pop(task_id, None) self._active.pop(task_id, None)
class CCSession: class CCSession:
def __init__(self, computer_id, sender): def __init__(self, computer_id, sender):
# computer_id is unique identifier of a CCSession # computer_id is unique identifier of a CCSession
self._computer_id = computer_id self._computer_id = computer_id
self._tid_allocator = map(base36, count(start=1)) self._tid_allocator = map(base36, count(start=1))
self._sender = sender self._sender = sender
self._greenlets = {} self._greenlets = {}
self._server_greenlet = get_current_greenlet() self._server_greenlet = get_current_greenlet()
self._program_greenlet = None self._program_greenlet = None
self._evr = CCEventRouter( self._evr = CCEventRouter(
lambda event: self._sender(b'S' + ser.serialize(event)), lambda event: self._sender(b'S' + ser.serialize(event)),
lambda event: self._sender(b'U' + ser.serialize(event)), lambda event: self._sender(b'U' + ser.serialize(event)),
lambda task_id: self._greenlets[task_id].defer_switch('event'), lambda task_id: self._greenlets[task_id].defer_switch('event'),
) )
def on_task_result(self, task_id, result): def on_task_result(self, task_id, result):
assert get_current_greenlet() is self._server_greenlet assert get_current_greenlet() is self._server_greenlet
if task_id not in self._greenlets: if task_id not in self._greenlets:
# ignore for dropped tasks # ignore for dropped tasks
return return
self._greenlets[task_id].switch(result) self._greenlets[task_id].switch(result)
def on_event(self, event, params): def on_event(self, event, params):
self._evr.on_event(event, params) self._evr.on_event(event, params)
def create_task_id(self): def create_task_id(self):
return next(self._tid_allocator) return next(self._tid_allocator)
def drop(self, task_ids): def drop(self, task_ids):
def collect(task_id): def collect(task_id):
yield task_id yield task_id
g = self._greenlets.pop(task_id) g = self._greenlets.pop(task_id)
for tid in g._children: for tid in g._children:
yield from collect(tid) yield from collect(tid)
all_tids = [] all_tids = []
for task_id in task_ids: for task_id in task_ids:
all_tids.extend(collect(task_id)) all_tids.extend(collect(task_id))
self._sender(b'D' + b''.join(ser.serialize(tid) for tid in all_tids)) self._sender(b'D' + b''.join(ser.serialize(tid) for tid in all_tids))
def _run_sandboxed_greenlet(self, fn): def _run_sandboxed_greenlet(self, fn):
self._program_greenlet = CCGreenlet(fn, sess=self) self._program_greenlet = CCGreenlet(fn, sess=self)
self._program_greenlet.switch() self._program_greenlet.switch()
def run_program(self, program, args): def run_program(self, program, args):
def _run_program(): def _run_program():
rp = eval_lua(''' rp = eval_lua('''
local p = fs.combine(shell.dir(), ...) local p = fs.combine(shell.dir(), ...)
if not fs.exists(p) then return nil end if not fs.exists(p) then return nil end
if fs.isDir(p) then return nil end if fs.isDir(p) then return nil end
@ -347,20 +347,20 @@ local code = f.readAll()
f.close() f.close()
return p, code return p, code
'''.lstrip(), program) '''.lstrip(), program)
if rp.peek() is None: if rp.peek() is None:
print('Program not found', file=sys.stderr) print('Program not found', file=sys.stderr)
return return
p = rp.take_string() p = rp.take_string()
code = rp.take_string() code = rp.take_string()
cc = compile(code, p, 'exec') cc = compile(code, p, 'exec')
exec(cc, {'__file__': p, 'args': args}) exec(cc, {'__file__': p, 'args': args})
self._run_sandboxed_greenlet(_run_program) self._run_sandboxed_greenlet(_run_program)
def run_repl(self): def run_repl(self):
def _repl(): def _repl():
InteractiveConsole(locals={}).interact( InteractiveConsole(locals={}).interact(
banner='Python {}'.format(python_version()), banner='Python {}'.format(python_version()),
) )
self._run_sandboxed_greenlet(_repl) self._run_sandboxed_greenlet(_repl)

View file

@ -6,26 +6,26 @@ from ..sess import eval_lua
__all__ = ( __all__ = (
'import_file', 'import_file',
'is_commands', 'is_commands',
'is_multishell', 'is_multishell',
'is_turtle', 'is_turtle',
'is_pocket', 'is_pocket',
'eval_lua', 'eval_lua',
'LuaException', 'LuaException',
) )
def import_file(path: str, relative_to: str = None): def import_file(path: str, relative_to: str = None):
mod = ModuleType(path) mod = ModuleType(path)
mod.__file__ = path mod.__file__ = path
path_expr = lua_string(path) path_expr = lua_string(path)
if relative_to is not None: if relative_to is not None:
path_expr = 'fs.combine(fs.getDir({}), {})'.format( path_expr = 'fs.combine(fs.getDir({}), {})'.format(
lua_string(relative_to), lua_string(relative_to),
path_expr, path_expr,
) )
source = eval_lua(''' source = eval_lua('''
local p = {} local p = {}
if not fs.exists(p) then return nil end if not fs.exists(p) then return nil end
if fs.isDir(p) then return nil end if fs.isDir(p) then return nil end
@ -34,26 +34,26 @@ local src = f.readAll()
f.close() f.close()
return src return src
'''.lstrip().format( '''.lstrip().format(
path_expr, path_expr,
)).take_option_string() )).take_option_string()
if source is None: if source is None:
raise ImportError('File not found: {}'.format(path)) raise ImportError('File not found: {}'.format(path))
cc = compile(source, mod.__name__, 'exec') cc = compile(source, mod.__name__, 'exec')
exec(cc, vars(mod)) exec(cc, vars(mod))
return mod return mod
def is_commands() -> bool: def is_commands() -> bool:
return eval_lua('return commands ~= nil').take_bool() return eval_lua('return commands ~= nil').take_bool()
def is_multishell() -> bool: def is_multishell() -> bool:
return eval_lua('return multishell ~= nil').take_bool() return eval_lua('return multishell ~= nil').take_bool()
def is_turtle() -> bool: def is_turtle() -> bool:
return eval_lua('return turtle ~= nil').take_bool() return eval_lua('return turtle ~= nil').take_bool()
def is_pocket() -> bool: def is_pocket() -> bool:
return eval_lua('return pocket ~= nil').take_bool() return eval_lua('return pocket ~= nil').take_bool()

View file

@ -3,12 +3,12 @@ from ..sess import eval_lua
class BaseSubAPI(LuaExpr): class BaseSubAPI(LuaExpr):
def __init__(self, lua_expr): def __init__(self, lua_expr):
self._lua_expr = lua_expr self._lua_expr = lua_expr
def get_expr_code(self): def get_expr_code(self):
return self._lua_expr return self._lua_expr
def _method(self, name, *params): def _method(self, name, *params):
code = 'return {}.{}(...)'.format(self.get_expr_code(), name) code = 'return {}.{}(...)'.format(self.get_expr_code(), name)
return eval_lua(code, *params) return eval_lua(code, *params)

View file

@ -7,29 +7,29 @@ method = eval_lua_method_factory('colors.')
__all__ = ( __all__ = (
'white', 'white',
'orange', 'orange',
'magenta', 'magenta',
'lightBlue', 'lightBlue',
'yellow', 'yellow',
'lime', 'lime',
'pink', 'pink',
'gray', 'gray',
'lightGray', 'lightGray',
'cyan', 'cyan',
'purple', 'purple',
'blue', 'blue',
'brown', 'brown',
'green', 'green',
'red', 'red',
'black', 'black',
'combine', 'combine',
'subtract', 'subtract',
'test', 'test',
'packRGB', 'packRGB',
'unpackRGB', 'unpackRGB',
'chars', 'chars',
'iter_colors', 'iter_colors',
) )
@ -54,47 +54,47 @@ black = 0x8000
# combine, subtract and test are mostly for redstone.setBundledOutput # combine, subtract and test are mostly for redstone.setBundledOutput
def combine(*colors: int) -> int: def combine(*colors: int) -> int:
return method('combine', *colors).take_int() return method('combine', *colors).take_int()
def subtract(color_set: int, *colors: int) -> int: def subtract(color_set: int, *colors: int) -> int:
return method('subtract', color_set, *colors).take_int() return method('subtract', color_set, *colors).take_int()
def test(colors: int, color: int) -> bool: def test(colors: int, color: int) -> bool:
return method('test', colors, color).take_bool() return method('test', colors, color).take_bool()
def packRGB(r: float, g: float, b: float) -> int: def packRGB(r: float, g: float, b: float) -> int:
return method('packRGB', r, g, b).take_int() return method('packRGB', r, g, b).take_int()
def unpackRGB(rgb: int) -> Tuple[float, float, float]: def unpackRGB(rgb: int) -> Tuple[float, float, float]:
rp = method('unpackRGB', rgb) rp = method('unpackRGB', rgb)
return tuple(rp.take_number() for _ in range(3)) return tuple(rp.take_number() for _ in range(3))
# use these chars for term.blit # use these chars for term.blit
chars = { chars = {
'0': white, '0': white,
'1': orange, '1': orange,
'2': magenta, '2': magenta,
'3': lightBlue, '3': lightBlue,
'4': yellow, '4': yellow,
'5': lime, '5': lime,
'6': pink, '6': pink,
'7': gray, '7': gray,
'8': lightGray, '8': lightGray,
'9': cyan, '9': cyan,
'a': purple, 'a': purple,
'b': blue, 'b': blue,
'c': brown, 'c': brown,
'd': green, 'd': green,
'e': red, 'e': red,
'f': black, 'f': black,
} }
def iter_colors(): def iter_colors():
for c in chars.values(): for c in chars.values():
yield c yield c

View file

@ -8,34 +8,34 @@ method = eval_lua_method_factory('commands.')
__all__ = ( __all__ = (
'exec', 'exec',
'list', 'list',
'getBlockPosition', 'getBlockPosition',
'getBlockInfo', 'getBlockInfo',
'getBlockInfos', 'getBlockInfos',
) )
def exec(command: str) -> Tuple[bool, List[str], Optional[int]]: def exec(command: str) -> Tuple[bool, List[str], Optional[int]]:
rp = method('exec', ser.encode(command)) rp = method('exec', ser.encode(command))
success = rp.take_bool() success = rp.take_bool()
log = rp.take_list_of_strings() log = rp.take_list_of_strings()
n = rp.take_option_int() n = rp.take_option_int()
return success, log, n return success, log, n
def list() -> List[str]: def list() -> List[str]:
return method('list').take_list_of_strings() return method('list').take_list_of_strings()
def getBlockPosition() -> Tuple[int, int, int]: def getBlockPosition() -> Tuple[int, int, int]:
rp = method('getBlockPosition') rp = method('getBlockPosition')
return tuple(rp.take_int() for _ in range(3)) return tuple(rp.take_int() for _ in range(3))
def getBlockInfo(x: int, y: int, z: int) -> dict: def getBlockInfo(x: int, y: int, z: int) -> dict:
return method('getBlockInfo', x, y, z).take_dict() return method('getBlockInfo', x, y, z).take_dict()
def getBlockInfos(x1: int, y1: int, z1: int, x2: int, y2: int, z2: int) -> List[dict]: def getBlockInfos(x1: int, y1: int, z1: int, x2: int, y2: int, z2: int) -> List[dict]:
return method('getBlockInfos', x1, y1, z1, x2, y2, z2).take_list() return method('getBlockInfos', x1, y1, z1, x2, y2, z2).take_list()

View file

@ -8,59 +8,59 @@ method = eval_lua_method_factory('disk.')
__all__ = ( __all__ = (
'isPresent', 'isPresent',
'hasData', 'hasData',
'getMountPath', 'getMountPath',
'setLabel', 'setLabel',
'getLabel', 'getLabel',
'getID', 'getID',
'hasAudio', 'hasAudio',
'getAudioTitle', 'getAudioTitle',
'playAudio', 'playAudio',
'stopAudio', 'stopAudio',
'eject', 'eject',
) )
def isPresent(side: str) -> bool: def isPresent(side: str) -> bool:
return method('isPresent', ser.encode(side)).take_bool() return method('isPresent', ser.encode(side)).take_bool()
def hasData(side: str) -> bool: def hasData(side: str) -> bool:
return method('hasData', ser.encode(side)).take_bool() return method('hasData', ser.encode(side)).take_bool()
def getMountPath(side: str) -> Optional[str]: def getMountPath(side: str) -> Optional[str]:
return method('getMountPath', ser.encode(side)).take_option_string() return method('getMountPath', ser.encode(side)).take_option_string()
def setLabel(side: str, label: Optional[str]): def setLabel(side: str, label: Optional[str]):
return method('setLabel', ser.encode(side), ser.nil_encode(label)).take_none() return method('setLabel', ser.encode(side), ser.nil_encode(label)).take_none()
def getLabel(side: str) -> Optional[str]: def getLabel(side: str) -> Optional[str]:
return method('getLabel', ser.encode(side)).take_option_string() return method('getLabel', ser.encode(side)).take_option_string()
def getID(side: str) -> Optional[int]: def getID(side: str) -> Optional[int]:
return method('getID', ser.encode(side)).take_option_int() return method('getID', ser.encode(side)).take_option_int()
def hasAudio(side: str) -> bool: def hasAudio(side: str) -> bool:
return method('hasAudio', ser.encode(side)).take_bool() return method('hasAudio', ser.encode(side)).take_bool()
def getAudioTitle(side: str) -> Optional[Union[bool, str]]: def getAudioTitle(side: str) -> Optional[Union[bool, str]]:
return method('getAudioTitle', ser.encode(side)).take_option_string_bool() return method('getAudioTitle', ser.encode(side)).take_option_string_bool()
def playAudio(side: str): def playAudio(side: str):
return method('playAudio', ser.encode(side)).take_none() return method('playAudio', ser.encode(side)).take_none()
def stopAudio(side: str): def stopAudio(side: str):
return method('stopAudio', ser.encode(side)).take_none() return method('stopAudio', ser.encode(side)).take_none()
def eject(side: str): def eject(side: str):
return method('eject', ser.encode(side)).take_none() return method('eject', ser.encode(side)).take_none()

View file

@ -7,207 +7,207 @@ from ..sess import eval_lua_method_factory, lua_context_object
class SeekMixin: class SeekMixin:
def seek(self, whence: str = None, offset: int = None) -> int: def seek(self, whence: str = None, offset: int = None) -> int:
# whence: set, cur, end # whence: set, cur, end
rp = self._method('seek', ser.nil_encode(whence), offset) rp = self._method('seek', ser.nil_encode(whence), offset)
rp.check_nil_error() rp.check_nil_error()
return rp.take_int() return rp.take_int()
class ReadMixin: class ReadMixin:
def _take(self, rp): def _take(self, rp):
raise NotImplementedError raise NotImplementedError
def read(self, count: int = 1) -> Optional[str]: def read(self, count: int = 1) -> Optional[str]:
return self._take(self._method('read', count)) return self._take(self._method('read', count))
def readLine(self, withTrailing: bool = False) -> Optional[str]: def readLine(self, withTrailing: bool = False) -> Optional[str]:
return self._take(self._method('readLine', withTrailing)) return self._take(self._method('readLine', withTrailing))
def readAll(self) -> Optional[str]: def readAll(self) -> Optional[str]:
return self._take(self._method('readAll')) return self._take(self._method('readAll'))
def __iter__(self): def __iter__(self):
return self return self
def __next__(self): def __next__(self):
line = self.readLine() line = self.readLine()
if line is None: if line is None:
raise StopIteration raise StopIteration
return line return line
class WriteMixin: class WriteMixin:
def _put(self, t): def _put(self, t):
raise NotImplementedError raise NotImplementedError
def write(self, text: str): def write(self, text: str):
return self._method('write', self._put(text)).take_none() return self._method('write', self._put(text)).take_none()
def flush(self): def flush(self):
return self._method('flush').take_none() return self._method('flush').take_none()
class ReadHandle(ReadMixin, BaseSubAPI): class ReadHandle(ReadMixin, BaseSubAPI):
def _take(self, rp): def _take(self, rp):
return rp.take_option_unicode() return rp.take_option_unicode()
class BinaryReadHandle(ReadMixin, SeekMixin, BaseSubAPI): class BinaryReadHandle(ReadMixin, SeekMixin, BaseSubAPI):
def _take(self, rp): def _take(self, rp):
return rp.take_option_bytes() return rp.take_option_bytes()
class WriteHandle(WriteMixin, BaseSubAPI): class WriteHandle(WriteMixin, BaseSubAPI):
def _put(self, t: str) -> bytes: def _put(self, t: str) -> bytes:
return t.encode('utf-8') return t.encode('utf-8')
def writeLine(self, text: str): def writeLine(self, text: str):
return self.write(text + '\n') return self.write(text + '\n')
class BinaryWriteHandle(WriteMixin, SeekMixin, BaseSubAPI): class BinaryWriteHandle(WriteMixin, SeekMixin, BaseSubAPI):
def _put(self, b: bytes) -> bytes: def _put(self, b: bytes) -> bytes:
return b return b
method = eval_lua_method_factory('fs.') method = eval_lua_method_factory('fs.')
__all__ = ( __all__ = (
'list', 'list',
'exists', 'exists',
'isDir', 'isDir',
'isReadOnly', 'isReadOnly',
'getDrive', 'getDrive',
'getSize', 'getSize',
'getFreeSpace', 'getFreeSpace',
'getCapacity', 'getCapacity',
'makeDir', 'makeDir',
'move', 'move',
'copy', 'copy',
'delete', 'delete',
'combine', 'combine',
'open', 'open',
'find', 'find',
'getDir', 'getDir',
'getName', 'getName',
'isDriveRoot', 'isDriveRoot',
'complete', 'complete',
'attributes', 'attributes',
) )
def list(path: str) -> List[str]: def list(path: str) -> List[str]:
return method('list', ser.encode(path)).take_list_of_strings() return method('list', ser.encode(path)).take_list_of_strings()
def exists(path: str) -> bool: def exists(path: str) -> bool:
return method('exists', ser.encode(path)).take_bool() return method('exists', ser.encode(path)).take_bool()
def isDir(path: str) -> bool: def isDir(path: str) -> bool:
return method('isDir', ser.encode(path)).take_bool() return method('isDir', ser.encode(path)).take_bool()
def isReadOnly(path: str) -> bool: def isReadOnly(path: str) -> bool:
return method('isReadOnly', ser.encode(path)).take_bool() return method('isReadOnly', ser.encode(path)).take_bool()
def getDrive(path: str) -> Optional[str]: def getDrive(path: str) -> Optional[str]:
return method('getDrive', ser.encode(path)).take_option_string() return method('getDrive', ser.encode(path)).take_option_string()
def getSize(path: str) -> int: def getSize(path: str) -> int:
return method('getSize', ser.encode(path)).take_int() return method('getSize', ser.encode(path)).take_int()
def getFreeSpace(path: str) -> int: def getFreeSpace(path: str) -> int:
return method('getFreeSpace', ser.encode(path)).take_int() return method('getFreeSpace', ser.encode(path)).take_int()
def getCapacity(path: str) -> int: def getCapacity(path: str) -> int:
return method('getCapacity', ser.encode(path)).take_int() return method('getCapacity', ser.encode(path)).take_int()
def makeDir(path: str): def makeDir(path: str):
return method('makeDir', ser.encode(path)).take_none() return method('makeDir', ser.encode(path)).take_none()
def move(fromPath: str, toPath: str): def move(fromPath: str, toPath: str):
return method('move', ser.encode(fromPath), ser.encode(toPath)).take_none() return method('move', ser.encode(fromPath), ser.encode(toPath)).take_none()
def copy(fromPath: str, toPath: str): def copy(fromPath: str, toPath: str):
return method('copy', ser.encode(fromPath), ser.encode(toPath)).take_none() return method('copy', ser.encode(fromPath), ser.encode(toPath)).take_none()
def delete(path: str): def delete(path: str):
return method('delete', ser.encode(path)).take_none() return method('delete', ser.encode(path)).take_none()
def combine(basePath: str, localPath: str) -> str: def combine(basePath: str, localPath: str) -> str:
return method('combine', ser.encode(basePath), ser.encode(localPath)).take_string() return method('combine', ser.encode(basePath), ser.encode(localPath)).take_string()
@contextmanager @contextmanager
def open(path: str, mode: str): def open(path: str, mode: str):
''' '''
Usage: Usage:
with fs.open('filename', 'w') as f: with fs.open('filename', 'w') as f:
f.writeLine('textline') f.writeLine('textline')
with fs.open('filename', 'r') as f: with fs.open('filename', 'r') as f:
for line in f: for line in f:
... ...
''' '''
with lua_context_object( with lua_context_object(
'fs.open(...)', 'fs.open(...)',
(ser.encode(path), ser.encode(mode.replace('b', '') + 'b')), (ser.encode(path), ser.encode(mode.replace('b', '') + 'b')),
'{e}.close()', '{e}.close()',
) as var: ) as var:
if 'b' in mode: if 'b' in mode:
hcls = BinaryReadHandle if 'r' in mode else BinaryWriteHandle hcls = BinaryReadHandle if 'r' in mode else BinaryWriteHandle
else: else:
hcls = ReadHandle if 'r' in mode else WriteHandle hcls = ReadHandle if 'r' in mode else WriteHandle
yield hcls(var) yield hcls(var)
def find(wildcard: str) -> List[str]: def find(wildcard: str) -> List[str]:
return method('find', ser.encode(wildcard)).take_list_of_strings() return method('find', ser.encode(wildcard)).take_list_of_strings()
def getDir(path: str) -> str: def getDir(path: str) -> str:
return method('getDir', ser.encode(path)).take_string() return method('getDir', ser.encode(path)).take_string()
def getName(path: str) -> str: def getName(path: str) -> str:
return method('getName', ser.encode(path)).take_string() return method('getName', ser.encode(path)).take_string()
def isDriveRoot(path: str) -> bool: def isDriveRoot(path: str) -> bool:
return method('isDriveRoot', ser.encode(path)).take_bool() return method('isDriveRoot', ser.encode(path)).take_bool()
def complete( def complete(
partialName: str, path: str, includeFiles: bool = None, includeDirs: bool = None, partialName: str, path: str, includeFiles: bool = None, includeDirs: bool = None,
) -> List[str]: ) -> List[str]:
return method( return method(
'complete', ser.encode(partialName), ser.encode(path), includeFiles, includeDirs, 'complete', ser.encode(partialName), ser.encode(path), includeFiles, includeDirs,
).take_list_of_strings() ).take_list_of_strings()
def attributes(path: str) -> dict: def attributes(path: str) -> dict:
tp = method('attributes', ser.encode(path)).take_dict(( tp = method('attributes', ser.encode(path)).take_dict((
b'created', b'created',
b'modification', b'modification',
b'isDir', b'isDir',
b'size', b'size',
)) ))
r = {} r = {}
r['created'] = tp.take_int() r['created'] = tp.take_int()
r['modification'] = tp.take_int() r['modification'] = tp.take_int()
r['isDir'] = tp.take_bool() r['isDir'] = tp.take_bool()
r['size'] = tp.take_int() r['size'] = tp.take_int()
return r return r

View file

@ -8,8 +8,8 @@ method = eval_lua_method_factory('gps.')
__all__ = ( __all__ = (
'CHANNEL_GPS', 'CHANNEL_GPS',
'locate', 'locate',
) )
@ -17,7 +17,7 @@ CHANNEL_GPS = 65534
def locate(timeout: LuaNum = None, debug: bool = None) -> Optional[Tuple[LuaNum, LuaNum, LuaNum]]: def locate(timeout: LuaNum = None, debug: bool = None) -> Optional[Tuple[LuaNum, LuaNum, LuaNum]]:
rp = method('locate', timeout, debug) rp = method('locate', timeout, debug)
if rp.peek() is None: if rp.peek() is None:
return None return None
return tuple(rp.take_number() for _ in range(3)) return tuple(rp.take_number() for _ in range(3))

View file

@ -8,29 +8,29 @@ method = eval_lua_method_factory('help.')
__all__ = ( __all__ = (
'path', 'path',
'setPath', 'setPath',
'lookup', 'lookup',
'topics', 'topics',
'completeTopic', 'completeTopic',
) )
def path() -> str: def path() -> str:
return method('path').take_string() return method('path').take_string()
def setPath(path: str): def setPath(path: str):
return method('setPath', ser.encode(path)).take_none() return method('setPath', ser.encode(path)).take_none()
def lookup(topic: str) -> Optional[str]: def lookup(topic: str) -> Optional[str]:
return method('lookup', ser.encode(topic)).take_option_string() return method('lookup', ser.encode(topic)).take_option_string()
def topics() -> List[str]: def topics() -> List[str]:
return method('topics').take_list_of_strings() return method('topics').take_list_of_strings()
def completeTopic(topicPrefix: str) -> List[str]: def completeTopic(topicPrefix: str) -> List[str]:
return method('completeTopic', ser.encode(topicPrefix)).take_list_of_strings() return method('completeTopic', ser.encode(topicPrefix)).take_list_of_strings()

View file

@ -8,21 +8,21 @@ method = eval_lua_method_factory('keys.')
__all__ = ( __all__ = (
'getCode', 'getCode',
'getName', 'getName',
) )
def getCode(name: str) -> Optional[int]: def getCode(name: str) -> Optional[int]:
# replaces properties # replaces properties
# keys.space → keys.getCode('space') # keys.space → keys.getCode('space')
return eval_lua(''' return eval_lua('''
local k = ... local k = ...
if type(keys[k]) == 'number' then if type(keys[k]) == 'number' then
return keys[k] return keys[k]
end end
return nil''', ser.encode(name)).take_option_int() return nil''', ser.encode(name)).take_option_int()
def getName(code: int) -> Optional[str]: def getName(code: int) -> Optional[str]:
return method('getName', code).take_option_string() return method('getName', code).take_option_string()

View file

@ -5,64 +5,64 @@ from ..lua import LuaExpr
class TermMixin: class TermMixin:
def write(self, text: str): def write(self, text: str):
return self._method('write', ser.dirty_encode(text)).take_none() return self._method('write', ser.dirty_encode(text)).take_none()
def blit(self, text: str, textColors: bytes, backgroundColors: bytes): def blit(self, text: str, textColors: bytes, backgroundColors: bytes):
return self._method('blit', ser.dirty_encode(text), textColors, backgroundColors).take_none() return self._method('blit', ser.dirty_encode(text), textColors, backgroundColors).take_none()
def clear(self): def clear(self):
return self._method('clear').take_none() return self._method('clear').take_none()
def clearLine(self): def clearLine(self):
return self._method('clearLine').take_none() return self._method('clearLine').take_none()
def getCursorPos(self) -> Tuple[int, int]: def getCursorPos(self) -> Tuple[int, int]:
rp = self._method('getCursorPos') rp = self._method('getCursorPos')
return tuple(rp.take_int() for _ in range(2)) return tuple(rp.take_int() for _ in range(2))
def setCursorPos(self, x: int, y: int): def setCursorPos(self, x: int, y: int):
return self._method('setCursorPos', x, y).take_none() return self._method('setCursorPos', x, y).take_none()
def getCursorBlink(self) -> bool: def getCursorBlink(self) -> bool:
return self._method('getCursorBlink').take_bool() return self._method('getCursorBlink').take_bool()
def setCursorBlink(self, value: bool): def setCursorBlink(self, value: bool):
return self._method('setCursorBlink', value).take_none() return self._method('setCursorBlink', value).take_none()
def isColor(self) -> bool: def isColor(self) -> bool:
return self._method('isColor').take_bool() return self._method('isColor').take_bool()
def getSize(self) -> Tuple[int, int]: def getSize(self) -> Tuple[int, int]:
rp = self._method('getSize') rp = self._method('getSize')
return tuple(rp.take_int() for _ in range(2)) return tuple(rp.take_int() for _ in range(2))
def scroll(self, lines: int): def scroll(self, lines: int):
return self._method('scroll', lines).take_none() return self._method('scroll', lines).take_none()
def setTextColor(self, colorID: int): def setTextColor(self, colorID: int):
return self._method('setTextColor', colorID).take_none() return self._method('setTextColor', colorID).take_none()
def getTextColor(self) -> int: def getTextColor(self) -> int:
return self._method('getTextColor').take_int() return self._method('getTextColor').take_int()
def setBackgroundColor(self, colorID: int): def setBackgroundColor(self, colorID: int):
return self._method('setBackgroundColor', colorID).take_none() return self._method('setBackgroundColor', colorID).take_none()
def getBackgroundColor(self) -> int: def getBackgroundColor(self) -> int:
return self._method('getBackgroundColor').take_int() return self._method('getBackgroundColor').take_int()
def getPaletteColor(self, colorID: int) -> Tuple[float, float, float]: def getPaletteColor(self, colorID: int) -> Tuple[float, float, float]:
rp = self._method('getPaletteColor', colorID) rp = self._method('getPaletteColor', colorID)
return tuple(rp.take_number() for _ in range(3)) return tuple(rp.take_number() for _ in range(3))
def setPaletteColor(self, colorID: int, r: float, g: float, b: float): def setPaletteColor(self, colorID: int, r: float, g: float, b: float):
return self._method('setPaletteColor', colorID, r, g, b).take_none() return self._method('setPaletteColor', colorID, r, g, b).take_none()
class TermTarget(LuaExpr): class TermTarget(LuaExpr):
def __init__(self, code): def __init__(self, code):
self._code = code self._code = code
def get_expr_code(self): def get_expr_code(self):
return self._code return self._code

View file

@ -8,40 +8,40 @@ method = eval_lua_method_factory('multishell.')
__all__ = ( __all__ = (
'getCurrent', 'getCurrent',
'getCount', 'getCount',
'launch', 'launch',
'setTitle', 'setTitle',
'getTitle', 'getTitle',
'setFocus', 'setFocus',
'getFocus', 'getFocus',
) )
def getCurrent() -> int: def getCurrent() -> int:
return method('getCurrent').take_int() return method('getCurrent').take_int()
def getCount() -> int: def getCount() -> int:
return method('getCount').take_int() return method('getCount').take_int()
def launch(environment: dict, programPath: str, *args: str) -> int: def launch(environment: dict, programPath: str, *args: str) -> int:
args = tuple(ser.encode(a) for a in args) args = tuple(ser.encode(a) for a in args)
return method('launch', environment, ser.encode(programPath), *args).take_int() return method('launch', environment, ser.encode(programPath), *args).take_int()
def setTitle(tabID: int, title: str): def setTitle(tabID: int, title: str):
return method('setTitle', tabID, ser.encode(title)).take_none() return method('setTitle', tabID, ser.encode(title)).take_none()
def getTitle(tabID: int) -> Optional[str]: def getTitle(tabID: int) -> Optional[str]:
return method('getTitle', tabID).take_option_string() return method('getTitle', tabID).take_option_string()
def setFocus(tabID: int) -> bool: def setFocus(tabID: int) -> bool:
return method('setFocus', tabID).take_bool() return method('setFocus', tabID).take_bool()
def getFocus() -> int: def getFocus() -> int:
return method('getFocus').take_int() return method('getFocus').take_int()

View file

@ -9,73 +9,73 @@ method = eval_lua_method_factory('os.')
__all__ = ( __all__ = (
'version', 'version',
'getComputerID', 'getComputerID',
'getComputerLabel', 'getComputerLabel',
'setComputerLabel', 'setComputerLabel',
'run', 'run',
'captureEvent', 'captureEvent',
'queueEvent', 'queueEvent',
'clock', 'clock',
'time', 'time',
'day', 'day',
'epoch', 'epoch',
'sleep', 'sleep',
'startTimer', 'startTimer',
'cancelTimer', 'cancelTimer',
'setAlarm', 'setAlarm',
'cancelAlarm', 'cancelAlarm',
'shutdown', 'shutdown',
'reboot', 'reboot',
) )
def version() -> str: def version() -> str:
return method('version').take_string() return method('version').take_string()
def getComputerID() -> int: def getComputerID() -> int:
return method('getComputerID').take_int() return method('getComputerID').take_int()
def getComputerLabel() -> Optional[str]: def getComputerLabel() -> Optional[str]:
return method('getComputerLabel').take_option_string() return method('getComputerLabel').take_option_string()
def setComputerLabel(label: Optional[str]): def setComputerLabel(label: Optional[str]):
return method('setComputerLabel', ser.nil_encode(label)).take_none() return method('setComputerLabel', ser.nil_encode(label)).take_none()
def run(environment: dict, programPath: str, *args: str): def run(environment: dict, programPath: str, *args: str):
args = tuple(ser.encode(a) for a in args) args = tuple(ser.encode(a) for a in args)
return method('run', environment, ser.encode(programPath), *args).take_bool() return method('run', environment, ser.encode(programPath), *args).take_bool()
def captureEvent(event: str): def captureEvent(event: str):
event = ser.encode(event) event = ser.encode(event)
glet = get_current_greenlet().cc_greenlet glet = get_current_greenlet().cc_greenlet
sess = glet._sess sess = glet._sess
evr = sess._evr evr = sess._evr
evr.sub(glet._task_id, event) evr.sub(glet._task_id, event)
try: try:
while True: while True:
val = evr.get_from_stack(glet._task_id, event) val = evr.get_from_stack(glet._task_id, event)
if val is None: if val is None:
res = sess._server_greenlet.switch() res = sess._server_greenlet.switch()
assert res == 'event' assert res == 'event'
else: else:
yield val yield val
finally: finally:
evr.unsub(glet._task_id, event) evr.unsub(glet._task_id, event)
def queueEvent(event: str, *params): def queueEvent(event: str, *params):
return method('queueEvent', ser.encode(event), *params).take_none() return method('queueEvent', ser.encode(event), *params).take_none()
def clock() -> LuaNum: def clock() -> LuaNum:
# number of game ticks * 0.05, roughly seconds # number of game ticks * 0.05, roughly seconds
return method('clock').take_number() return method('clock').take_number()
# regarding ingame parameter below: # regarding ingame parameter below:
@ -83,43 +83,43 @@ def clock() -> LuaNum:
# we keep here only in-game time methods and parameters # we keep here only in-game time methods and parameters
def time() -> LuaNum: def time() -> LuaNum:
# in hours 0..24 # in hours 0..24
return method('time', b'ingame').take_number() return method('time', b'ingame').take_number()
def day() -> int: def day() -> int:
return method('day', b'ingame').take_int() return method('day', b'ingame').take_int()
def epoch() -> int: def epoch() -> int:
return method('epoch', b'ingame').take_int() return method('epoch', b'ingame').take_int()
def sleep(seconds: LuaNum): def sleep(seconds: LuaNum):
return method('sleep', seconds).take_none() return method('sleep', seconds).take_none()
def startTimer(timeout: LuaNum) -> int: def startTimer(timeout: LuaNum) -> int:
return method('startTimer', timeout).take_int() return method('startTimer', timeout).take_int()
def cancelTimer(timerID: int): def cancelTimer(timerID: int):
return method('cancelTimer', timerID).take_none() return method('cancelTimer', timerID).take_none()
def setAlarm(time: LuaNum) -> int: def setAlarm(time: LuaNum) -> int:
# takes time of the day in hours 0..24 # takes time of the day in hours 0..24
# returns integer alarmID # returns integer alarmID
return method('setAlarm', time).take_int() return method('setAlarm', time).take_int()
def cancelAlarm(alarmID: int): def cancelAlarm(alarmID: int):
return method('cancelAlarm', alarmID).take_none() return method('cancelAlarm', alarmID).take_none()
def shutdown(): def shutdown():
return method('shutdown').take_none() return method('shutdown').take_none()
def reboot(): def reboot():
return method('reboot').take_none() return method('reboot').take_none()

View file

@ -8,39 +8,39 @@ method = eval_lua_method_factory('paintutils.')
__all__ = ( __all__ = (
'parseImage', 'parseImage',
'loadImage', 'loadImage',
'drawPixel', 'drawPixel',
'drawLine', 'drawLine',
'drawBox', 'drawBox',
'drawFilledBox', 'drawFilledBox',
'drawImage', 'drawImage',
) )
def parseImage(data: bytes) -> List[List[int]]: def parseImage(data: bytes) -> List[List[int]]:
return method('parseImage', data).take_2d_int() return method('parseImage', data).take_2d_int()
def loadImage(path: str) -> List[List[int]]: def loadImage(path: str) -> List[List[int]]:
return method('loadImage', ser.encode(path)).take_2d_int() return method('loadImage', ser.encode(path)).take_2d_int()
def drawPixel(x: int, y: int, color: int = None): def drawPixel(x: int, y: int, color: int = None):
return method('drawPixel', x, y, color).take_none() return method('drawPixel', x, y, color).take_none()
def drawLine(startX: int, startY: int, endX: int, endY: int, color: int = None): def drawLine(startX: int, startY: int, endX: int, endY: int, color: int = None):
return method('drawLine', startX, startY, endX, endY, color).take_none() return method('drawLine', startX, startY, endX, endY, color).take_none()
def drawBox(startX: int, startY: int, endX: int, endY: int, color: int = None): def drawBox(startX: int, startY: int, endX: int, endY: int, color: int = None):
return method('drawBox', startX, startY, endX, endY, color).take_none() return method('drawBox', startX, startY, endX, endY, color).take_none()
def drawFilledBox(startX: int, startY: int, endX: int, endY: int, color: int = None): def drawFilledBox(startX: int, startY: int, endX: int, endY: int, color: int = None):
return method('drawFilledBox', startX, startY, endX, endY, color).take_none() return method('drawFilledBox', startX, startY, endX, endY, color).take_none()
def drawImage(image: List[List[int]], xPos: int, yPos: int): def drawImage(image: List[List[int]], xPos: int, yPos: int):
return method('drawImage', image, xPos, yPos).take_none() return method('drawImage', image, xPos, yPos).take_none()

View file

@ -2,35 +2,35 @@ from ..sess import CCGreenlet, get_current_greenlet
__all__ = ( __all__ = (
'waitForAny', 'waitForAny',
'waitForAll', 'waitForAll',
) )
def waitForAny(*task_fns): def waitForAny(*task_fns):
pgl = get_current_greenlet().cc_greenlet pgl = get_current_greenlet().cc_greenlet
sess = pgl._sess sess = pgl._sess
gs = [CCGreenlet(fn) for fn in task_fns] gs = [CCGreenlet(fn) for fn in task_fns]
for g in gs: for g in gs:
g.defer_switch() g.defer_switch()
try: try:
sess._server_greenlet.switch() sess._server_greenlet.switch()
finally: finally:
pgl.detach_children() pgl.detach_children()
def waitForAll(*task_fns): def waitForAll(*task_fns):
pgl = get_current_greenlet().cc_greenlet pgl = get_current_greenlet().cc_greenlet
sess = pgl._sess sess = pgl._sess
gs = [CCGreenlet(fn) for fn in task_fns] gs = [CCGreenlet(fn) for fn in task_fns]
for g in gs: for g in gs:
g.defer_switch() g.defer_switch()
try: try:
for _ in range(len(task_fns)): for _ in range(len(task_fns)):
sess._server_greenlet.switch() sess._server_greenlet.switch()
finally: finally:
pgl.detach_children() pgl.detach_children()

View file

@ -8,262 +8,262 @@ from ..sess import eval_lua, eval_lua_method_factory
class BasePeripheral: class BasePeripheral:
# NOTE: is not LuaExpr, you can't pass peripheral as parameter # NOTE: is not LuaExpr, you can't pass peripheral as parameter
# TODO: to fix this we can supply separate lua expr, result of .wrap() # TODO: to fix this we can supply separate lua expr, result of .wrap()
def __init__(self, lua_method_expr, *prepend_params): def __init__(self, lua_method_expr, *prepend_params):
self._lua_method_expr = lua_method_expr self._lua_method_expr = lua_method_expr
self._prepend_params = prepend_params self._prepend_params = prepend_params
def _method(self, name, *params): def _method(self, name, *params):
code = 'return ' + self._lua_method_expr + '(...)' code = 'return ' + self._lua_method_expr + '(...)'
return eval_lua(code, *self._prepend_params, ser.encode(name), *params) return eval_lua(code, *self._prepend_params, ser.encode(name), *params)
class CCDrive(BasePeripheral): class CCDrive(BasePeripheral):
def isDiskPresent(self) -> bool: def isDiskPresent(self) -> bool:
return self._method('isDiskPresent').take_bool() return self._method('isDiskPresent').take_bool()
def getDiskLabel(self) -> Optional[str]: def getDiskLabel(self) -> Optional[str]:
return self._method('getDiskLabel').take_option_string() return self._method('getDiskLabel').take_option_string()
def setDiskLabel(self, label: Optional[str]): def setDiskLabel(self, label: Optional[str]):
return self._method('setDiskLabel', ser.nil_encode(label)).take_none() return self._method('setDiskLabel', ser.nil_encode(label)).take_none()
def hasData(self) -> bool: def hasData(self) -> bool:
return self._method('hasData').take_bool() return self._method('hasData').take_bool()
def getMountPath(self) -> Optional[str]: def getMountPath(self) -> Optional[str]:
return self._method('getMountPath').take_option_string() return self._method('getMountPath').take_option_string()
def hasAudio(self) -> bool: def hasAudio(self) -> bool:
return self._method('hasAudio').take_bool() return self._method('hasAudio').take_bool()
def getAudioTitle(self) -> Optional[Union[bool, str]]: def getAudioTitle(self) -> Optional[Union[bool, str]]:
return self._method('getAudioTitle').take_option_string_bool() return self._method('getAudioTitle').take_option_string_bool()
def playAudio(self): def playAudio(self):
return self._method('playAudio').take_none() return self._method('playAudio').take_none()
def stopAudio(self): def stopAudio(self):
return self._method('stopAudio').take_none() return self._method('stopAudio').take_none()
def ejectDisk(self): def ejectDisk(self):
return self._method('ejectDisk').take_none() return self._method('ejectDisk').take_none()
def getDiskID(self) -> Optional[int]: def getDiskID(self) -> Optional[int]:
return self._method('getDiskID').take_option_int() return self._method('getDiskID').take_option_int()
class CCMonitor(BasePeripheral, TermMixin): class CCMonitor(BasePeripheral, TermMixin):
def getTextScale(self) -> int: def getTextScale(self) -> int:
return self._method('getTextScale').take_int() return self._method('getTextScale').take_int()
def setTextScale(self, scale: int): def setTextScale(self, scale: int):
return self._method('setTextScale', scale).take_none() return self._method('setTextScale', scale).take_none()
class ComputerMixin: class ComputerMixin:
def turnOn(self): def turnOn(self):
return self._method('turnOn').take_none() return self._method('turnOn').take_none()
def shutdown(self): def shutdown(self):
return self._method('shutdown').take_none() return self._method('shutdown').take_none()
def reboot(self): def reboot(self):
return self._method('reboot').take_none() return self._method('reboot').take_none()
def getID(self) -> int: def getID(self) -> int:
return self._method('getID').take_int() return self._method('getID').take_int()
def getLabel(self) -> Optional[str]: def getLabel(self) -> Optional[str]:
return self._method('getLabel').take_option_string() return self._method('getLabel').take_option_string()
def isOn(self) -> bool: def isOn(self) -> bool:
return self._method('isOn').take_bool() return self._method('isOn').take_bool()
class CCComputer(BasePeripheral, ComputerMixin): class CCComputer(BasePeripheral, ComputerMixin):
pass pass
class CCTurtle(BasePeripheral, ComputerMixin): class CCTurtle(BasePeripheral, ComputerMixin):
pass pass
@dataclass @dataclass
class ModemMessage: class ModemMessage:
reply_channel: int reply_channel: int
content: Any content: Any
distance: LuaNum distance: LuaNum
class ModemMixin: class ModemMixin:
def isOpen(self, channel: int) -> bool: def isOpen(self, channel: int) -> bool:
return self._method('isOpen', channel).take_bool() return self._method('isOpen', channel).take_bool()
def open(self, channel: int): def open(self, channel: int):
return self._method('open', channel).take_none() return self._method('open', channel).take_none()
def close(self, channel: int): def close(self, channel: int):
return self._method('close', channel).take_none() return self._method('close', channel).take_none()
def closeAll(self): def closeAll(self):
return self._method('closeAll').take_none() return self._method('closeAll').take_none()
def transmit(self, channel: int, replyChannel: int, message: Any): def transmit(self, channel: int, replyChannel: int, message: Any):
return self._method('transmit', channel, replyChannel, message).take_none() return self._method('transmit', channel, replyChannel, message).take_none()
def isWireless(self) -> bool: def isWireless(self) -> bool:
return self._method('isWireless').take_bool() return self._method('isWireless').take_bool()
@property @property
def _side(self): def _side(self):
return self._prepend_params[0] return self._prepend_params[0]
def receive(self, channel: int): def receive(self, channel: int):
from .os import captureEvent from .os import captureEvent
if self.isOpen(channel): if self.isOpen(channel):
raise Exception('Channel is busy') raise Exception('Channel is busy')
self.open(channel) self.open(channel)
try: try:
for evt in captureEvent('modem_message'): for evt in captureEvent('modem_message'):
if evt[0] != self._side: if evt[0] != self._side:
continue continue
if evt[1] != channel: if evt[1] != channel:
continue continue
yield ModemMessage(*evt[2:]) yield ModemMessage(*evt[2:])
finally: finally:
self.close(channel) self.close(channel)
class CCWirelessModem(BasePeripheral, ModemMixin): class CCWirelessModem(BasePeripheral, ModemMixin):
pass pass
class CCWiredModem(BasePeripheral, ModemMixin): class CCWiredModem(BasePeripheral, ModemMixin):
def getNameLocal(self) -> Optional[str]: def getNameLocal(self) -> Optional[str]:
return self._method('getNameLocal').take_option_string() return self._method('getNameLocal').take_option_string()
def getNamesRemote(self) -> List[str]: def getNamesRemote(self) -> List[str]:
return self._method('getNamesRemote').take_list_of_strings() return self._method('getNamesRemote').take_list_of_strings()
def getTypeRemote(self, peripheralName: str) -> Optional[str]: def getTypeRemote(self, peripheralName: str) -> Optional[str]:
return self._method('getTypeRemote', ser.encode(peripheralName)).take_option_string() return self._method('getTypeRemote', ser.encode(peripheralName)).take_option_string()
def isPresentRemote(self, peripheralName: str) -> bool: def isPresentRemote(self, peripheralName: str) -> bool:
return self._method('isPresentRemote', ser.encode(peripheralName)).take_bool() return self._method('isPresentRemote', ser.encode(peripheralName)).take_bool()
def wrapRemote(self, peripheralName: str) -> Optional[BasePeripheral]: def wrapRemote(self, peripheralName: str) -> Optional[BasePeripheral]:
# use instead getMethodsRemote and callRemote # use instead getMethodsRemote and callRemote
# NOTE: you can also use peripheral.wrap(peripheralName) # NOTE: you can also use peripheral.wrap(peripheralName)
ptype = self.getTypeRemote(peripheralName) ptype = self.getTypeRemote(peripheralName)
if ptype is None: if ptype is None:
return None return None
return TYPE_MAP[ptype]( return TYPE_MAP[ptype](
self._lua_method_expr, *self._prepend_params, self._lua_method_expr, *self._prepend_params,
b'callRemote', ser.encode(peripheralName), b'callRemote', ser.encode(peripheralName),
) )
# NOTE: for TermTarget use peripheral.get_term_target(peripheralName) # NOTE: for TermTarget use peripheral.get_term_target(peripheralName)
class CCPrinter(BasePeripheral): class CCPrinter(BasePeripheral):
def newPage(self) -> bool: def newPage(self) -> bool:
return self._method('newPage').take_bool() return self._method('newPage').take_bool()
def endPage(self) -> bool: def endPage(self) -> bool:
return self._method('endPage').take_bool() return self._method('endPage').take_bool()
def write(self, text: str): def write(self, text: str):
return self._method('write', ser.dirty_encode(text)).take_none() return self._method('write', ser.dirty_encode(text)).take_none()
def setCursorPos(self, x: int, y: int): def setCursorPos(self, x: int, y: int):
return self._method('setCursorPos', x, y).take_none() return self._method('setCursorPos', x, y).take_none()
def getCursorPos(self) -> Tuple[int, int]: def getCursorPos(self) -> Tuple[int, int]:
rp = self._method('getCursorPos') rp = self._method('getCursorPos')
return tuple(rp.take_int() for _ in range(2)) return tuple(rp.take_int() for _ in range(2))
def getPageSize(self) -> Tuple[int, int]: def getPageSize(self) -> Tuple[int, int]:
rp = self._method('getPageSize') rp = self._method('getPageSize')
return tuple(rp.take_int() for _ in range(2)) return tuple(rp.take_int() for _ in range(2))
def setPageTitle(self, title: str): def setPageTitle(self, title: str):
return self._method('setPageTitle', ser.encode(title)).take_none() return self._method('setPageTitle', ser.encode(title)).take_none()
def getPaperLevel(self) -> int: def getPaperLevel(self) -> int:
return self._method('getPaperLevel').take_int() return self._method('getPaperLevel').take_int()
def getInkLevel(self) -> int: def getInkLevel(self) -> int:
return self._method('getInkLevel').take_int() return self._method('getInkLevel').take_int()
class CCSpeaker(BasePeripheral): class CCSpeaker(BasePeripheral):
def playNote(self, instrument: str, volume: int = 1, pitch: int = 1) -> bool: def playNote(self, instrument: str, volume: int = 1, pitch: int = 1) -> bool:
# instrument: # instrument:
# https://minecraft.gamepedia.com/Note_Block#Instruments # https://minecraft.gamepedia.com/Note_Block#Instruments
# bass # bass
# basedrum # basedrum
# bell # bell
# chime # chime
# flute # flute
# guitar # guitar
# hat # hat
# snare # snare
# xylophone # xylophone
# iron_xylophone # iron_xylophone
# pling # pling
# banjo # banjo
# bit # bit
# didgeridoo # didgeridoo
# cow_bell # cow_bell
# volume 0..3 # volume 0..3
# pitch 0..24 # pitch 0..24
return self._method('playNote', ser.encode(instrument), volume, pitch).take_bool() return self._method('playNote', ser.encode(instrument), volume, pitch).take_bool()
def playSound(self, sound: str, volume: int = 1, pitch: int = 1) -> bool: def playSound(self, sound: str, volume: int = 1, pitch: int = 1) -> bool:
# volume 0..3 # volume 0..3
# pitch 0..2 # pitch 0..2
return self._method('playSound', ser.encode(sound), volume, pitch).take_bool() return self._method('playSound', ser.encode(sound), volume, pitch).take_bool()
class CCCommandBlock(BasePeripheral): class CCCommandBlock(BasePeripheral):
def getCommand(self) -> str: def getCommand(self) -> str:
return self._method('getCommand').take_string() return self._method('getCommand').take_string()
def setCommand(self, command: str): def setCommand(self, command: str):
return self._method('setCommand', ser.encode(command)).take_none() return self._method('setCommand', ser.encode(command)).take_none()
def runCommand(self): def runCommand(self):
return self._method('runCommand').check_bool_error() return self._method('runCommand').check_bool_error()
class CCWorkbench(BasePeripheral): class CCWorkbench(BasePeripheral):
def craft(self, quantity: int = 64): def craft(self, quantity: int = 64):
return self._method('craft', quantity).check_bool_error() return self._method('craft', quantity).check_bool_error()
class CCInventory(BasePeripheral): class CCInventory(BasePeripheral):
def getItemDetail(self, slot: int) -> Optional[dict]: def getItemDetail(self, slot: int) -> Optional[dict]:
return self._method('getItemDetail', slot).take() return self._method('getItemDetail', slot).take()
def list(self) -> Dict[int, dict]: def list(self) -> Dict[int, dict]:
return self._method('list').take_dict() return self._method('list').take_dict()
def pullItems(self, fromName: str, fromSlot: int, limit: int = None, toSlot: int = None) -> int: def pullItems(self, fromName: str, fromSlot: int, limit: int = None, toSlot: int = None) -> int:
return self._method('pullItems', ser.encode(fromName), fromSlot, limit, toSlot).take_int() return self._method('pullItems', ser.encode(fromName), fromSlot, limit, toSlot).take_int()
def pushItems(self, toName: str, fromSlot: int, limit: int = None, toSlot: int = None) -> int: def pushItems(self, toName: str, fromSlot: int, limit: int = None, toSlot: int = None) -> int:
return self._method('pushItems', ser.encode(toName), fromSlot, limit, toSlot).take_int() return self._method('pushItems', ser.encode(toName), fromSlot, limit, toSlot).take_int()
def size(self) -> int: def size(self) -> int:
return self._method('size').take_int() return self._method('size').take_int()
TYPE_MAP = {} TYPE_MAP = {}
@ -273,55 +273,55 @@ method = eval_lua_method_factory('peripheral.')
__all__ = ( __all__ = (
'BasePeripheral', # exposed for subclassing & registerType 'BasePeripheral', # exposed for subclassing & registerType
'CCInventory', # exposed for registerType for 3rdparty mod inventory-like entities 'CCInventory', # exposed for registerType for 3rdparty mod inventory-like entities
'isPresent', 'isPresent',
'getType', 'getType',
'getNames', 'getNames',
'wrap', 'wrap',
'registerType', 'registerType',
'get_term_target', 'get_term_target',
) )
def isPresent(side: str) -> bool: def isPresent(side: str) -> bool:
return method('isPresent', ser.encode(side)).take_bool() return method('isPresent', ser.encode(side)).take_bool()
def getType(side: str) -> Optional[str]: def getType(side: str) -> Optional[str]:
return method('getType', ser.encode(side)).take_option_string() return method('getType', ser.encode(side)).take_option_string()
def getNames() -> List[str]: def getNames() -> List[str]:
return method('getNames').take_list_of_strings() return method('getNames').take_list_of_strings()
# use instead getMethods and call # use instead getMethods and call
def wrap(side: str) -> Optional[BasePeripheral]: def wrap(side: str) -> Optional[BasePeripheral]:
ptype = getType(side) ptype = getType(side)
if ptype is None: if ptype is None:
return None return None
m = 'peripheral.call' m = 'peripheral.call'
side = ser.encode(side) side = ser.encode(side)
if ptype == 'modem': if ptype == 'modem':
if method('call', side, b'isWireless').take_bool(): if method('call', side, b'isWireless').take_bool():
return CCWirelessModem(m, side) return CCWirelessModem(m, side)
else: else:
return CCWiredModem(m, side) return CCWiredModem(m, side)
else: else:
return TYPE_MAP[ptype](m, side) return TYPE_MAP[ptype](m, side)
def registerType(ptype: str, pcls: Type[BasePeripheral]): def registerType(ptype: str, pcls: Type[BasePeripheral]):
TYPE_MAP[ptype] = pcls TYPE_MAP[ptype] = pcls
def get_term_target(side: str) -> TermTarget: def get_term_target(side: str) -> TermTarget:
return TermTarget('peripheral.wrap({})'.format( return TermTarget('peripheral.wrap({})'.format(
lua_string(side), lua_string(side),
)) ))
registerType('drive', CCDrive) registerType('drive', CCDrive)
@ -333,15 +333,15 @@ registerType('speaker', CCSpeaker)
registerType('command', CCCommandBlock) registerType('command', CCCommandBlock)
registerType('workbench', CCWorkbench) registerType('workbench', CCWorkbench)
for k in [ for k in [
'chest', 'chest',
'furnace', 'furnace',
'barrel', 'barrel',
'hopper', 'hopper',
'dropper', 'dropper',
'dispenser', 'dispenser',
'blast_furnace', 'blast_furnace',
'smoker', 'smoker',
'shulker_box', 'shulker_box',
'brewing_stand', 'brewing_stand',
]: ]:
registerType('minecraft:' + k, CCInventory) registerType('minecraft:' + k, CCInventory)

View file

@ -5,14 +5,14 @@ method = eval_lua_method_factory('pocket.')
__all__ = ( __all__ = (
'equipBack', 'equipBack',
'unequipBack', 'unequipBack',
) )
def equipBack(): def equipBack():
return method('equipBack').check_bool_error() return method('equipBack').check_bool_error()
def unequipBack(): def unequipBack():
return method('unequipBack').check_bool_error() return method('unequipBack').check_bool_error()

View file

@ -9,17 +9,17 @@ method = eval_lua_method_factory('rednet.')
__all__ = ( __all__ = (
'CHANNEL_REPEAT', 'CHANNEL_REPEAT',
'CHANNEL_BROADCAST', 'CHANNEL_BROADCAST',
'open', 'open',
'close', 'close',
'send', 'send',
'broadcast', 'broadcast',
'receive', 'receive',
'isOpen', 'isOpen',
'host', 'host',
'unhost', 'unhost',
'lookup', 'lookup',
) )
@ -28,48 +28,48 @@ CHANNEL_BROADCAST = 65535
def open(side: str): def open(side: str):
return method('open', ser.encode(side)).take_none() return method('open', ser.encode(side)).take_none()
def close(side: str = None): def close(side: str = None):
return method('close', ser.nil_encode(side)).take_none() return method('close', ser.nil_encode(side)).take_none()
def send(receiverID: int, message: Any, protocol: str = None) -> bool: def send(receiverID: int, message: Any, protocol: str = None) -> bool:
return method('send', receiverID, message, ser.nil_encode(protocol)).take_bool() return method('send', receiverID, message, ser.nil_encode(protocol)).take_bool()
def broadcast(message: Any, protocol: str = None): def broadcast(message: Any, protocol: str = None):
return method('broadcast', message, ser.nil_encode(protocol)).take_none() return method('broadcast', message, ser.nil_encode(protocol)).take_none()
def receive( def receive(
protocolFilter: str = None, timeout: LuaNum = None, protocolFilter: str = None, timeout: LuaNum = None,
) -> Optional[Tuple[int, Any, Optional[str]]]: ) -> Optional[Tuple[int, Any, Optional[str]]]:
rp = method('receive', ser.nil_encode(protocolFilter), timeout) rp = method('receive', ser.nil_encode(protocolFilter), timeout)
if rp.peek() is None: if rp.peek() is None:
return None return None
return (rp.take_int(), rp.take(), rp.take_option_string()) return (rp.take_int(), rp.take(), rp.take_option_string())
def isOpen(side: str = None) -> bool: def isOpen(side: str = None) -> bool:
return method('isOpen', ser.nil_encode(side)).take_bool() return method('isOpen', ser.nil_encode(side)).take_bool()
def host(protocol: str, hostname: str): def host(protocol: str, hostname: str):
return method('host', ser.encode(protocol), ser.encode(hostname)).take_none() return method('host', ser.encode(protocol), ser.encode(hostname)).take_none()
def unhost(protocol: str): def unhost(protocol: str):
return method('unhost', ser.encode(protocol)).take_none() return method('unhost', ser.encode(protocol)).take_none()
def lookup(protocol: str, hostname: str = None) -> Union[Optional[int], List[int]]: def lookup(protocol: str, hostname: str = None) -> Union[Optional[int], List[int]]:
rp = method('lookup', ser.encode(protocol), ser.nil_encode(hostname)) rp = method('lookup', ser.encode(protocol), ser.nil_encode(hostname))
if hostname is None: if hostname is None:
r = [] r = []
while rp.peek() is not None: while rp.peek() is not None:
r.append(rp.take_int()) r.append(rp.take_int())
return r return r
else: else:
return rp.take_option_int() return rp.take_option_int()

View file

@ -8,61 +8,61 @@ method = eval_lua_method_factory('redstone.')
__all__ = ( __all__ = (
'getSides', 'getSides',
'getInput', 'getInput',
'setOutput', 'setOutput',
'getOutput', 'getOutput',
'getAnalogInput', 'getAnalogInput',
'setAnalogOutput', 'setAnalogOutput',
'getAnalogOutput', 'getAnalogOutput',
'getBundledInput', 'getBundledInput',
'setBundledOutput', 'setBundledOutput',
'getBundledOutput', 'getBundledOutput',
'testBundledInput', 'testBundledInput',
) )
def getSides() -> List[str]: def getSides() -> List[str]:
return method('getSides').take_list_of_strings() return method('getSides').take_list_of_strings()
def getInput(side: str) -> bool: def getInput(side: str) -> bool:
return method('getInput', ser.encode(side)).take_bool() return method('getInput', ser.encode(side)).take_bool()
def setOutput(side: str, value: bool): def setOutput(side: str, value: bool):
return method('setOutput', ser.encode(side), value).take_none() return method('setOutput', ser.encode(side), value).take_none()
def getOutput(side: str) -> bool: def getOutput(side: str) -> bool:
return method('getOutput', ser.encode(side)).take_bool() return method('getOutput', ser.encode(side)).take_bool()
def getAnalogInput(side: str) -> int: def getAnalogInput(side: str) -> int:
return method('getAnalogInput', ser.encode(side)).take_int() return method('getAnalogInput', ser.encode(side)).take_int()
def setAnalogOutput(side: str, strength: int): def setAnalogOutput(side: str, strength: int):
return method('setAnalogOutput', ser.encode(side), strength).take_none() return method('setAnalogOutput', ser.encode(side), strength).take_none()
def getAnalogOutput(side: str) -> int: def getAnalogOutput(side: str) -> int:
return method('getAnalogOutput', ser.encode(side)).take_int() return method('getAnalogOutput', ser.encode(side)).take_int()
# bundled cables are not available in vanilla # bundled cables are not available in vanilla
def getBundledInput(side: str) -> int: def getBundledInput(side: str) -> int:
return method('getBundledInput', ser.encode(side)).take_int() return method('getBundledInput', ser.encode(side)).take_int()
def setBundledOutput(side: str, colors: int): def setBundledOutput(side: str, colors: int):
return method('setBundledOutput', ser.encode(side), colors).take_none() return method('setBundledOutput', ser.encode(side), colors).take_none()
def getBundledOutput(side: str) -> int: def getBundledOutput(side: str) -> int:
return method('getBundledOutput', ser.encode(side)).take_int() return method('getBundledOutput', ser.encode(side)).take_int()
def testBundledInput(side: str, color: int) -> bool: def testBundledInput(side: str, color: int) -> bool:
return method('testBundledInput', ser.encode(side), color).take_bool() return method('testBundledInput', ser.encode(side), color).take_bool()

View file

@ -8,78 +8,78 @@ method = eval_lua_method_factory('settings.')
__all__ = ( __all__ = (
'define', 'define',
'undefine', 'undefine',
'getDetails', 'getDetails',
'set', 'set',
'get', 'get',
'unset', 'unset',
'clear', 'clear',
'getNames', 'getNames',
'load', 'load',
'save', 'save',
) )
def define(name: str, description: str = None, default: Any = None, type: str = None): def define(name: str, description: str = None, default: Any = None, type: str = None):
options = {} options = {}
if description is not None: if description is not None:
options[b'description'] = ser.encode(description) options[b'description'] = ser.encode(description)
if default is not None: if default is not None:
options[b'default'] = default options[b'default'] = default
if type is not None: if type is not None:
options[b'type'] = ser.encode(type) options[b'type'] = ser.encode(type)
return method('define', ser.encode(name), options).take_none() return method('define', ser.encode(name), options).take_none()
def undefine(name: str): def undefine(name: str):
return method('undefine', ser.encode(name)).take_none() return method('undefine', ser.encode(name)).take_none()
def getDetails(name: str) -> dict: def getDetails(name: str) -> dict:
tp = method('getDetails', ser.encode(name)).take_dict(( tp = method('getDetails', ser.encode(name)).take_dict((
b'changed', b'changed',
b'description', b'description',
b'default', b'default',
b'type', b'type',
b'value', b'value',
)) ))
r = {} r = {}
r['changed'] = tp.take_bool() r['changed'] = tp.take_bool()
for k, v in [ for k, v in [
('description', tp.take_option_string()), ('description', tp.take_option_string()),
('default', tp.take()), ('default', tp.take()),
('type', tp.take_option_string()), ('type', tp.take_option_string()),
('value', tp.take()), ('value', tp.take()),
]: ]:
if v is not None: if v is not None:
r[k] = v r[k] = v
return r return r
def set(name: str, value: Any): def set(name: str, value: Any):
return method('set', ser.encode(name), value).take_none() return method('set', ser.encode(name), value).take_none()
def get(name: str, default: Any = None) -> Any: def get(name: str, default: Any = None) -> Any:
return method('get', ser.encode(name), default).take() return method('get', ser.encode(name), default).take()
def unset(name: str): def unset(name: str):
return method('unset', ser.encode(name)).take_none() return method('unset', ser.encode(name)).take_none()
def clear(): def clear():
return method('clear').take_none() return method('clear').take_none()
def getNames() -> List[str]: def getNames() -> List[str]:
return method('getNames').take_list_of_strings() return method('getNames').take_list_of_strings()
def load(path: str = None) -> bool: def load(path: str = None) -> bool:
return method('load', ser.nil_encode(path)).take_bool() return method('load', ser.nil_encode(path)).take_bool()
def save(path: str = None) -> bool: def save(path: str = None) -> bool:
return method('save', ser.nil_encode(path)).take_bool() return method('save', ser.nil_encode(path)).take_bool()

View file

@ -8,101 +8,101 @@ method = eval_lua_method_factory('shell.')
__all__ = ( __all__ = (
'exit', 'exit',
'dir', 'dir',
'setDir', 'setDir',
'path', 'path',
'setPath', 'setPath',
'resolve', 'resolve',
'resolveProgram', 'resolveProgram',
'aliases', 'aliases',
'setAlias', 'setAlias',
'clearAlias', 'clearAlias',
'programs', 'programs',
'getRunningProgram', 'getRunningProgram',
'run', 'run',
'execute', 'execute',
'openTab', 'openTab',
'switchTab', 'switchTab',
'complete', 'complete',
'completeProgram', 'completeProgram',
) )
def exit(): def exit():
return method('exit').take_none() return method('exit').take_none()
def dir() -> str: def dir() -> str:
return method('dir').take_string() return method('dir').take_string()
def setDir(path: str): def setDir(path: str):
return method('setDir', ser.encode(path)).take_none() return method('setDir', ser.encode(path)).take_none()
def path() -> str: def path() -> str:
return method('path').take_string() return method('path').take_string()
def setPath(path: str): def setPath(path: str):
return method('setPath', ser.encode(path)).take_none() return method('setPath', ser.encode(path)).take_none()
def resolve(localPath: str) -> str: def resolve(localPath: str) -> str:
return method('resolve', ser.encode(localPath)).take_string() return method('resolve', ser.encode(localPath)).take_string()
def resolveProgram(name: str) -> Optional[str]: def resolveProgram(name: str) -> Optional[str]:
return method('resolveProgram', ser.encode(name)).take_option_string() return method('resolveProgram', ser.encode(name)).take_option_string()
def aliases() -> Dict[str, str]: def aliases() -> Dict[str, str]:
d = method('aliases').take_dict() d = method('aliases').take_dict()
return {ser.decode(k): ser.decode(v) for k, v in d.items()} return {ser.decode(k): ser.decode(v) for k, v in d.items()}
def setAlias(alias: str, program: str): def setAlias(alias: str, program: str):
return method('setAlias', ser.encode(alias), ser.encode(program)).take_none() return method('setAlias', ser.encode(alias), ser.encode(program)).take_none()
def clearAlias(alias: str): def clearAlias(alias: str):
return method('clearAlias', ser.encode(alias)).take_none() return method('clearAlias', ser.encode(alias)).take_none()
def programs(showHidden: bool = None) -> List[str]: def programs(showHidden: bool = None) -> List[str]:
return method('programs', showHidden).take_list_of_strings() return method('programs', showHidden).take_list_of_strings()
def getRunningProgram() -> str: def getRunningProgram() -> str:
return method('getRunningProgram').take_string() return method('getRunningProgram').take_string()
def run(command: str, *args: str) -> bool: def run(command: str, *args: str) -> bool:
args = tuple(ser.encode(a) for a in args) args = tuple(ser.encode(a) for a in args)
return method('run', ser.encode(command), *args).take_bool() return method('run', ser.encode(command), *args).take_bool()
def execute(command: str, *args: str) -> bool: def execute(command: str, *args: str) -> bool:
args = tuple(ser.encode(a) for a in args) args = tuple(ser.encode(a) for a in args)
return method('execute', ser.encode(command), *args).take_bool() return method('execute', ser.encode(command), *args).take_bool()
def openTab(command: str, *args: str) -> int: def openTab(command: str, *args: str) -> int:
args = tuple(ser.encode(a) for a in args) args = tuple(ser.encode(a) for a in args)
return method('openTab', ser.encode(command), *args).take_int() return method('openTab', ser.encode(command), *args).take_int()
def switchTab(tabID: int): def switchTab(tabID: int):
return method('switchTab', tabID).take_none() return method('switchTab', tabID).take_none()
def complete(prefix: str) -> List[str]: def complete(prefix: str) -> List[str]:
return method('complete', ser.encode(prefix)).take_list_of_strings() return method('complete', ser.encode(prefix)).take_list_of_strings()
def completeProgram(prefix: str) -> List[str]: def completeProgram(prefix: str) -> List[str]:
return method('completeProgram', ser.encode(prefix)).take_list_of_strings() return method('completeProgram', ser.encode(prefix)).take_list_of_strings()
# TODO: ? # TODO: ?
# these functions won't be implemented # these functions won't be implemented
@ -112,4 +112,4 @@ def completeProgram(prefix: str) -> List[str]:
# getCompletionInfo # getCompletionInfo
# we can create callbacks to python code, but this will require # we can create callbacks to python code, but this will require
# connection to python, and will break the shell if python disconnects # connection to python, and will break the shell if python disconnects

View file

@ -7,7 +7,7 @@ from ..sess import eval_lua_method_factory, lua_context_object
class TermAPI(BaseSubAPI, TermMixin): class TermAPI(BaseSubAPI, TermMixin):
pass pass
method = eval_lua_method_factory('term.') method = eval_lua_method_factory('term.')
@ -15,27 +15,27 @@ tapi = TermAPI('term')
__all__ = ( __all__ = (
'write', 'write',
'blit', 'blit',
'clear', 'clear',
'clearLine', 'clearLine',
'getCursorPos', 'getCursorPos',
'setCursorPos', 'setCursorPos',
'getCursorBlink', 'getCursorBlink',
'setCursorBlink', 'setCursorBlink',
'isColor', 'isColor',
'getSize', 'getSize',
'scroll', 'scroll',
'setTextColor', 'setTextColor',
'getTextColor', 'getTextColor',
'setBackgroundColor', 'setBackgroundColor',
'getBackgroundColor', 'getBackgroundColor',
'getPaletteColor', 'getPaletteColor',
'setPaletteColor', 'setPaletteColor',
'nativePaletteColor', 'nativePaletteColor',
'redirect', 'redirect',
'get_current_target', 'get_current_target',
'get_native_target', 'get_native_target',
) )
@ -59,23 +59,23 @@ setPaletteColor = tapi.setPaletteColor
def nativePaletteColor(colorID: int) -> Tuple[float, float, float]: def nativePaletteColor(colorID: int) -> Tuple[float, float, float]:
rp = method('nativePaletteColor', colorID) rp = method('nativePaletteColor', colorID)
return tuple(rp.take_number() for _ in range(3)) return tuple(rp.take_number() for _ in range(3))
@contextmanager @contextmanager
def redirect(target: TermTarget): def redirect(target: TermTarget):
with lua_context_object( with lua_context_object(
'term.redirect(...)', 'term.redirect(...)',
(target, ), (target, ),
'term.redirect({e})', 'term.redirect({e})',
): ):
yield yield
def get_current_target() -> TermTarget: def get_current_target() -> TermTarget:
return TermTarget('term.current()') return TermTarget('term.current()')
def get_native_target() -> TermTarget: def get_native_target() -> TermTarget:
return TermTarget('term.native()') return TermTarget('term.native()')

View file

@ -9,52 +9,52 @@ method = eval_lua_method_factory('textutils.')
__all__ = ( __all__ = (
'slowWrite', 'slowWrite',
'slowPrint', 'slowPrint',
'formatTime', 'formatTime',
'tabulate', 'tabulate',
'pagedTabulate', 'pagedTabulate',
'pagedPrint', 'pagedPrint',
'complete', 'complete',
) )
def slowWrite(text: str, rate: LuaNum = None): def slowWrite(text: str, rate: LuaNum = None):
return method('slowWrite', ser.dirty_encode(text), rate).take_none() return method('slowWrite', ser.dirty_encode(text), rate).take_none()
def slowPrint(text: str, rate: LuaNum = None): def slowPrint(text: str, rate: LuaNum = None):
return method('slowPrint', ser.dirty_encode(text), rate).take_none() return method('slowPrint', ser.dirty_encode(text), rate).take_none()
def formatTime(time: LuaNum, twentyFourHour: bool = None) -> str: def formatTime(time: LuaNum, twentyFourHour: bool = None) -> str:
return method('formatTime', time, twentyFourHour).take_string() return method('formatTime', time, twentyFourHour).take_string()
def _prepareTab(rows_and_colors): def _prepareTab(rows_and_colors):
r = [] r = []
for item in rows_and_colors: for item in rows_and_colors:
if isinstance(item, int): if isinstance(item, int):
r.append(item) r.append(item)
else: else:
r.append([ser.dirty_encode(x) for x in item]) r.append([ser.dirty_encode(x) for x in item])
return r return r
def tabulate(*rows_and_colors: Union[List[str], int]): def tabulate(*rows_and_colors: Union[List[str], int]):
return method('tabulate', *_prepareTab(rows_and_colors)).take_none() return method('tabulate', *_prepareTab(rows_and_colors)).take_none()
def pagedTabulate(*rows_and_colors: Union[List[str], int]): def pagedTabulate(*rows_and_colors: Union[List[str], int]):
return method('pagedTabulate', *_prepareTab(rows_and_colors)).take_none() return method('pagedTabulate', *_prepareTab(rows_and_colors)).take_none()
def pagedPrint(text: str, freeLines: int = None) -> int: def pagedPrint(text: str, freeLines: int = None) -> int:
return method('pagedPrint', ser.dirty_encode(text), freeLines).take_int() return method('pagedPrint', ser.dirty_encode(text), freeLines).take_int()
def complete(partial: str, possible: List[str]) -> List[str]: def complete(partial: str, possible: List[str]) -> List[str]:
return [p[len(partial):] for p in possible if p.startswith(partial)] return [p[len(partial):] for p in possible if p.startswith(partial)]
# Questionable to implement # Questionable to implement
@ -66,4 +66,4 @@ def complete(partial: str, possible: List[str]) -> List[str]:
# unserializeJSON # unserializeJSON
# urlEncode # urlEncode
# json_null # json_null
# empty_json_array # empty_json_array

View file

@ -9,233 +9,233 @@ method = eval_lua_method_factory('turtle.')
def inspect_result(rp): def inspect_result(rp):
success = rp.take_bool() success = rp.take_bool()
if not success: if not success:
msg = rp.take_string() msg = rp.take_string()
if msg == 'No block to inspect': if msg == 'No block to inspect':
return None return None
raise LuaException(msg) raise LuaException(msg)
else: else:
return rp.take_dict() return rp.take_dict()
__all__ = ( __all__ = (
'craft', 'craft',
'forward', 'forward',
'back', 'back',
'up', 'up',
'down', 'down',
'turnLeft', 'turnLeft',
'turnRight', 'turnRight',
'select', 'select',
'getSelectedSlot', 'getSelectedSlot',
'getItemCount', 'getItemCount',
'getItemSpace', 'getItemSpace',
'getItemDetail', 'getItemDetail',
'equipLeft', 'equipLeft',
'equipRight', 'equipRight',
'attack', 'attack',
'attackUp', 'attackUp',
'attackDown', 'attackDown',
'dig', 'dig',
'digUp', 'digUp',
'digDown', 'digDown',
'place', 'place',
'placeUp', 'placeUp',
'placeDown', 'placeDown',
'detect', 'detect',
'detectUp', 'detectUp',
'detectDown', 'detectDown',
'inspect', 'inspect',
'inspectUp', 'inspectUp',
'inspectDown', 'inspectDown',
'compare', 'compare',
'compareUp', 'compareUp',
'compareDown', 'compareDown',
'compareTo', 'compareTo',
'drop', 'drop',
'dropUp', 'dropUp',
'dropDown', 'dropDown',
'suck', 'suck',
'suckUp', 'suckUp',
'suckDown', 'suckDown',
'refuel', 'refuel',
'getFuelLevel', 'getFuelLevel',
'getFuelLimit', 'getFuelLimit',
'transferTo', 'transferTo',
) )
def craft(quantity: int = 64): def craft(quantity: int = 64):
return method('craft', quantity).check_bool_error() return method('craft', quantity).check_bool_error()
def forward(): def forward():
return method('forward').check_bool_error() return method('forward').check_bool_error()
def back(): def back():
return method('back').check_bool_error() return method('back').check_bool_error()
def up(): def up():
return method('up').check_bool_error() return method('up').check_bool_error()
def down(): def down():
return method('down').check_bool_error() return method('down').check_bool_error()
def turnLeft(): def turnLeft():
return method('turnLeft').check_bool_error() return method('turnLeft').check_bool_error()
def turnRight(): def turnRight():
return method('turnRight').check_bool_error() return method('turnRight').check_bool_error()
def select(slotNum: int): def select(slotNum: int):
return method('select', slotNum).check_bool_error() return method('select', slotNum).check_bool_error()
def getSelectedSlot() -> int: def getSelectedSlot() -> int:
return method('getSelectedSlot').take_int() return method('getSelectedSlot').take_int()
def getItemCount(slotNum: int = None) -> int: def getItemCount(slotNum: int = None) -> int:
return method('getItemCount', slotNum).take_int() return method('getItemCount', slotNum).take_int()
def getItemSpace(slotNum: int = None) -> int: def getItemSpace(slotNum: int = None) -> int:
return method('getItemSpace', slotNum).take_int() return method('getItemSpace', slotNum).take_int()
def getItemDetail(slotNum: int = None) -> Optional[dict]: def getItemDetail(slotNum: int = None) -> Optional[dict]:
rp = method('getItemDetail', slotNum) rp = method('getItemDetail', slotNum)
if rp.peek() is None: if rp.peek() is None:
return None return None
return rp.take_dict() return rp.take_dict()
def equipLeft(): def equipLeft():
return method('equipLeft').check_bool_error() return method('equipLeft').check_bool_error()
def equipRight(): def equipRight():
return method('equipRight').check_bool_error() return method('equipRight').check_bool_error()
def attack(): def attack():
return method('attack').check_bool_error() return method('attack').check_bool_error()
def attackUp(): def attackUp():
return method('attackUp').check_bool_error() return method('attackUp').check_bool_error()
def attackDown(): def attackDown():
return method('attackDown').check_bool_error() return method('attackDown').check_bool_error()
def dig(): def dig():
return method('dig').check_bool_error() return method('dig').check_bool_error()
def digUp(): def digUp():
return method('digUp').check_bool_error() return method('digUp').check_bool_error()
def digDown(): def digDown():
return method('digDown').check_bool_error() return method('digDown').check_bool_error()
def place(signText: str = None): def place(signText: str = None):
return method('place', ser.nil_encode(signText)).check_bool_error() return method('place', ser.nil_encode(signText)).check_bool_error()
def placeUp(signText: str = None): def placeUp(signText: str = None):
return method('placeUp', ser.nil_encode(signText)).check_bool_error() return method('placeUp', ser.nil_encode(signText)).check_bool_error()
def placeDown(signText: str = None): def placeDown(signText: str = None):
return method('placeDown', ser.nil_encode(signText)).check_bool_error() return method('placeDown', ser.nil_encode(signText)).check_bool_error()
def detect() -> bool: def detect() -> bool:
return method('detect').take_bool() return method('detect').take_bool()
def detectUp() -> bool: def detectUp() -> bool:
return method('detectUp').take_bool() return method('detectUp').take_bool()
def detectDown() -> bool: def detectDown() -> bool:
return method('detectDown').take_bool() return method('detectDown').take_bool()
def inspect() -> Optional[dict]: def inspect() -> Optional[dict]:
return inspect_result(method('inspect')) return inspect_result(method('inspect'))
def inspectUp() -> Optional[dict]: def inspectUp() -> Optional[dict]:
return inspect_result(method('inspectUp')) return inspect_result(method('inspectUp'))
def inspectDown() -> Optional[dict]: def inspectDown() -> Optional[dict]:
return inspect_result(method('inspectDown')) return inspect_result(method('inspectDown'))
def compare() -> bool: def compare() -> bool:
return method('compare').take_bool() return method('compare').take_bool()
def compareUp() -> bool: def compareUp() -> bool:
return method('compareUp').take_bool() return method('compareUp').take_bool()
def compareDown() -> bool: def compareDown() -> bool:
return method('compareDown').take_bool() return method('compareDown').take_bool()
def compareTo(slot: int) -> bool: def compareTo(slot: int) -> bool:
return method('compareTo', slot).take_bool() return method('compareTo', slot).take_bool()
def drop(count: int = None): def drop(count: int = None):
return method('drop', count).check_bool_error() return method('drop', count).check_bool_error()
def dropUp(count: int = None): def dropUp(count: int = None):
return method('dropUp', count).check_bool_error() return method('dropUp', count).check_bool_error()
def dropDown(count: int = None): def dropDown(count: int = None):
return method('dropDown', count).check_bool_error() return method('dropDown', count).check_bool_error()
def suck(amount: int = None): def suck(amount: int = None):
return method('suck', amount).check_bool_error() return method('suck', amount).check_bool_error()
def suckUp(amount: int = None): def suckUp(amount: int = None):
return method('suckUp', amount).check_bool_error() return method('suckUp', amount).check_bool_error()
def suckDown(amount: int = None): def suckDown(amount: int = None):
return method('suckDown', amount).check_bool_error() return method('suckDown', amount).check_bool_error()
def refuel(quantity: int = None): def refuel(quantity: int = None):
return method('refuel', quantity).check_bool_error() return method('refuel', quantity).check_bool_error()
def getFuelLevel() -> int: def getFuelLevel() -> int:
return method('getFuelLevel').take_int() return method('getFuelLevel').take_int()
def getFuelLimit() -> int: def getFuelLimit() -> int:
return method('getFuelLimit').take_int() return method('getFuelLimit').take_int()
def transferTo(slot: int, quantity: int = None): def transferTo(slot: int, quantity: int = None):
return method('transferTo', slot, quantity).check_bool_error() return method('transferTo', slot, quantity).check_bool_error()

View file

@ -7,44 +7,44 @@ from .mixins import TermMixin, TermTarget
class CCWindow(BaseSubAPI, TermMixin): class CCWindow(BaseSubAPI, TermMixin):
def setVisible(self, visibility: bool): def setVisible(self, visibility: bool):
return self._method('setVisible', visibility).take_none() return self._method('setVisible', visibility).take_none()
def redraw(self): def redraw(self):
return self._method('redraw').take_none() return self._method('redraw').take_none()
def restoreCursor(self): def restoreCursor(self):
return self._method('restoreCursor').take_none() return self._method('restoreCursor').take_none()
def getPosition(self) -> Tuple[int, int]: def getPosition(self) -> Tuple[int, int]:
rp = self._method('getPosition') rp = self._method('getPosition')
return tuple(rp.take_int() for _ in range(2)) return tuple(rp.take_int() for _ in range(2))
def reposition(self, x: int, y: int, width: int = None, height: int = None, parent: TermTarget = None): def reposition(self, x: int, y: int, width: int = None, height: int = None, parent: TermTarget = None):
return self._method('reposition', x, y, width, height, parent).take_none() return self._method('reposition', x, y, width, height, parent).take_none()
def getLine(self, y: int) -> Tuple[str, bytes, bytes]: def getLine(self, y: int) -> Tuple[str, bytes, bytes]:
rp = self._method('getLine', y) rp = self._method('getLine', y)
return rp.take_string(), rp.take_bytes(), rp.take_bytes() return rp.take_string(), rp.take_bytes(), rp.take_bytes()
def get_term_target(self) -> TermTarget: def get_term_target(self) -> TermTarget:
return TermTarget(self.get_expr_code()) return TermTarget(self.get_expr_code())
method = eval_lua_method_factory('window.') method = eval_lua_method_factory('window.')
__all__ = ( __all__ = (
'create', 'create',
) )
@contextmanager @contextmanager
def create( def create(
parentTerm: TermTarget, x: int, y: int, width: int, height: int, visible: bool = None, parentTerm: TermTarget, x: int, y: int, width: int, height: int, visible: bool = None,
) -> CCWindow: ) -> CCWindow:
with lua_context_object( with lua_context_object(
'window.create(...)', 'window.create(...)',
(parentTerm, x, y, width, height, visible), (parentTerm, x, y, width, height, visible),
) as var: ) as var:
yield CCWindow(var) yield CCWindow(var)

View file

@ -7,133 +7,133 @@ from cc import eval_lua
@contextmanager @contextmanager
def assert_raises(etype, message=None): def assert_raises(etype, message=None):
try: try:
yield yield
except Exception as e: except Exception as e:
assert isinstance(e, etype), repr(e) assert isinstance(e, etype), repr(e)
if message is not None: if message is not None:
assert e.args == (message, ) assert e.args == (message, )
else: else:
raise AssertionError(f'Exception of type {etype} was not raised') raise AssertionError(f'Exception of type {etype} was not raised')
@contextmanager @contextmanager
def assert_takes_time(at_least, at_most): def assert_takes_time(at_least, at_most):
t = monotonic() t = monotonic()
yield yield
dt = monotonic() - t dt = monotonic() - t
# print(at_least, '<=', dt, '<=', at_most) # print(at_least, '<=', dt, '<=', at_most)
assert at_least <= dt <= at_most assert at_least <= dt <= at_most
class AnyInstanceOf: class AnyInstanceOf:
def __init__(self, cls): def __init__(self, cls):
self.c = cls self.c = cls
def __eq__(self, other): def __eq__(self, other):
return isinstance(other, self.c) return isinstance(other, self.c)
def step(text): def step(text):
input(f'{text} [enter]') input(f'{text} [enter]')
def get_object_table(objname): def get_object_table(objname):
rp = eval_lua(f""" rp = eval_lua(f"""
local r = {{}} local r = {{}}
for k in pairs({objname}) do for k in pairs({objname}) do
local t = type({objname}[k]) local t = type({objname}[k])
if r[t] == nil then r[t] = {{}} end if r[t] == nil then r[t] = {{}} end
if t == 'number' or t == 'boolean' or t == 'string' then if t == 'number' or t == 'boolean' or t == 'string' then
r[t][k] = {objname}[k] r[t][k] = {objname}[k]
else else
r[t][k] = true r[t][k] = true
end end
end end
return r""", immediate=True) return r""", immediate=True)
d = rp.take_dict() d = rp.take_dict()
return { return {
k1.decode('latin1'): { k1.decode('latin1'): {
k2.decode('latin1'): v for k2, v in t.items() k2.decode('latin1'): v for k2, v in t.items()
} for k1, t in d.items() } for k1, t in d.items()
} }
def get_class_table(cls): def get_class_table(cls):
items = { items = {
k: v for k, v in vars(cls).items() k: v for k, v in vars(cls).items()
if not k.startswith('_') if not k.startswith('_')
} }
nums = { nums = {
k: v for k, v in items.items() k: v for k, v in items.items()
if isinstance(v, (int, float)) if isinstance(v, (int, float))
} }
methods = { methods = {
k: True for k, v in items.items() k: True for k, v in items.items()
if isinstance(v, FunctionType) if isinstance(v, FunctionType)
} }
r = {} r = {}
if nums: if nums:
r['number'] = nums r['number'] = nums
if methods: if methods:
r['function'] = methods r['function'] = methods
return r return r
def get_multiclass_table(*cls): def get_multiclass_table(*cls):
result = {} result = {}
for c in cls: for c in cls:
for k, v in get_class_table(c).items(): for k, v in get_class_table(c).items():
result.setdefault(k, {}).update(v) result.setdefault(k, {}).update(v)
return result return result
def term_step(text): def term_step(text):
from cc import colors, term from cc import colors, term
for color in colors.iter_colors(): for color in colors.iter_colors():
r, g, b = term.nativePaletteColor(color) r, g, b = term.nativePaletteColor(color)
term.setPaletteColor(color, r, g, b) term.setPaletteColor(color, r, g, b)
term.setBackgroundColor(colors.black) term.setBackgroundColor(colors.black)
term.setTextColor(colors.white) term.setTextColor(colors.white)
term.clear() term.clear()
term.setCursorPos(1, 1) term.setCursorPos(1, 1)
term.setCursorBlink(True) term.setCursorBlink(True)
step(text) step(text)
def _computer_peri(place_thing, thing): def _computer_peri(place_thing, thing):
from cc import peripheral from cc import peripheral
side = 'left' side = 'left'
step( step(
f'Place {place_thing} on {side} side of computer\n' f'Place {place_thing} on {side} side of computer\n'
"Don't turn it on!", "Don't turn it on!",
) )
c = peripheral.wrap(side) c = peripheral.wrap(side)
assert c is not None assert c is not None
from computercraft.subapis.peripheral import ComputerMixin from computercraft.subapis.peripheral import ComputerMixin
tbl = get_object_table(f'peripheral.wrap("{side}")') tbl = get_object_table(f'peripheral.wrap("{side}")')
assert get_class_table(ComputerMixin) == tbl assert get_class_table(ComputerMixin) == tbl
assert c.isOn() is False assert c.isOn() is False
assert isinstance(c.getID(), int) assert isinstance(c.getID(), int)
assert c.getLabel() is None assert c.getLabel() is None
assert c.turnOn() is None assert c.turnOn() is None
step(f'{thing.capitalize()} must be turned on now') step(f'{thing.capitalize()} must be turned on now')
assert c.shutdown() is None assert c.shutdown() is None
step(f'{thing.capitalize()} must shutdown') step(f'{thing.capitalize()} must shutdown')
step(f'Now turn on {thing} manually and enter some commands') step(f'Now turn on {thing} manually and enter some commands')
assert c.reboot() is None assert c.reboot() is None
step(f'{thing.capitalize()} must reboot') step(f'{thing.capitalize()} must reboot')
print('Test finished successfully') print('Test finished successfully')

View file

@ -6,10 +6,10 @@ import argparse
parser = argparse.ArgumentParser(prog=__file__, description='Process some integers.') parser = argparse.ArgumentParser(prog=__file__, description='Process some integers.')
parser.add_argument('integers', metavar='N', type=int, nargs='+', parser.add_argument('integers', metavar='N', type=int, nargs='+',
help='an integer for the accumulator') help='an integer for the accumulator')
parser.add_argument('--sum', dest='accumulate', action='store_const', parser.add_argument('--sum', dest='accumulate', action='store_const',
const=sum, default=max, const=sum, default=max,
help='sum the integers (default: find the max)') help='sum the integers (default: find the max)')
args = parser.parse_args(args=args) args = parser.parse_args(args=args)
print(args.accumulate(args.integers)) print(args.accumulate(args.integers))

View file

@ -1 +1 @@
raise ValueError raise ValueError

View file

@ -1 +1 @@
print('Hello world!') print('Hello world!')

View file

@ -2,4 +2,4 @@ from cc import os
print('ID', os.getComputerID()) print('ID', os.getComputerID())
print('Label', os.getComputerLabel()) print('Label', os.getComputerLabel())
print('Version', os.version()) print('Version', os.version())

View file

@ -6,8 +6,8 @@ m = peripheral.wrap(side)
listen_channel = 5 listen_channel = 5
m.close(listen_channel) m.close(listen_channel)
for msg in m.receive(listen_channel): for msg in m.receive(listen_channel):
print(repr(msg)) print(repr(msg))
if msg.content == b'stop': if msg.content == b'stop':
break break
else: else:
m.transmit(msg.reply_channel, listen_channel, msg.content) m.transmit(msg.reply_channel, listen_channel, msg.content)

View file

@ -1,9 +1,9 @@
from cc import is_turtle, turtle from cc import is_turtle, turtle
if not is_turtle(): if not is_turtle():
print('Turtle required!') print('Turtle required!')
exit() exit()
for _ in range(4): for _ in range(4):
turtle.forward() turtle.forward()
turtle.turnLeft() turtle.turnLeft()

View file

@ -1,2 +1,2 @@
line = input() line = input()
print(f'Entered line: {line}') print(f'Entered line: {line}')

View file

@ -13,18 +13,18 @@ tbl['function']['iter_colors'] = True
assert _lib.get_class_table(colors) == tbl assert _lib.get_class_table(colors) == tbl
cs = colors.combine( cs = colors.combine(
colors.orange, colors.orange,
colors.cyan, colors.cyan,
colors.pink, colors.pink,
colors.brown, colors.brown,
) )
assert isinstance(cs, int) assert isinstance(cs, int)
cs = colors.subtract(cs, colors.brown, colors.green) cs = colors.subtract(cs, colors.brown, colors.green)
assert isinstance(cs, int) assert isinstance(cs, int)
assert cs == colors.combine( assert cs == colors.combine(
colors.orange, colors.orange,
colors.cyan, colors.cyan,
colors.pink, colors.pink,
) )
assert colors.test(cs, colors.red) is False assert colors.test(cs, colors.red) is False
assert colors.test(cs, colors.cyan) is True assert colors.test(cs, colors.cyan) is True
@ -35,4 +35,4 @@ assert 0.68 < r < 0.72
assert 0.18 < g < 0.22 assert 0.18 < g < 0.22
assert 0.58 < b < 0.62 assert 0.58 < b < 0.62
print('Test finished successfully') print('Test finished successfully')

View file

@ -13,24 +13,24 @@ xyz = commands.getBlockPosition()
assert len(xyz) == 3 assert len(xyz) == 3
for c in xyz: for c in xyz:
assert isinstance(c, int) assert isinstance(c, int)
# TODO: decode bytes? # TODO: decode bytes?
expected_binfo = { expected_binfo = {
b'state': { b'state': {
b'state': AnyInstanceOf(bytes), b'state': AnyInstanceOf(bytes),
b'facing': AnyInstanceOf(bytes), b'facing': AnyInstanceOf(bytes),
}, },
b'name': b'computercraft:computer_command', b'name': b'computercraft:computer_command',
b'nbt': { b'nbt': {
b'x': xyz[0], b'x': xyz[0],
b'y': xyz[1], b'y': xyz[1],
b'z': xyz[2], b'z': xyz[2],
b'ComputerId': AnyInstanceOf(int), b'ComputerId': AnyInstanceOf(int),
b'id': b'computercraft:computer_command', b'id': b'computercraft:computer_command',
b'On': 1, b'On': 1,
}, },
b'tags': {}, b'tags': {},
} }
assert commands.getBlockInfo(*xyz) == expected_binfo assert commands.getBlockInfo(*xyz) == expected_binfo
@ -40,7 +40,7 @@ cmdlist = commands.list()
assert len(cmdlist) > 0 assert len(cmdlist) > 0
for c in cmdlist: for c in cmdlist:
assert isinstance(c, str) assert isinstance(c, str)
assert commands.exec('say Hello!') == (True, [], AnyInstanceOf(int)) assert commands.exec('say Hello!') == (True, [], AnyInstanceOf(int))
@ -53,4 +53,4 @@ assert len(d[1]) == 1
assert d[1][0].startswith('The difficulty is ') assert d[1][0].startswith('The difficulty is ')
assert isinstance(d[2], int) assert isinstance(d[2], int)
print('Test finished successfully') print('Test finished successfully')

View file

@ -70,9 +70,9 @@ assert label != 'label'
print(f'Label is {label}') print(f'Label is {label}')
assert disk.getLabel(s) == label assert disk.getLabel(s) == label
with assert_raises(LuaException): with assert_raises(LuaException):
assert disk.setLabel(s, 'label') is None assert disk.setLabel(s, 'label') is None
with assert_raises(LuaException): with assert_raises(LuaException):
assert disk.setLabel(s, None) is None assert disk.setLabel(s, None) is None
# no effect # no effect
assert disk.getLabel(s) == label assert disk.getLabel(s) == label
@ -83,4 +83,4 @@ step('Audio must be playing now')
assert disk.stopAudio(s) is None assert disk.stopAudio(s) is None
assert disk.eject(s) is None assert disk.eject(s) is None
print('Test finished successfully') print('Test finished successfully')

View file

@ -7,12 +7,12 @@ assert_raises, AnyInstanceOf = _lib.assert_raises, _lib.AnyInstanceOf
assert _lib.get_class_table(fs) == _lib.get_object_table('fs') assert _lib.get_class_table(fs) == _lib.get_object_table('fs')
for name in ('tdir', 'tfile'): for name in ('tdir', 'tfile'):
if fs.exists(name): if fs.exists(name):
fs.delete(name) fs.delete(name)
assert fs.makeDir('tdir') is None assert fs.makeDir('tdir') is None
with fs.open('tfile', 'w') as f: with fs.open('tfile', 'w') as f:
f.writeLine('textline') f.writeLine('textline')
dlist = set(fs.list('.')) dlist = set(fs.list('.'))
@ -91,7 +91,7 @@ assert fs.combine('a/b/c', './../.') == 'a/b'
assert fs.getSize('tfile') == 9 assert fs.getSize('tfile') == 9
assert fs.getSize('tdir') == 0 assert fs.getSize('tdir') == 0
with assert_raises(LuaException): with assert_raises(LuaException):
fs.getSize('doesnotexist') fs.getSize('doesnotexist')
assert fs.move('tfile', 'tdir/apple') is None assert fs.move('tfile', 'tdir/apple') is None
assert fs.list('tdir') == ['apple'] assert fs.list('tdir') == ['apple']
@ -126,19 +126,19 @@ dlist = set(fs.list('tdir'))
assert dlist == {'apple', 'banana', 'cherry'} assert dlist == {'apple', 'banana', 'cherry'}
assert fs.attributes('tdir/banana') == { assert fs.attributes('tdir/banana') == {
'created': AnyInstanceOf(int), 'created': AnyInstanceOf(int),
'modification': AnyInstanceOf(int), 'modification': AnyInstanceOf(int),
'isDir': False, 'isDir': False,
'size': 9, 'size': 9,
} }
assert fs.attributes('tdir') == { assert fs.attributes('tdir') == {
'created': AnyInstanceOf(int), 'created': AnyInstanceOf(int),
'modification': AnyInstanceOf(int), 'modification': AnyInstanceOf(int),
'isDir': True, 'isDir': True,
'size': 0, 'size': 0,
} }
with assert_raises(LuaException): with assert_raises(LuaException):
fs.attributes('doesnotexist') fs.attributes('doesnotexist')
assert fs.complete('ba', 'tdir') == ['nana'] assert fs.complete('ba', 'tdir') == ['nana']
assert fs.complete('ap', 'tdir') == ['ple'] assert fs.complete('ap', 'tdir') == ['ple']
@ -151,55 +151,55 @@ assert fs.complete('ap', 'tdir', includeFiles=False) == []
assert fs.getSize('tdir/banana') == 9 assert fs.getSize('tdir/banana') == 9
with fs.open('tdir/banana', 'r') as f: with fs.open('tdir/banana', 'r') as f:
assert f.read(4) == 'text' assert f.read(4) == 'text'
assert f.readLine() == 'line' assert f.readLine() == 'line'
assert f.read(1) is None assert f.read(1) is None
assert f.readLine() is None assert f.readLine() is None
assert f.readAll() is None assert f.readAll() is None
assert f.readAll() is None assert f.readAll() is None
assert fs.getSize('tdir/banana') == 9 assert fs.getSize('tdir/banana') == 9
with fs.open('tdir/banana', 'a') as f: with fs.open('tdir/banana', 'a') as f:
assert f.write('x') is None assert f.write('x') is None
assert fs.getSize('tdir/banana') == 10 assert fs.getSize('tdir/banana') == 10
with fs.open('tdir/banana', 'w') as f: with fs.open('tdir/banana', 'w') as f:
pass pass
assert fs.getSize('tdir/banana') == 0 # truncate assert fs.getSize('tdir/banana') == 0 # truncate
with fs.open('tdir/banana', 'w') as f: with fs.open('tdir/banana', 'w') as f:
assert f.write('Bro') is None assert f.write('Bro') is None
assert f.writeLine('wn fox jumps') is None assert f.writeLine('wn fox jumps') is None
# assert fs.getSize('tdir/banana') == 0 # changes are not on a disk # assert fs.getSize('tdir/banana') == 0 # changes are not on a disk
assert f.flush() is None assert f.flush() is None
assert fs.getSize('tdir/banana') == len('Brown fox jumps\n') assert fs.getSize('tdir/banana') == len('Brown fox jumps\n')
assert f.write('ov') is None assert f.write('ov') is None
assert f.write('er ') is None assert f.write('er ') is None
assert f.write('a lazy') is None assert f.write('a lazy') is None
assert f.writeLine(' дог.') is None # supports unicode! assert f.writeLine(' дог.') is None # supports unicode!
assert fs.getSize('tdir/banana') > 9 assert fs.getSize('tdir/banana') > 9
with fs.open('tdir/banana', 'r') as f: with fs.open('tdir/banana', 'r') as f:
assert f.readAll() == 'Brown fox jumps\nover a lazy дог.\n' assert f.readAll() == 'Brown fox jumps\nover a lazy дог.\n'
with assert_raises(LuaException): with assert_raises(LuaException):
with fs.open('tdir/banana', 'rw') as f: with fs.open('tdir/banana', 'rw') as f:
pass pass
assert fs.exists('tdir/banana') is True assert fs.exists('tdir/banana') is True
with fs.open('tdir/binfile', 'wb') as f: with fs.open('tdir/binfile', 'wb') as f:
assert f.write(b'a' * 9) is None assert f.write(b'a' * 9) is None
assert f.seek() == 9 assert f.seek() == 9
assert f.seek('set', 0) == 0 assert f.seek('set', 0) == 0
assert f.write(b'b' * 3) is None assert f.write(b'b' * 3) is None
assert f.seek('cur', -1) == 2 assert f.seek('cur', -1) == 2
assert f.write(b'c' * 3) is None assert f.write(b'c' * 3) is None
assert f.seek('end') == 9 assert f.seek('end') == 9
assert f.write(b'd' * 3) is None assert f.write(b'd' * 3) is None
with assert_raises(LuaException): with assert_raises(LuaException):
f.seek('set', -10) f.seek('set', -10)
with fs.open('tdir/binfile', 'rb') as f: with fs.open('tdir/binfile', 'rb') as f:
assert f.readAll() == b'bbcccaaaaddd' assert f.readAll() == b'bbcccaaaaddd'
with fs.open('tdir/binfile', 'r') as f: with fs.open('tdir/binfile', 'r') as f:
assert [line for line in f] == ['bbcccaaaaddd'] assert [line for line in f] == ['bbcccaaaaddd']
assert fs.delete('tdir') is None assert fs.delete('tdir') is None
assert fs.delete('tfile') is None assert fs.delete('tfile') is None
@ -207,4 +207,4 @@ assert fs.delete('doesnotexist') is None
assert fs.exists('tdir/banana') is False assert fs.exists('tdir/banana') is False
print('Test finished successfully') print('Test finished successfully')

View file

@ -15,4 +15,4 @@ assert gps.locate(debug=True) is None
assert gps.locate(timeout=5, debug=True) is None assert gps.locate(timeout=5, debug=True) is None
print('Test finished successfully') print('Test finished successfully')

View file

@ -6,9 +6,9 @@ _lib = import_file('_lib.py', __file__)
assert _lib.get_class_table(gps) == _lib.get_object_table('gps') assert _lib.get_class_table(gps) == _lib.get_object_table('gps')
assert gps.locate() == ( assert gps.locate() == (
_lib.AnyInstanceOf(int), _lib.AnyInstanceOf(int),
_lib.AnyInstanceOf(int), _lib.AnyInstanceOf(int),
_lib.AnyInstanceOf(int), _lib.AnyInstanceOf(int),
) )
print('Test finished successfully') print('Test finished successfully')

View file

@ -26,4 +26,4 @@ assert help.path() == '/kek'
assert help.topics() == ['index'] assert help.topics() == ['index']
assert help.setPath('/rom/help') is None assert help.setPath('/rom/help') is None
print('Test finished successfully') print('Test finished successfully')

View file

@ -17,4 +17,4 @@ assert keys.getName(enter) == 'enter'
# for i in range(255): # for i in range(255):
# print(i, keys.getName(i)) # print(i, keys.getName(i))
print('Test finished successfully') print('Test finished successfully')

View file

@ -27,4 +27,4 @@ assert multishell.getTitle(2) is None
assert multishell.launch({}, 'rom/programs/fun/hello.lua') == 2 assert multishell.launch({}, 'rom/programs/fun/hello.lua') == 2
assert isinstance(multishell.getTitle(2), str) assert isinstance(multishell.getTitle(2), str)
print('Test finished successfully') print('Test finished successfully')

View file

@ -25,11 +25,11 @@ assert _lib.get_class_table(os) == tbl
with _lib.assert_takes_time(1.5, 3): with _lib.assert_takes_time(1.5, 3):
timer_id = os.startTimer(2) timer_id = os.startTimer(2)
for e in os.captureEvent('timer'): for e in os.captureEvent('timer'):
if e[0] == timer_id: if e[0] == timer_id:
print('Timer reached') print('Timer reached')
break break
timer_id = os.startTimer(20) timer_id = os.startTimer(20)
@ -43,7 +43,7 @@ assert os.cancelAlarm(alarm_id) is None
assert os.cancelAlarm(alarm_id) is None assert os.cancelAlarm(alarm_id) is None
with _lib.assert_takes_time(1.5, 3): with _lib.assert_takes_time(1.5, 3):
assert os.sleep(2) is None assert os.sleep(2) is None
assert (os.version()).startswith('CraftOS ') assert (os.version()).startswith('CraftOS ')
assert isinstance(os.getComputerID(), int) assert isinstance(os.getComputerID(), int)
@ -62,4 +62,4 @@ assert isinstance(os.clock(), (int, float))
assert os.run({}, 'rom/programs/fun/hello.lua') is True assert os.run({}, 'rom/programs/fun/hello.lua') is True
print('Test finished successfully') print('Test finished successfully')

View file

@ -28,7 +28,7 @@ bbbbbbbbbbbbbbbbbbbbbb399399bbbbbbbbbbbbbbbbbbbbb
assert _lib.get_class_table(paintutils) == _lib.get_object_table('paintutils') assert _lib.get_class_table(paintutils) == _lib.get_object_table('paintutils')
with fs.open('img.nfp', 'w') as f: with fs.open('img.nfp', 'w') as f:
f.write(pixels) f.write(pixels)
int_pixels = paintutils.loadImage('img.nfp') int_pixels = paintutils.loadImage('img.nfp')
assert len(int_pixels) > 0 assert len(int_pixels) > 0
@ -69,4 +69,4 @@ term.setCursorPos(1, by + 6)
os.sleep(2) os.sleep(2)
print('Test finished successfully') print('Test finished successfully')

View file

@ -8,128 +8,128 @@ tags = set()
def partial(tag, fn, *args): def partial(tag, fn, *args):
def wrap(): def wrap():
tags.add(tag) tags.add(tag)
return fn(*args) return fn(*args)
return wrap return wrap
all_parallels = [ all_parallels = [
('waitForAll', parallel.waitForAll), ('waitForAll', parallel.waitForAll),
('waitForAny', parallel.waitForAny), ('waitForAny', parallel.waitForAny),
] ]
for name, fn in all_parallels: for name, fn in all_parallels:
tags.clear() tags.clear()
with assert_takes_time(1.5, 3): with assert_takes_time(1.5, 3):
# Since os.sleep is mostly waiting for events, it doesn't block execution of parallel threads # Since os.sleep is mostly waiting for events, it doesn't block execution of parallel threads
# and this snippet takes approximately 2 seconds to complete. # and this snippet takes approximately 2 seconds to complete.
fn( fn(
partial('a', os.sleep, 2), partial('a', os.sleep, 2),
partial('b', os.sleep, 2), partial('b', os.sleep, 2),
partial('c', os.sleep, 2), partial('c', os.sleep, 2),
) )
assert tags == {'a', 'b', 'c'} assert tags == {'a', 'b', 'c'}
print(name, 'OK') print(name, 'OK')
for name, fn in all_parallels: for name, fn in all_parallels:
tags.clear() tags.clear()
tts = (0, 1) if name == 'waitForAny' else (1.5, 3) tts = (0, 1) if name == 'waitForAny' else (1.5, 3)
with assert_takes_time(*tts): with assert_takes_time(*tts):
fn( fn(
partial('fast', os.version), partial('fast', os.version),
partial('s1', os.sleep, 2), partial('s1', os.sleep, 2),
partial('s2', os.sleep, 2), partial('s2', os.sleep, 2),
) )
assert tags == {'fast', 's1', 's2'} assert tags == {'fast', 's1', 's2'}
print(name, 'fast OK') print(name, 'fast OK')
def breaks_fast(etype): def breaks_fast(etype):
os.sleep(0.5) os.sleep(0.5)
raise etype raise etype
def breaks_slow(etype): def breaks_slow(etype):
os.sleep(3) os.sleep(3)
raise etype raise etype
tags.clear() tags.clear()
with assert_takes_time(0, 1): with assert_takes_time(0, 1):
parallel.waitForAny( parallel.waitForAny(
partial('fast', os.version), partial('fast', os.version),
partial('bomb', breaks_slow, IndexError), partial('bomb', breaks_slow, IndexError),
) )
assert tags == {'fast', 'bomb'} assert tags == {'fast', 'bomb'}
print('waitForAny fast success OK') print('waitForAny fast success OK')
tags.clear() tags.clear()
with assert_takes_time(2.5, 3.8): with assert_takes_time(2.5, 3.8):
with assert_raises(IndexError): with assert_raises(IndexError):
parallel.waitForAll( parallel.waitForAll(
partial('fast', os.version), partial('fast', os.version),
partial('bomb', breaks_slow, IndexError), partial('bomb', breaks_slow, IndexError),
) )
assert tags == {'fast', 'bomb'} assert tags == {'fast', 'bomb'}
print('waitForAll waits for bomb OK') print('waitForAll waits for bomb OK')
for name, fn in all_parallels: for name, fn in all_parallels:
tags.clear() tags.clear()
with assert_takes_time(0.4, 1.2): with assert_takes_time(0.4, 1.2):
with assert_raises(ValueError): with assert_raises(ValueError):
fn( fn(
partial('v', breaks_fast, ValueError), partial('v', breaks_fast, ValueError),
partial('s', os.sleep, 2), partial('s', os.sleep, 2),
partial('i', breaks_slow, IndexError), partial('i', breaks_slow, IndexError),
) )
os.sleep(4) os.sleep(4)
assert tags == {'v', 's', 'i'} assert tags == {'v', 's', 'i'}
print(name + ' handles error OK') print(name + ' handles error OK')
for name, fn in all_parallels: for name, fn in all_parallels:
tags.clear() tags.clear()
with assert_takes_time(1.5, 3): with assert_takes_time(1.5, 3):
fn( fn(
partial('1_s', os.sleep, 2), partial('1_s', os.sleep, 2),
partial( partial(
'1_p', '1_p',
fn, fn,
partial('2_s', os.sleep, 2), partial('2_s', os.sleep, 2),
partial( partial(
'2_p', '2_p',
fn, fn,
partial('3_s', os.sleep, 2), partial('3_s', os.sleep, 2),
), ),
), ),
) )
assert tags == {'1_s', '1_p', '2_s', '2_p', '3_s'} assert tags == {'1_s', '1_p', '2_s', '2_p', '3_s'}
print('Nested', name, 'OK') print('Nested', name, 'OK')
def nested_err(): def nested_err():
parallel.waitForAll( parallel.waitForAll(
partial('n_v', breaks_fast, ValueError), partial('n_v', breaks_fast, ValueError),
partial('n_s', os.sleep, 2), partial('n_s', os.sleep, 2),
partial('n_i', breaks_slow, IndexError), partial('n_i', breaks_slow, IndexError),
) )
tags.clear() tags.clear()
with assert_takes_time(0.4, 1.2): with assert_takes_time(0.4, 1.2):
with assert_raises(ValueError): with assert_raises(ValueError):
parallel.waitForAll( parallel.waitForAll(
nested_err, nested_err,
partial('s', os.sleep, 2), partial('s', os.sleep, 2),
partial('i', breaks_slow, IndexError), partial('i', breaks_slow, IndexError),
) )
assert tags == {'s', 'i', 'n_v', 'n_s', 'n_i'} assert tags == {'s', 'i', 'n_v', 'n_s', 'n_i'}
print('Nested errors OK') print('Nested errors OK')
print('Test finished successfully') print('Test finished successfully')

View file

@ -37,4 +37,4 @@ assert d.isDiskPresent() is False
print('Remove disk drive') print('Remove disk drive')
print('Test finished successfully') print('Test finished successfully')

View file

@ -25,7 +25,7 @@ assert m.runCommand() is None
assert m.setCommand('') is None assert m.setCommand('') is None
assert m.getCommand() == '' assert m.getCommand() == ''
with _lib.assert_raises(LuaException): with _lib.assert_raises(LuaException):
m.runCommand() m.runCommand()
print('You must have seen chat message') print('You must have seen chat message')
print('Test finished successfully') print('Test finished successfully')

View file

@ -2,4 +2,4 @@ from cc import import_file
_lib = import_file('_lib.py', __file__) _lib = import_file('_lib.py', __file__)
_lib._computer_peri('another computer', 'computer') _lib._computer_peri('another computer', 'computer')

View file

@ -60,9 +60,9 @@ assert label != 'label'
print(f'Label is {label}') print(f'Label is {label}')
assert d.getDiskLabel() == label assert d.getDiskLabel() == label
with _lib.assert_raises(LuaException): with _lib.assert_raises(LuaException):
d.setDiskLabel('label') d.setDiskLabel('label')
with _lib.assert_raises(LuaException): with _lib.assert_raises(LuaException):
d.setDiskLabel(None) d.setDiskLabel(None)
# no effect # no effect
assert d.getDiskLabel() == label assert d.getDiskLabel() == label
@ -73,4 +73,4 @@ _lib.step('Audio must be playing now')
assert d.stopAudio() is None assert d.stopAudio() is None
assert d.ejectDisk() is None assert d.ejectDisk() is None
print('Test finished successfully') print('Test finished successfully')

View file

@ -8,10 +8,10 @@ _lib = import_file('_lib.py', __file__)
side = 'back' side = 'back'
_lib.step( _lib.step(
f'Attach modem to {side} side of computer\n' f'Attach modem to {side} side of computer\n'
f'Place another computer with similar modem at {side} side\n' f'Place another computer with similar modem at {side} side\n'
'In case of wired modems connect them\n' 'In case of wired modems connect them\n'
'On another computer start py modem_server.py' 'On another computer start py modem_server.py'
) )
m = peripheral.wrap(side) m = peripheral.wrap(side)
@ -22,25 +22,25 @@ messages = []
def _send(): def _send():
for msg in [ for msg in [
1, 1,
b'hi', b'hi',
{b'data': 5}, {b'data': 5},
b'stop', b'stop',
]: ]:
os.sleep(1) os.sleep(1)
m.transmit(remote_channel, local_channel, msg) m.transmit(remote_channel, local_channel, msg)
def _recv(): def _recv():
assert m.isOpen(local_channel) is False assert m.isOpen(local_channel) is False
for msg in m.receive(local_channel): for msg in m.receive(local_channel):
assert m.isOpen(local_channel) is True assert m.isOpen(local_channel) is True
assert msg.reply_channel == remote_channel assert msg.reply_channel == remote_channel
assert msg.distance > 0 assert msg.distance > 0
messages.append(msg.content) messages.append(msg.content)
if len(messages) == 3: if len(messages) == 3:
break break
assert m.closeAll() is None assert m.closeAll() is None
@ -51,4 +51,4 @@ assert m.isOpen(local_channel) is False
assert m.closeAll() is None assert m.closeAll() is None
assert isinstance(m.isWireless(), bool) assert isinstance(m.isWireless(), bool)
print('Test finished successfully') print('Test finished successfully')

View file

@ -8,8 +8,8 @@ _lib = import_file('_lib.py', __file__)
side = 'left' side = 'left'
_lib.step( _lib.step(
'Use advanced computer and monitor for colors\n' 'Use advanced computer and monitor for colors\n'
f'Place single block monitor on {side} side of computer', f'Place single block monitor on {side} side of computer',
) )
m = peripheral.wrap(side) m = peripheral.wrap(side)
@ -50,25 +50,25 @@ _lib.step('You must have seen word Alpha with blinking cursor')
assert m.clear() is None assert m.clear() is None
assert m.setCursorBlink(False) is None assert m.setCursorBlink(False) is None
for offs, (tc, bc) in enumerate(( for offs, (tc, bc) in enumerate((
(colors.lime, colors.green), (colors.lime, colors.green),
(colors.yellow, colors.brown), (colors.yellow, colors.brown),
(colors.red, colors.orange), (colors.red, colors.orange),
), start=1): ), start=1):
assert m.setTextColor(tc) is None assert m.setTextColor(tc) is None
assert m.getTextColor() == tc assert m.getTextColor() == tc
assert m.setBackgroundColor(bc) is None assert m.setBackgroundColor(bc) is None
assert m.getBackgroundColor() == bc assert m.getBackgroundColor() == bc
assert m.setCursorPos(offs, offs) is None assert m.setCursorPos(offs, offs) is None
assert m.getCursorPos() == (offs, offs) assert m.getCursorPos() == (offs, offs)
assert m.write('text') is None assert m.write('text') is None
assert m.setBackgroundColor(colors.black) is None assert m.setBackgroundColor(colors.black) is None
os.sleep(1) os.sleep(1)
for i in range(2): for i in range(2):
assert m.scroll(-1) is None assert m.scroll(-1) is None
os.sleep(0.5) os.sleep(0.5)
for i in range(2): for i in range(2):
assert m.scroll(1) is None assert m.scroll(1) is None
os.sleep(0.5) os.sleep(0.5)
_lib.step('You must have seen three texts with different colors scrolling') _lib.step('You must have seen three texts with different colors scrolling')
@ -76,12 +76,12 @@ assert m.setTextColor(colors.white) is None
assert m.setBackgroundColor(colors.black) is None assert m.setBackgroundColor(colors.black) is None
assert m.clear() is None assert m.clear() is None
for i in range(1, 5): for i in range(1, 5):
assert m.setCursorPos(1, i) is None assert m.setCursorPos(1, i) is None
assert m.write((str(i) + ' ') * 4) is None assert m.write((str(i) + ' ') * 4) is None
os.sleep(2) os.sleep(2)
for i in range(2, 5, 2): for i in range(2, 5, 2):
assert m.setCursorPos(1, i) is None assert m.setCursorPos(1, i) is None
assert m.clearLine() is None assert m.clearLine() is None
_lib.step('You must have seen some lines disappearing') _lib.step('You must have seen some lines disappearing')
@ -89,15 +89,15 @@ assert m.setBackgroundColor(colors.black) is None
assert m.clear() is None assert m.clear() is None
assert m.setCursorPos(1, 1) is None assert m.setCursorPos(1, 1) is None
assert m.blit( assert m.blit(
'rainbow', 'rainbow',
b'e14d3ba', b'e14d3ba',
b'fffffff', b'fffffff',
) is None ) is None
assert m.setCursorPos(1, 2) is None assert m.setCursorPos(1, 2) is None
assert m.blit( assert m.blit(
'rainbow', 'rainbow',
b'0000000', b'0000000',
b'e14d3ba', b'e14d3ba',
) is None ) is None
_lib.step('You must have seen per-letter colored text') _lib.step('You must have seen per-letter colored text')
@ -118,27 +118,27 @@ assert m.setTextScale(1) is None
assert m.setBackgroundColor(colors.white) is None assert m.setBackgroundColor(colors.white) is None
assert m.clear() is None assert m.clear() is None
for i, color in enumerate(colors.iter_colors()): for i, color in enumerate(colors.iter_colors()):
m.setPaletteColor(color, i / 15, 0, 0) m.setPaletteColor(color, i / 15, 0, 0)
assert m.setCursorPos(1, 1) is None assert m.setCursorPos(1, 1) is None
assert m.blit( assert m.blit(
' redtex', ' redtex',
b'0123456', b'0123456',
b'0000000', b'0000000',
) is None ) is None
assert m.setCursorPos(1, 2) is None assert m.setCursorPos(1, 2) is None
assert m.blit( assert m.blit(
'tappear', 'tappear',
b'789abcd', b'789abcd',
b'0000000', b'0000000',
) is None ) is None
assert m.setCursorPos(1, 3) is None assert m.setCursorPos(1, 3) is None
assert m.blit( assert m.blit(
's!', 's!',
b'ef', b'ef',
b'00', b'00',
) is None ) is None
_lib.step('You must have seen different shades of red made using palettes') _lib.step('You must have seen different shades of red made using palettes')
print('Remove monitor') print('Remove monitor')
print('Test finished successfully') print('Test finished successfully')

View file

@ -21,17 +21,17 @@ assert m.getInkLevel() == 0
assert m.newPage() is False assert m.newPage() is False
# page not started # page not started
with assert_raises(LuaException): with assert_raises(LuaException):
m.endPage() m.endPage()
with assert_raises(LuaException): with assert_raises(LuaException):
m.write('test') m.write('test')
with assert_raises(LuaException): with assert_raises(LuaException):
m.setCursorPos(2, 2) m.setCursorPos(2, 2)
with assert_raises(LuaException): with assert_raises(LuaException):
m.getCursorPos() m.getCursorPos()
with assert_raises(LuaException): with assert_raises(LuaException):
m.getPageSize() m.getPageSize()
with assert_raises(LuaException): with assert_raises(LuaException):
m.setPageTitle('title') m.setPageTitle('title')
_lib.step('Put paper into printer') _lib.step('Put paper into printer')
paper_level = m.getPaperLevel() paper_level = m.getPaperLevel()
@ -56,39 +56,39 @@ assert m.getPageSize() == (25, 21)
def row(n=1): def row(n=1):
_, r = m.getCursorPos() _, r = m.getCursorPos()
m.setCursorPos(1, r + n) m.setCursorPos(1, r + n)
def split_text(text, max_width=25): def split_text(text, max_width=25):
for i in range(0, len(text), max_width): for i in range(0, len(text), max_width):
yield text[i:i + max_width] yield text[i:i + max_width]
def split_by_words(text, max_width=25): def split_by_words(text, max_width=25):
stack = [] stack = []
stack_len = 0 stack_len = 0
for word in text.split(' '): for word in text.split(' '):
assert len(word) <= max_width assert len(word) <= max_width
with_word = len(word) if stack_len == 0 else stack_len + 1 + len(word) with_word = len(word) if stack_len == 0 else stack_len + 1 + len(word)
if with_word > max_width: if with_word > max_width:
yield ' '.join(stack) yield ' '.join(stack)
stack.clear() stack.clear()
stack_len = 0 stack_len = 0
else: else:
stack.append(word) stack.append(word)
stack_len = with_word stack_len = with_word
if stack: if stack:
yield ' '.join(stack) yield ' '.join(stack)
def multiline_write(text): def multiline_write(text):
_, r = m.getCursorPos() _, r = m.getCursorPos()
for pt in split_by_words(text): for pt in split_by_words(text):
assert m.setCursorPos(1, r) is None assert m.setCursorPos(1, r) is None
assert m.write(pt) is None assert m.write(pt) is None
r += 1 r += 1
assert m.setCursorPos(1, r) is None assert m.setCursorPos(1, r) is None
assert m.write('Green bottles'.center(25)) is None assert m.write('Green bottles'.center(25)) is None
@ -96,13 +96,13 @@ row(2)
x = 2 x = 2
while x > 0: while x > 0:
multiline_write(f'{x} green bottles hanging on the wall') multiline_write(f'{x} green bottles hanging on the wall')
multiline_write(f'{x} green bottles hanging on the wall') multiline_write(f'{x} green bottles hanging on the wall')
multiline_write('if one green bottle accidently falls') multiline_write('if one green bottle accidently falls')
x -= 1 x -= 1
multiline_write(f'there will be {x} hanging on the wall') multiline_write(f'there will be {x} hanging on the wall')
row() row()
assert m.endPage() is True assert m.endPage() is True
print('Test finished successfully') print('Test finished successfully')

View file

@ -22,9 +22,9 @@ assert isinstance(names, list)
assert len(names) > 0 assert len(names) > 0
speaker = [] speaker = []
for n in names: for n in names:
assert isinstance(n, str) assert isinstance(n, str)
if n.startswith('speaker_'): if n.startswith('speaker_'):
speaker.append(n) speaker.append(n)
assert len(speaker) == 1 assert len(speaker) == 1
speaker = speaker[0] speaker = speaker[0]
@ -40,4 +40,4 @@ s = m.wrapRemote(speaker)
assert s.playSound('minecraft:entity.player.levelup') is True assert s.playSound('minecraft:entity.player.levelup') is True
print('You must have heard levelup sound') print('You must have heard levelup sound')
print('Test finished successfully') print('Test finished successfully')

View file

@ -17,18 +17,18 @@ tbl = _lib.get_object_table(f'peripheral.wrap("{side}")')
assert _lib.get_class_table(CCSpeaker) == tbl assert _lib.get_class_table(CCSpeaker) == tbl
for _ in range(48): for _ in range(48):
assert m.playNote( assert m.playNote(
random.choice([ random.choice([
'bass', 'basedrum', 'bell', 'chime', 'flute', 'guitar', 'hat', 'bass', 'basedrum', 'bell', 'chime', 'flute', 'guitar', 'hat',
'snare', 'xylophone', 'iron_xylophone', 'pling', 'banjo', 'snare', 'xylophone', 'iron_xylophone', 'pling', 'banjo',
'bit', 'didgeridoo', 'cow_bell', 'bit', 'didgeridoo', 'cow_bell',
]), ]),
3, 3,
random.randint(0, 24) random.randint(0, 24)
) is True ) is True
os.sleep(0.2) os.sleep(0.2)
assert m.playSound('minecraft:entity.player.levelup') is True assert m.playSound('minecraft:entity.player.levelup') is True
print('You must have heard notes and sounds') print('You must have heard notes and sounds')
print('Test finished successfully') print('Test finished successfully')

View file

@ -2,4 +2,4 @@ from cc import import_file
_lib = import_file('_lib.py', __file__) _lib = import_file('_lib.py', __file__)
_lib._computer_peri('turtle', 'turtle') _lib._computer_peri('turtle', 'turtle')

View file

@ -11,9 +11,9 @@ assert _lib.get_class_table(pocket) == tbl
_lib.step('Clean inventory from any pocket upgrades') _lib.step('Clean inventory from any pocket upgrades')
with _lib.assert_raises(LuaException): with _lib.assert_raises(LuaException):
pocket.equipBack() pocket.equipBack()
with _lib.assert_raises(LuaException): with _lib.assert_raises(LuaException):
pocket.unequipBack() pocket.unequipBack()
assert peripheral.isPresent('back') is False assert peripheral.isPresent('back') is False
_lib.step('Put any pocket upgrade to inventory') _lib.step('Put any pocket upgrade to inventory')
@ -24,4 +24,4 @@ assert peripheral.isPresent('back') is True
assert pocket.unequipBack() is None assert pocket.unequipBack() is None
assert peripheral.isPresent('back') is False assert peripheral.isPresent('back') is False
print('Test finished successfully') print('Test finished successfully')

View file

@ -2,4 +2,4 @@ from cc import os
assert os.reboot() is None assert os.reboot() is None
print('Test finished successfully') print('Test finished successfully')

View file

@ -7,10 +7,10 @@ side = 'left'
_lib.step(f'Attach 3x3 color monitor to {side} side of computer') _lib.step(f'Attach 3x3 color monitor to {side} side of computer')
with term.redirect(peripheral.get_term_target(side)): with term.redirect(peripheral.get_term_target(side)):
term.setBackgroundColor(colors.green) term.setBackgroundColor(colors.green)
term.setTextColor(colors.white) term.setTextColor(colors.white)
term.clear() term.clear()
term.setCursorPos(1, 1) term.setCursorPos(1, 1)
print('Redirected to monitor') print('Redirected to monitor')
print('Test finished successfully') print('Test finished successfully')

View file

@ -11,16 +11,16 @@ mod = peripheral.wrap(side)
_lib.step('Connect remote monitor using wires, activate its modem') _lib.step('Connect remote monitor using wires, activate its modem')
for name in mod.getNamesRemote(): for name in mod.getNamesRemote():
if mod.getTypeRemote(name) == 'monitor': if mod.getTypeRemote(name) == 'monitor':
break break
else: else:
assert False assert False
with term.redirect(peripheral.get_term_target(name)): with term.redirect(peripheral.get_term_target(name)):
term.setBackgroundColor(colors.blue) term.setBackgroundColor(colors.blue)
term.setTextColor(colors.white) term.setTextColor(colors.white)
term.clear() term.clear()
term.setCursorPos(1, 1) term.setCursorPos(1, 1)
print('Redirected to monitor') print('Redirected to monitor')
print('Test finished successfully') print('Test finished successfully')

View file

@ -5,26 +5,26 @@ from cc import colors, term, window
w, h = term.getSize() w, h = term.getSize()
with ExitStack() as stack: with ExitStack() as stack:
left = stack.enter_context(window.create( left = stack.enter_context(window.create(
term.get_current_target(), term.get_current_target(),
1, 1, w // 2, h, True, 1, 1, w // 2, h, True,
)) ))
right = stack.enter_context(window.create( right = stack.enter_context(window.create(
term.get_current_target(), term.get_current_target(),
w // 2 + 1, 1, w // 2, h, True, w // 2 + 1, 1, w // 2, h, True,
)) ))
with term.redirect(left.get_term_target()): with term.redirect(left.get_term_target()):
term.setBackgroundColor(colors.green) term.setBackgroundColor(colors.green)
term.setTextColor(colors.white) term.setTextColor(colors.white)
term.clear() term.clear()
term.setCursorPos(1, h // 2) term.setCursorPos(1, h // 2)
print('Left part') print('Left part')
with term.redirect(right.get_term_target()): with term.redirect(right.get_term_target()):
term.setBackgroundColor(colors.red) term.setBackgroundColor(colors.red)
term.setTextColor(colors.yellow) term.setTextColor(colors.yellow)
term.clear() term.clear()
term.setCursorPos(1, h // 2) term.setCursorPos(1, h // 2)
print('Right part') print('Right part')
print('Default terminal restored') print('Default terminal restored')
print('Test finished successfully') print('Test finished successfully')

View file

@ -18,19 +18,19 @@ assert rednet.isOpen(side) is False
assert rednet.isOpen() is False assert rednet.isOpen() is False
with assert_raises(LuaException): with assert_raises(LuaException):
rednet.close('doesnotexist') rednet.close('doesnotexist')
assert rednet.close(side) is None assert rednet.close(side) is None
with assert_raises(LuaException): with assert_raises(LuaException):
rednet.open('doesnotexist') rednet.open('doesnotexist')
assert rednet.open(side) is None assert rednet.open(side) is None
assert rednet.isOpen(side) is True assert rednet.isOpen(side) is True
with assert_raises(LuaException): with assert_raises(LuaException):
# disallowed hostname # disallowed hostname
rednet.host('helloproto', 'localhost') rednet.host('helloproto', 'localhost')
assert rednet.host('helloproto', 'alpha') is None assert rednet.host('helloproto', 'alpha') is None
cid = os.getComputerID() cid = os.getComputerID()
@ -49,11 +49,11 @@ assert rednet.receive(timeout=1) is None
def _send(): def _send():
assert rednet.send(cid, b'message') is True assert rednet.send(cid, b'message') is True
def _recv(): def _recv():
assert rednet.receive(timeout=1) == (cid, b'message', None) assert rednet.receive(timeout=1) == (cid, b'message', None)
parallel.waitForAll(_send, _recv) parallel.waitForAll(_send, _recv)
@ -61,4 +61,4 @@ parallel.waitForAll(_send, _recv)
assert rednet.close() is None assert rednet.close() is None
assert rednet.isOpen(side) is False assert rednet.isOpen(side) is False
print('Test finished successfully') print('Test finished successfully')

View file

@ -52,4 +52,4 @@ assert redstone.setOutput(side, False) is None
print('Piston must have been activated\nRemove piston') print('Piston must have been activated\nRemove piston')
print('Test finished successfully') print('Test finished successfully')

View file

@ -18,37 +18,37 @@ assert settings.define('test.c', type='string') is None
assert settings.define('test.d', default=42) is None assert settings.define('test.d', default=42) is None
assert settings.getDetails('test.a') == { assert settings.getDetails('test.a') == {
'changed': False, 'changed': False,
} }
assert settings.getDetails('test.b') == { assert settings.getDetails('test.b') == {
'changed': False, 'changed': False,
'description': 'b', 'description': 'b',
} }
assert settings.getDetails('test.c') == { assert settings.getDetails('test.c') == {
'changed': False, 'changed': False,
'type': 'string', 'type': 'string',
} }
assert settings.getDetails('test.d') == { assert settings.getDetails('test.d') == {
'changed': False, 'changed': False,
'default': 42, 'default': 42,
'value': 42, 'value': 42,
} }
# redefining # redefining
assert settings.define('test.a', type='number', default=11) is None assert settings.define('test.a', type='number', default=11) is None
assert settings.getDetails('test.a') == { assert settings.getDetails('test.a') == {
'changed': False, 'changed': False,
'type': 'number', 'type': 'number',
'default': 11, 'default': 11,
'value': 11, 'value': 11,
} }
assert settings.get('test.a') == 11 assert settings.get('test.a') == 11
assert settings.set('test.a', 12) is None assert settings.set('test.a', 12) is None
assert settings.get('test.a') == 12 assert settings.get('test.a') == 12
with assert_raises(LuaException): with assert_raises(LuaException):
settings.set('test.a', b'text') settings.set('test.a', b'text')
assert settings.get('test.a') == 12 assert settings.get('test.a') == 12
assert settings.unset('test.a') is None assert settings.unset('test.a') is None
assert settings.get('test.a') == 11 assert settings.get('test.a') == 11
@ -65,15 +65,15 @@ assert settings.undefine('test.d') is None
assert 'test.c' in settings.getNames() assert 'test.c' in settings.getNames()
assert settings.get('test.c') == b'hello' assert settings.get('test.c') == b'hello'
assert settings.getDetails('test.c') == { assert settings.getDetails('test.c') == {
'changed': True, 'changed': True,
'value': b'hello', 'value': b'hello',
} }
assert settings.unset('test.c') is None assert settings.unset('test.c') is None
assert settings.get('test.c') is None assert settings.get('test.c') is None
assert settings.getDetails('test.c') == { assert settings.getDetails('test.c') == {
'changed': False, 'changed': False,
} }
assert {'test.a', 'test.b', 'test.c', 'test.d'} & set(settings.getNames()) == set() assert {'test.a', 'test.b', 'test.c', 'test.d'} & set(settings.getNames()) == set()
@ -98,4 +98,4 @@ assert settings.load('sfile') is True
fs.delete('sfile') fs.delete('sfile')
print('Test finished successfully') print('Test finished successfully')

View file

@ -58,4 +58,4 @@ _lib.step('Computer will shutdown after test due to shell.exit')
assert shell.exit() is None assert shell.exit() is None
print('Test finished successfully') print('Test finished successfully')

View file

@ -2,4 +2,4 @@ from cc import os
assert os.shutdown() is None assert os.shutdown() is None
print('Test finished successfully') print('Test finished successfully')

View file

@ -25,9 +25,9 @@ del tbl['function']['setTextColour']
assert _lib.get_class_table(TermMixin) == tbl assert _lib.get_class_table(TermMixin) == tbl
_lib.step( _lib.step(
'Detach all monitors\n' 'Detach all monitors\n'
'Use advanced computer for colors\n' 'Use advanced computer for colors\n'
'Screen will be cleared' 'Screen will be cleared'
) )
assert term.getSize() == (51, 19) assert term.getSize() == (51, 19)
@ -47,36 +47,36 @@ _lib.term_step('You must have seen word Alpha with blinking cursor')
assert term.clear() is None assert term.clear() is None
for offs, (tc, bc) in enumerate(( for offs, (tc, bc) in enumerate((
(colors.lime, colors.green), (colors.lime, colors.green),
(colors.yellow, colors.brown), (colors.yellow, colors.brown),
(colors.red, colors.orange), (colors.red, colors.orange),
), start=1): ), start=1):
assert term.setTextColor(tc) is None assert term.setTextColor(tc) is None
assert term.getTextColor() == tc assert term.getTextColor() == tc
assert term.setBackgroundColor(bc) is None assert term.setBackgroundColor(bc) is None
assert term.getBackgroundColor() == bc assert term.getBackgroundColor() == bc
assert term.setCursorPos(offs * 2, offs) is None assert term.setCursorPos(offs * 2, offs) is None
assert term.getCursorPos() == (offs * 2, offs) assert term.getCursorPos() == (offs * 2, offs)
assert term.write('text with colors') is None assert term.write('text with colors') is None
assert term.setBackgroundColor(colors.black) is None assert term.setBackgroundColor(colors.black) is None
os.sleep(1) os.sleep(1)
for i in range(3): for i in range(3):
assert term.scroll(-2) is None assert term.scroll(-2) is None
os.sleep(0.5) os.sleep(0.5)
for i in range(6): for i in range(6):
assert term.scroll(1) is None assert term.scroll(1) is None
os.sleep(0.25) os.sleep(0.25)
_lib.term_step('You must have seen three texts with different colors scrolling') _lib.term_step('You must have seen three texts with different colors scrolling')
assert term.clear() is None assert term.clear() is None
for i in range(1, 10): for i in range(1, 10):
assert term.setCursorPos(1, i) is None assert term.setCursorPos(1, i) is None
assert term.write((str(i) + ' ') * 10) is None assert term.write((str(i) + ' ') * 10) is None
os.sleep(2) os.sleep(2)
for i in range(2, 10, 2): for i in range(2, 10, 2):
assert term.setCursorPos(1, i) is None assert term.setCursorPos(1, i) is None
assert term.clearLine() is None assert term.clearLine() is None
os.sleep(2) os.sleep(2)
_lib.term_step('You must have seen some lines disappearing') _lib.term_step('You must have seen some lines disappearing')
@ -84,9 +84,9 @@ _lib.term_step('You must have seen some lines disappearing')
assert term.clear() is None assert term.clear() is None
assert term.setCursorPos(1, 1) is None assert term.setCursorPos(1, 1) is None
assert term.blit( assert term.blit(
'rainbowrainbow', 'rainbowrainbow',
b'e14d3ba0000000', b'e14d3ba0000000',
b'fffffffe14d3ba', b'fffffffe14d3ba',
) is None ) is None
os.sleep(3) os.sleep(3)
@ -96,14 +96,14 @@ assert term.setBackgroundColor(colors.white) is None
assert term.clear() is None assert term.clear() is None
assert term.setCursorPos(1, 1) is None assert term.setCursorPos(1, 1) is None
for i, color in enumerate(colors.iter_colors()): for i, color in enumerate(colors.iter_colors()):
term.setPaletteColor(color, i / 15, 0, 0) term.setPaletteColor(color, i / 15, 0, 0)
assert term.blit( assert term.blit(
' redtextappears!', ' redtextappears!',
b'0123456789abcdef', b'0123456789abcdef',
b'0000000000000000', b'0000000000000000',
) is None ) is None
os.sleep(3) os.sleep(3)
_lib.term_step('You must have seen different shades of red made using palettes') _lib.term_step('You must have seen different shades of red made using palettes')
print('Test finished successfully') print('Test finished successfully')

View file

@ -10,25 +10,25 @@ assert textutils.formatTime(0) == '0:00 AM'
assert textutils.formatTime(0, True) == '0:00' assert textutils.formatTime(0, True) == '0:00'
table = [ table = [
colors.red, colors.red,
['Planet', 'Distance', 'Mass'], ['Planet', 'Distance', 'Mass'],
colors.gray, colors.gray,
['Mercury', '0.387', '0.055'], ['Mercury', '0.387', '0.055'],
colors.lightGray, colors.lightGray,
['Venus', '0.723', '0.815'], ['Venus', '0.723', '0.815'],
colors.green, colors.green,
['Earth', '1.000', '1.000'], ['Earth', '1.000', '1.000'],
colors.red, colors.red,
['Mars', '1.524', '0.107'], ['Mars', '1.524', '0.107'],
colors.orange, colors.orange,
['Jupiter', '5.203', '318'], ['Jupiter', '5.203', '318'],
colors.yellow, colors.yellow,
['Saturn', '9.537', '95'], ['Saturn', '9.537', '95'],
colors.cyan, colors.cyan,
['Uranus', '19.191', '14.5'], ['Uranus', '19.191', '14.5'],
colors.blue, colors.blue,
['Neptune', '30.069', '17'], ['Neptune', '30.069', '17'],
colors.white, colors.white,
] ]
assert textutils.tabulate(*table) is None assert textutils.tabulate(*table) is None
@ -47,6 +47,6 @@ assert lines > 0
assert textutils.pagedTabulate(*table[:-1], *table[2:-1], *table[2:]) is None assert textutils.pagedTabulate(*table[:-1], *table[2:-1], *table[2:]) is None
assert textutils.complete('co', ['command', 'row', 'column']) == [ assert textutils.complete('co', ['command', 'row', 'column']) == [
'mmand', 'lumn'] 'mmand', 'lumn']
print('Test finished successfully') print('Test finished successfully')

View file

@ -21,7 +21,7 @@ assert 0 <= flevel <= flimit
assert turtle.select(2) is None assert turtle.select(2) is None
assert turtle.getSelectedSlot() == 2 assert turtle.getSelectedSlot() == 2
with assert_raises(LuaException): with assert_raises(LuaException):
turtle.select(0) turtle.select(0)
assert turtle.select(1) is None assert turtle.select(1) is None
assert turtle.getSelectedSlot() == 1 assert turtle.getSelectedSlot() == 1
@ -31,12 +31,12 @@ assert turtle.getItemCount() == 3
assert turtle.getItemCount(1) == 3 assert turtle.getItemCount(1) == 3
assert turtle.getItemDetail() == { assert turtle.getItemDetail() == {
b'count': 3, # TODO: binary output b'count': 3, # TODO: binary output
b'name': b'minecraft:coal', b'name': b'minecraft:coal',
} }
assert turtle.getItemDetail(1) == { assert turtle.getItemDetail(1) == {
b'count': 3, b'count': 3,
b'name': b'minecraft:coal', b'name': b'minecraft:coal',
} }
assert turtle.getItemSpace() == 61 assert turtle.getItemSpace() == 61
@ -54,9 +54,9 @@ assert turtle.getFuelLevel() > flevel
assert turtle.getItemCount() == 0 assert turtle.getItemCount() == 0
with assert_raises(LuaException): with assert_raises(LuaException):
turtle.refuel(1) turtle.refuel(1)
with assert_raises(LuaException): with assert_raises(LuaException):
turtle.refuel() turtle.refuel()
step('Remove blocks in front/below/above turtle') step('Remove blocks in front/below/above turtle')
@ -75,12 +75,12 @@ assert turtle.detectUp() is True
assert turtle.detectDown() is True assert turtle.detectDown() is True
for c in [ for c in [
turtle.inspect(), turtle.inspect(),
turtle.inspectUp(), turtle.inspectUp(),
turtle.inspectDown() turtle.inspectDown()
]: ]:
assert isinstance(c, dict) assert isinstance(c, dict)
assert c[b'name'] == b'minecraft:cobblestone' assert c[b'name'] == b'minecraft:cobblestone'
assert turtle.select(1) is None assert turtle.select(1) is None
assert turtle.getItemCount() == 0 assert turtle.getItemCount() == 0
@ -91,17 +91,17 @@ assert turtle.getItemCount() == 0
assert turtle.equipRight() is None assert turtle.equipRight() is None
if ( if (
turtle.getItemCount(1) != 0 turtle.getItemCount(1) != 0
or turtle.getItemCount(2) != 0 or turtle.getItemCount(2) != 0
): ):
step('Remove all items from slots 1 and 2') step('Remove all items from slots 1 and 2')
assert turtle.select(1) is None assert turtle.select(1) is None
if turtle.getItemDetail(1) != { if turtle.getItemDetail(1) != {
b'count': 1, b'count': 1,
b'name': b'minecraft:diamond_pickaxe', b'name': b'minecraft:diamond_pickaxe',
}: }:
step('Put fresh diamond pickaxe at slot 1') step('Put fresh diamond pickaxe at slot 1')
assert turtle.equipLeft() is None assert turtle.equipLeft() is None
@ -127,7 +127,7 @@ assert turtle.placeUp() is True
assert turtle.placeUp() is False assert turtle.placeUp() is False
assert turtle.placeDown() is True assert turtle.placeDown() is True
with assert_raises(LuaException, 'No items to place'): with assert_raises(LuaException, 'No items to place'):
turtle.placeDown() turtle.placeDown()
step('Put 3 cobblestone blocks to slot 1') step('Put 3 cobblestone blocks to slot 1')
@ -173,9 +173,9 @@ assert turtle.getItemCount() == 0
assert turtle.drop() is False assert turtle.drop() is False
step( step(
'Collect dropped cobblestone\n' 'Collect dropped cobblestone\n'
'Drop stack of sticks right in front of the turtle\n' 'Drop stack of sticks right in front of the turtle\n'
'Its better to build 1-block room then throw sticks there', 'Its better to build 1-block room then throw sticks there',
) )
assert turtle.suck(1) is True assert turtle.suck(1) is True
@ -187,9 +187,9 @@ assert turtle.drop() is True
assert turtle.getItemCount() == 0 assert turtle.getItemCount() == 0
step( step(
'Collect dropped sticks\n' 'Collect dropped sticks\n'
'Drop stack of sticks right below the turtle\n' 'Drop stack of sticks right below the turtle\n'
'Its better to build 1-block room then throw sticks there', 'Its better to build 1-block room then throw sticks there',
) )
assert turtle.suckDown(1) is True assert turtle.suckDown(1) is True
@ -201,9 +201,9 @@ assert turtle.dropDown() is True
assert turtle.getItemCount() == 0 assert turtle.getItemCount() == 0
step( step(
'Collect dropped sticks\n' 'Collect dropped sticks\n'
'Drop stack of sticks right above the turtle\n' 'Drop stack of sticks right above the turtle\n'
'Its better to build 1-block room then throw sticks there', 'Its better to build 1-block room then throw sticks there',
) )
assert turtle.suckUp(1) is True assert turtle.suckUp(1) is True
@ -216,12 +216,12 @@ assert turtle.getItemCount() == 0
def craft1(): def craft1():
return turtle.craft() return turtle.craft()
def craft2(): def craft2():
c = peripheral.wrap('right') c = peripheral.wrap('right')
return c.craft() return c.craft()
step('Put crafting table into slot 1') step('Put crafting table into slot 1')
@ -229,20 +229,20 @@ assert turtle.select(1) is None
assert turtle.equipRight() is None assert turtle.equipRight() is None
for craft_fn in craft1, craft2: for craft_fn in craft1, craft2:
step( step(
'Clean inventory of turtle\n' 'Clean inventory of turtle\n'
'Put 8 cobblestones into slot 1', 'Put 8 cobblestones into slot 1',
) )
assert turtle.select(1) is None assert turtle.select(1) is None
assert craft_fn() is False assert craft_fn() is False
for idx in [2, 3, 5, 7, 9, 10, 11]: for idx in [2, 3, 5, 7, 9, 10, 11]:
assert turtle.transferTo(idx, 1) assert turtle.transferTo(idx, 1)
assert craft_fn() is True assert craft_fn() is True
assert craft_fn() is False assert craft_fn() is False
assert turtle.getItemDetail() == { assert turtle.getItemDetail() == {
b'count': 1, b'count': 1,
b'name': b'minecraft:furnace', b'name': b'minecraft:furnace',
} }
print('Test finished successfully') print('Test finished successfully')

View file

@ -4,9 +4,9 @@ _lib = import_file('_lib.py', __file__)
_lib.step( _lib.step(
'NOTE: this test is unreliable\n' 'NOTE: this test is unreliable\n'
'Build 1x1x1 stone cage in front of turtle\n' 'Build 1x1x1 stone cage in front of turtle\n'
'Spawn here a chicken', 'Spawn here a chicken',
) )
assert turtle.attack() is True assert turtle.attack() is True
@ -14,8 +14,8 @@ assert turtle.attack() is True
assert turtle.attack() is False assert turtle.attack() is False
_lib.step( _lib.step(
'Build 1x1x1 stone cage below turtle\n' 'Build 1x1x1 stone cage below turtle\n'
'Spawn here a chicken', 'Spawn here a chicken',
) )
assert turtle.attackDown() is True assert turtle.attackDown() is True
@ -23,12 +23,12 @@ assert turtle.attackDown() is True
assert turtle.attackDown() is False assert turtle.attackDown() is False
_lib.step( _lib.step(
'Build 1x1x1 stone cage above turtle\n' 'Build 1x1x1 stone cage above turtle\n'
'Spawn here a chicken', 'Spawn here a chicken',
) )
assert turtle.attackUp() is True assert turtle.attackUp() is True
assert turtle.attackUp() is True assert turtle.attackUp() is True
assert turtle.attackUp() is False assert turtle.attackUp() is False
print('Test finished successfully') print('Test finished successfully')

View file

@ -2,35 +2,35 @@ from cc import colors, term, os, window
with window.create( with window.create(
term.get_current_target(), term.get_current_target(),
15, 5, 5, 5, False, 15, 5, 5, 5, False,
) as win: ) as win:
assert win.getPosition() == (15, 5) assert win.getPosition() == (15, 5)
assert win.getSize() == (5, 5) assert win.getSize() == (5, 5)
win.setBackgroundColor(colors.red) win.setBackgroundColor(colors.red)
win.clear() win.clear()
win.setVisible(True) win.setVisible(True)
os.sleep(1) os.sleep(1)
win.setVisible(False) win.setVisible(False)
win.setCursorPos(1, 1) win.setCursorPos(1, 1)
win.setTextColor(colors.yellow) win.setTextColor(colors.yellow)
win.write('*********') win.write('*********')
win.setVisible(True) win.setVisible(True)
os.sleep(1) os.sleep(1)
term.clear() term.clear()
os.sleep(1) os.sleep(1)
win.redraw() win.redraw()
assert win.getLine(1) == ('*****', b'44444', b'eeeee') assert win.getLine(1) == ('*****', b'44444', b'eeeee')
# draws immediately # draws immediately
win.reposition(21, 5) win.reposition(21, 5)
win.reposition(27, 5) win.reposition(27, 5)
print('Test finished successfully') print('Test finished successfully')

View file

@ -3,6 +3,6 @@ from cc import os
timer_id = os.startTimer(2) timer_id = os.startTimer(2)
for e in os.captureEvent('timer'): for e in os.captureEvent('timer'):
if e[0] == timer_id: if e[0] == timer_id:
print('Timer reached') print('Timer reached')
break break