From b9029092b88a641f8ff89d8a22c724201d2f40b0 Mon Sep 17 00:00:00 2001 From: Walter Bender Date: Thu, 11 Mar 2010 19:02:59 +0000 Subject: pylint cleanup --- (limited to 'tautils.py') diff --git a/tautils.py b/tautils.py index ab2904f..a0361e8 100644 --- a/tautils.py +++ b/tautils.py @@ -23,7 +23,7 @@ import gtk import pickle import subprocess try: - _old_Sugar_system = False + OLD_SUGAR_SYSTEM = False import json json.dumps from json import load as jload @@ -34,140 +34,175 @@ except (ImportError, AttributeError): from simplejson import load as jload from simplejson import dump as jdump except: - _old_Sugar_system = True - + OLD_SUGAR_SYSTEM = True +from taconstants import STRING_OR_NUMBER_ARGS, HIDE_LAYER, CONTENT_ARGS, \ + COLLAPSIBLE, BLOCK_LAYER, CONTENT_BLOCKS from StringIO import StringIO import os.path +from gettext import gettext as _ + + +''' +The strategy for mixing numbers and strings is to first try +converting the string to a float; then if the string is a single +character, try converting it to an ord; finally, just treat it as a +string. Numbers appended to strings are first trreated as ints, then +floats. +''' +def convert(x, fn, try_ord=True): + try: + return fn(x) + except ValueError: + if try_ord: + xx, flag = chr_to_ord(x) + if flag: + return fn(xx) + return x def magnitude(pos): + """ Calculate the magnitude of the distance between to blocks. """ x, y = pos return x*x+y*y def json_load(text): - if _old_Sugar_system is True: - listdata = json.read(text) + """ Load JSON data using what ever resources are available. """ + if OLD_SUGAR_SYSTEM is True: + _listdata = json.read(text) else: # strip out leading and trailing whitespace, nulls, and newlines text = text.lstrip() text = text.replace('\12','') text = text.replace('\00','') - io = StringIO(text.rstrip()) - listdata = jload(io) + _io = StringIO(text.rstrip()) + _listdata = jload(_io) # json converts tuples to lists, so we need to convert back, - return _tuplify(listdata) + return _tuplify(_listdata) -def _tuplify(t): - if type(t) is not list: - return t - return tuple(map(_tuplify, t)) +def _tuplify(tup): + """ Convert to tuples """ + if type(tup) is not list: + return tup + return tuple(map(_tuplify, tup)) -def get_id(c): - if c is None: +def get_id(connection): + """ Get a connection block ID. """ + if connection is None: return None - return c.id + return connection.id def json_dump(data): - if _old_Sugar_system is True: + """ Save data using available JSON tools. """ + if OLD_SUGAR_SYSTEM is True: return json.write(data) else: - io = StringIO() - jdump(data,io) - return io.getvalue() + _io = StringIO() + jdump(data, _io) + return _io.getvalue() def get_load_name(suffix, load_save_folder): - dialog = gtk.FileChooserDialog("Load...", None, - gtk.FILE_CHOOSER_ACTION_OPEN, - (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, - gtk.STOCK_OPEN, gtk.RESPONSE_OK)) - dialog.set_default_response(gtk.RESPONSE_OK) - return do_dialog(dialog, suffix, load_save_folder) + """ Open a load file dialog. """ + _dialog = gtk.FileChooserDialog("Load...", None, + gtk.FILE_CHOOSER_ACTION_OPEN, + (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, + gtk.STOCK_OPEN, gtk.RESPONSE_OK)) + _dialog.set_default_response(gtk.RESPONSE_OK) + return do_dialog(_dialog, suffix, load_save_folder) def get_save_name(suffix, load_save_folder, save_file_name): - dialog = gtk.FileChooserDialog("Save...", None, - gtk.FILE_CHOOSER_ACTION_SAVE, - (gtk.STOCK_CANCEL, - gtk.RESPONSE_CANCEL, - gtk.STOCK_SAVE, - gtk.RESPONSE_OK)) - dialog.set_default_response(gtk.RESPONSE_OK) + """ Open a save file dialog. """ + _dialog = gtk.FileChooserDialog("Save...", None, + gtk.FILE_CHOOSER_ACTION_SAVE, + (gtk.STOCK_CANCEL, + gtk.RESPONSE_CANCEL, + gtk.STOCK_SAVE, + gtk.RESPONSE_OK)) + _dialog.set_default_response(gtk.RESPONSE_OK) if save_file_name is not None: - dialog.set_current_name(save_file_name+suffix) - return do_dialog(dialog, suffix, load_save_folder) + _dialog.set_current_name(save_file_name+suffix) + return do_dialog(_dialog, suffix, load_save_folder) # # We try to maintain read-compatibility with all versions of Turtle Art. # Try pickle first; then different versions of json. # def data_from_file(ta_file): - # Just open the .ta file, ignoring any .png file that might be present. - f = open(ta_file, "r") + """ Open the .ta file, ignoring any .png file that might be present. """ + file_handle = open(ta_file, "r") try: - data = pickle.load(f) + _data = pickle.load(file_handle) except: # Rewind necessary because of failed pickle.load attempt - f.seek(0) - text = f.read() - data = data_from_string(text) - f.close() - return data + file_handle.seek(0) + _text = file_handle.read() + _data = data_from_string(_text) + file_handle.close() + return _data def data_from_string(text): + """ JSON load data from a string. """ return json_load(text) def data_to_file(data, ta_file): - f = file(ta_file, "w") - f.write(data_to_string(data)) - f.close() + """ Write data to a file. """ + file_handle = file(ta_file, "w") + file_handle.write(data_to_string(data)) + file_handle.close() def data_to_string(data): + """ JSON dump a string. """ return json_dump(data) def do_dialog(dialog, suffix, load_save_folder): - result = None - filter = gtk.FileFilter() - filter.add_pattern('*'+suffix) - filter.set_name("Turtle Art") - dialog.add_filter(filter) + """ Open a file dialog. """ + _result = None + file_filter = gtk.FileFilter() + file_filter.add_pattern('*'+suffix) + file_filter.set_name("Turtle Art") + dialog.add_filter(file_filter) dialog.set_current_folder(load_save_folder) - response = dialog.run() - if response == gtk.RESPONSE_OK: - result = dialog.get_filename() + _response = dialog.run() + if _response == gtk.RESPONSE_OK: + _result = dialog.get_filename() load_save_folder = dialog.get_current_folder() dialog.destroy() - return result, load_save_folder - -def save_picture(canvas, fname=''): - pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, False, 8, canvas.width, - canvas.height) - pixbuf.get_from_drawable(canvas.canvas.images[0], - canvas.canvas.images[0].get_colormap(), - 0, 0, 0, 0, canvas.width, canvas.height) - if fname != '': - pixbuf.save(fname, 'png') - return pixbuf - -def save_svg(string, fname): - f = file(fname, "w") - f.write(string) - f.close() + return _result, load_save_folder + +def save_picture(canvas, file_name=''): + """ Save the canvas to a file. """ + _pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, False, 8, canvas.width, + canvas.height) + _pixbuf.get_from_drawable(canvas.canvas.images[0], + canvas.canvas.images[0].get_colormap(), + 0, 0, 0, 0, canvas.width, canvas.height) + if file_name != '': + _pixbuf.save(file_name, 'png') + return _pixbuf + +def save_svg(string, file_name): + """ Write a string to a file. """ + file_handle = file(file_name, "w") + file_handle.write(string) + file_handle.close() def get_pixbuf_from_journal(dsobject, w, h): + """ Load a pixbuf from a Journal object. """ try: - pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(dsobject.file_path, - int(w),int(h)) + _pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(dsobject.file_path, + int(w), int(h)) except: try: - pixbufloader = \ + _pixbufloader = \ gtk.gdk.pixbuf_loader_new_with_mime_type('image/png') - pixbufloader.set_size(min(300,int(w)),min(225,int(h))) - pixbufloader.write(dsobject.metadata['preview']) - pixbufloader.close() - pixbuf = pixbufloader.get_pixbuf() + _pixbufloader.set_size(min(300, int(w)), min(225, int(h))) + _pixbufloader.write(dsobject.metadata['preview']) + _pixbufloader.close() + _pixbuf = _pixbufloader.get_pixbuf() except: - pixbuf = None - return pixbuf + _pixbuf = None + return _pixbuf def get_path(activity, subpath ): + """ Find a Rainbow-approved place for temporary files. """ try: return(os.path.join(activity.get_activity_root(), subpath)) except: @@ -176,43 +211,456 @@ def get_path(activity, subpath ): "org.laptop.TurtleArtActivity", subpath)) def image_to_base64(pixbuf, activity): - filename = os.path.join(get_path(activity, 'instance'), 'imagetmp.png') + """ Convert an image to base64 """ + _file_name = os.path.join(get_path(activity, 'instance'), 'imagetmp.png') if pixbuf != None: - pixbuf.save(filename, "png") - base64 = os.path.join(get_path(activity, 'instance'), 'base64tmp') - cmd = "base64 <" + filename + " >" + base64 - subprocess.check_call(cmd, shell=True) - f = open( base64, 'r') - data = f.read() - f.close() - return data + pixbuf.save(_file_name, "png") + _base64 = os.path.join(get_path(activity, 'instance'), 'base64tmp') + _cmd = "base64 <" + _file_name + " >" + _base64 + subprocess.check_call(_cmd, shell=True) + _file_handle = open(_base64, 'r') + _data = _file_handle.read() + _file_handle.close() + return _data def movie_media_type(name): - return name.endswith(('.ogv','.vob','.mp4','.wmv','.mov', '.mpeg')) + """ Is it movie media? """ + return name.endswith(('.ogv', '.vob', '.mp4', '.wmv', '.mov', '.mpeg')) def audio_media_type(name): + """ Is it audio media? """ return name.endswith(('.ogg', '.oga', '.m4a')) def image_media_type(name): + """ Is it image media? """ return name.endswith(('.png', '.jpg', '.jpeg', '.gif', '.tiff', '.tif', '.svg')) def text_media_type(name): + """ Is it text media? """ return name.endswith(('.txt', '.py', '.lg', '.doc', '.rtf')) -def round_int(n): - if int(float(n)) == n: - return int(n) +def round_int(num): + """ Remove trailing decimal places if number is an int """ + if int(float(num)) == num: + return int(num) else: - nn = int(float(n+0.05)*10)/10. - if int(float(nn)) == nn: - return int(nn) - return nn + _nn = int(float(num+0.05)*10)/10. + if int(float(_nn)) == _nn: + return int(_nn) + return _nn + +def calc_image_size(spr): + """ Calculate the maximum size for placing an image onto a sprite. """ + return spr.label_safe_width(), spr.label_safe_height() + + + +# Collapsible stacks live between 'sandwichtop' and 'sandwichbottom' blocks + +def reset_stack_arm(top): + """ When we undock, retract the 'arm' that extends from 'sandwichtop'. """ + if top is not None and top.name == 'sandwichtop': + if top.ey > 0: + top.reset_y() + +def grow_stack_arm(top): + """ When we dock, grow an 'arm' from 'sandwichtop'. """ + if top is not None and top.name == 'sandwichtop': + _bot = find_sandwich_bottom(top) + if _bot is None: + return + if top.ey > 0: + top.reset_y() + _ty = top.spr.get_xy()[1] + _th = top.spr.get_dimensions()[1] + _by = _bot.spr.get_xy()[1] + _dy = _by-(_ty + _th) + if _dy > 0: + top.expand_in_y(_dy/top.scale) + top.refresh() + +def find_sandwich_top(blk): + """ Find the sandwich top above this block. """ + # Always follow the main branch of a flow: the first connection. + _blk = blk.connections[0] + while _blk is not None: + if _blk.name in COLLAPSIBLE: + return None + if _blk.name in ['repeat', 'if', 'ifelse', 'forever', 'while']: + if blk != _blk.connections[len(_blk.connections) - 1]: + return None + if _blk.name == 'sandwichtop' or _blk.name == 'sandwichtop2': + return _blk + blk = _blk + _blk = _blk.connections[0] + return None + +def find_sandwich_bottom(blk): + """ Find the sandwich bottom below this block. """ + # Always follow the main branch of a flow: the last connection. + _blk = blk.connections[len(blk.connections) - 1] + while _blk is not None: + if _blk.name == 'sandwichtop' or _blk.name == 'sandwichtop2': + return None + if _blk.name in COLLAPSIBLE: + return _blk + _blk = _blk.connections[len(_blk.connections) - 1] + return None + +def find_sandwich_top_below(blk): + """ Find the sandwich top below this block. """ + if blk.name == 'sandwichtop' or blk.name == 'sandwichtop2': + return blk + # Always follow the main branch of a flow: the last connection. + _blk = blk.connections[len(blk.connections) - 1] + while _blk is not None: + if _blk.name == 'sandwichtop' or _blk.name == 'sandwichtop2': + return _blk + _blk = _blk.connections[len(_blk.connections) - 1] + return None + +def restore_stack(top): + """ Restore the blocks between the sandwich top and sandwich bottom. """ + _group = find_group(top.connections[len(top.connections) - 1]) + _hit_bottom = False + _bot = find_sandwich_bottom(top) + for _blk in _group: + if not _hit_bottom and _blk == _bot: + _hit_bottom = True + if len(_blk.values) == 0: + _blk.values.append(0) + else: + _blk.values[0] = 0 + _olddx = _blk.docks[1][2] + _olddy = _blk.docks[1][3] + # Replace 'sandwichcollapsed' shape with 'sandwichbottom' shape + _blk.name = 'sandwichbottom' + _blk.spr.set_label(' ') + _blk.svg.set_show(False) + _blk.svg.set_hide(True) + _blk.refresh() + # Redock to previous block in group + _you = _blk.connections[0] + (_yx, _yy) = _you.spr.get_xy() + _yd = _you.docks[len(_you.docks) - 1] + (_bx, _by) = _blk.spr.get_xy() + _dx = _yx + _yd[2] - _blk.docks[0][2] - _bx + _dy = _yy + _yd[3] - _blk.docks[0][3] - _by + _blk.spr.move_relative((_dx, _dy)) + # Since the shapes have changed, the dock positions have too. + _newdx = _blk.docks[1][2] + _newdy = _blk.docks[1][3] + _dx += _newdx - _olddx + _dy += _newdy - _olddy + else: + if not _hit_bottom: + _blk.spr.set_layer(BLOCK_LAYER) + _blk.status = None + else: + _blk.spr.move_relative((_dx, _dy)) + # Add 'sandwichtop' arm + top.name = 'sandwichtop' + top.refresh() + grow_stack_arm(top) + +def uncollapse_forks(top, looping=False): + """ From the top, find and restore any collapsible stacks on forks. """ + if top == None: + return + if looping and top.name == 'sandwichtop' or top.name == 'sandwichtop2': + restore_stack(top) + return + if len(top.connections) == 0: + return + _blk = top.connections[len(top.connections) - 1] + while _blk is not None: + if _blk.name in COLLAPSIBLE: + return + if _blk.name == 'sandwichtop' or _blk.name == 'sandwichtop2': + restore_stack(_blk) + return + # Follow a fork + if _blk.name in ['repeat', 'if', 'ifelse', 'forever', 'while', 'until']: + top = find_sandwich_top_below( + _blk.connections[len(_blk.connections) - 2]) + if top is not None: + uncollapse_forks(top, True) + if _blk.name == 'ifelse': + top = find_sandwich_top_below( + _blk.connections[len(_blk.connections) - 3]) + if top is not None: + uncollapse_forks(top, True) + _blk = _blk.connections[len(_blk.connections) - 1] + return + +def collapse_stack(top): + """ Hide all the blocks between the sandwich top and sandwich bottom. """ + # First uncollapse any nested stacks + uncollapse_forks(top) + _hit_bottom = False + _bot = find_sandwich_bottom(top) + _group = find_group(top.connections[len(top.connections) - 1]) + for _blk in _group: + if not _hit_bottom and _blk == _bot: + _hit_bottom = True + # Replace 'sandwichbottom' shape with 'sandwichcollapsed' shape + if len(_blk.values) == 0: + _blk.values.append(1) + else: + _blk.values[0] = 1 + _olddx = _blk.docks[1][2] + _olddy = _blk.docks[1][3] + _blk.name = 'sandwichcollapsed' + _blk.svg.set_show(True) + _blk.svg.set_hide(False) + _blk._dx = 0 + _blk._ey = 0 + _blk.spr.set_label(' ') + _blk.resize() + _blk.spr.set_label(_('click to open')) + _blk.resize() + # Redock to sandwich top in group + _you = find_sandwich_top(_blk) + (_yx, _yy) = _you.spr.get_xy() + _yd = _you.docks[len(_you.docks) - 1] + (_bx, _by) = _blk.spr.get_xy() + _dx = _yx + _yd[2] - _blk.docks[0][2] - _bx + _dy = _yy + _yd[3] - _blk.docks[0][3] - _by + _blk.spr.move_relative((_dx, _dy)) + # Since the shapes have changed, the dock positions have too. + _newdx = _blk.docks[1][2] + _newdy = _blk.docks[1][3] + _dx += _newdx - _olddx + _dy += _newdy - _olddy + else: + if not _hit_bottom: + _blk.spr.set_layer(HIDE_LAYER) + _blk.status = 'collapsed' + else: + _blk.spr.move_relative((_dx, _dy)) + # Remove 'sandwichtop' arm + top.name = 'sandwichtop2' + top.refresh() + +def collapsed(blk): + """ Is this stack collapsed? """ + if blk is not None and blk.name in COLLAPSIBLE and\ + len(blk.values) == 1 and blk.values[0] != 0: + return True + return False + +def collapsible(blk): + """ Can this stack be collapsed? """ + if blk is None or blk.name not in COLLAPSIBLE: + return False + if find_sandwich_top(blk) is None: + return False + return True + +def hide_button_hit(spr, x, y): + """ Did the sprite's hide (contract) button get hit? """ + _red, _green, _blue, _alpha = spr.get_pixel((x, y)) + if (_red == 255 and _green == 0) or _green == 255: + return True + else: + return False + +def show_button_hit(spr, x, y): + """ Did the sprite's show (expand) button get hit? """ + _red, _green, _blue, _alpha = spr.get_pixel((x, y)) + if _green == 254: + return True + else: + return False + +def numeric_arg(value): + """ Dock test: looking for a numeric value """ + if type(convert(value, float)) is float: + return True + return False + +def zero_arg(value): + """ Dock test: looking for a zero argument """ + if numeric_arg(value): + if convert(value, float) == 0: + return True + return False + +def neg_arg(value): + """ Dock test: looking for a negative argument """ + if numeric_arg(value): + if convert(value, float) < 0: + return True + return False + +def dock_dx_dy(block1, dock1n, block2, dock2n): + """ Find the distance between the dock points of two blocks. """ + _dock1 = block1.docks[dock1n] + _dock2 = block2.docks[dock2n] + _d1type, _d1dir, _d1x, _d1y = _dock1[0:4] + _d2type, _d2dir, _d2x, _d2y = _dock2[0:4] + if block1 == block2: + return (100, 100) + if _d1dir == _d2dir: + return (100, 100) + if (_d2type is not 'number') or (dock2n is not 0): + if block1.connections is not None and \ + dock1n < len(block1.connections) and \ + block1.connections[dock1n] is not None: + return (100, 100) + if block2.connections is not None and \ + dock2n < len(block2.connections) and \ + block2.connections[dock2n] is not None: + return (100, 100) + if _d1type != _d2type: + if block1.name in STRING_OR_NUMBER_ARGS: + if _d2type == 'number' or _d2type == 'string': + pass + elif block1.name in CONTENT_ARGS: + if _d2type in CONTENT_BLOCKS: + pass + else: + return (100, 100) + (_b1x, _b1y) = block1.spr.get_xy() + (_b2x, _b2y) = block2.spr.get_xy() + return ((_b1x + _d1x) - (_b2x + _d2x), (_b1y + _d1y) - (_b2y + _d2y)) + +def arithmetic_check(blk1, blk2, dock1, dock2): + """ Dock strings only if they convert to numbers. Avoid /0 and root(-1)""" + if blk1 == None or blk2 == None: + return True + if blk1.name in ['sqrt', 'number', 'string'] and\ + blk2.name in ['sqrt', 'number', 'string']: + if blk1.name == 'number' or blk1.name == 'string': + if not numeric_arg(blk1.values[0]) or neg_arg(blk1.values[0]): + return False + elif blk2.name == 'number' or blk2.name == 'string': + if not numeric_arg(blk2.values[0]) or neg_arg(blk2.values[0]): + return False + elif blk1.name in ['division2', 'number', 'string'] and\ + blk2.name in ['division2', 'number', 'string']: + if blk1.name == 'number' or blk1.name == 'string': + if not numeric_arg(blk1.values[0]): + return False + if dock2 == 2 and zero_arg(blk1.values[0]): + return False + elif blk2.name == 'number' or blk2.name == 'string': + if not numeric_arg(blk2.values[0]): + return False + if dock1 == 2 and zero_arg(blk2.values[0]): + return False + elif blk1.name in ['product2', 'minus2', 'random', 'remainder2', + 'string'] and\ + blk2.name in ['product2', 'minus2', 'random', 'remainder2', + 'string']: + if blk1.name == 'string': + if not numeric_arg(blk1.values[0]): + return False + elif blk1.name == 'string': + if not numeric_arg(blk2.values[0]): + return False + elif blk1.name in ['greater2', 'less2'] and blk2.name == 'string': + # Non-numeric stings are OK if only both args are strings; + # Lots of test conditions... + if dock1 == 1 and blk1.connections[2] is not None: + if blk1.connections[2].name == 'number': + if not numeric_arg(blk2.values[0]): + return False + elif dock1 == 2 and blk1.connections[1] is not None: + if blk1.connections[1].name == 'number': + if not numeric_arg(blk2.values[0]): + return False + elif blk2.name in ['greater2', 'less2'] and blk1.name == 'string': + if dock2 == 1 and blk2.connections[2] is not None: + if blk2.connections[2].name == 'number': + if not numeric_arg(blk1.values[0]): + return False + elif dock2 == 2 and blk2.connections[1] is not None: + if blk2.connections[1].name == 'number': + if not numeric_arg(blk1.values[0]): + return False + elif blk1.name in ['greater2', 'less2'] and blk2.name == 'number': + if dock1 == 1 and blk1.connections[2] is not None: + if blk1.connections[2].name == 'string': + if not numeric_arg(blk1.connections[2].values[0]): + return False + elif dock1 == 2 and blk1.connections[1] is not None: + if blk1.connections[1].name == 'string': + if not numeric_arg(blk1.connections[1].values[0]): + return False + elif blk2.name in ['greater2', 'less2'] and blk1.name == 'number': + if dock2 == 1 and blk2.connections[2] is not None: + if blk2.connections[2].name == 'string': + if not numeric_arg(blk2.connections[2].values[0]): + return False + elif dock2 == 2 and blk2.connections[1] is not None: + if blk2.connections[1].name == 'string': + if not numeric_arg(blk2.connections[1].values[0]): + return False + return True + +def xy(event): + """ Where is the mouse event? """ + return map(int, event.get_coords()) """ -Calculate the maximum size for placing an image onto a sprite. +Utilities related to finding blocks in stacks. """ -def calc_image_size(spr): - w = spr.label_safe_width() - h = spr.label_safe_height() - return w, h +def find_block_to_run(blk): + """ Find a stack to run (any stack without a 'def action'on the top). """ + _top = find_top_block(blk) + if blk == _top and blk.name[0:3] is not 'def': + return True + else: + return False + +def find_top_block(blk): + """ Find the top block in a stack. """ + if len(blk.connections) == 0: + return blk + while blk.connections[0] is not None: + blk = blk.connections[0] + return blk + +def find_start_stack(blk): + """ Find a stack with a 'start' block on top. """ + if find_top_block(blk).name == 'start': + return True + else: + return False + +def find_group(blk): + """ Find the connected group of block in a stack. """ + if blk is None: + return [] + _group = [blk] + if blk.connections is not None: + for _blk2 in blk.connections[1:]: + if _blk2 is not None: + _group.extend(find_group(_blk2)) + return _group + +def find_blk_below(blk, name): + """ Find a specific block below this block. """ + if blk == None or len(blk.connections) == 0: + return + _group = find_group(blk) + for _gblk in _group: + if _gblk.name == name: + return _gblk + return None + +def olpc_xo_1(): + """ Is the an OLPC XO-1 or XO-1.5? """ + return os.path.exists('/etc/olpc-release') or \ + os.path.exists('/sys/power/olpc-pm') + +def walk_stack(tw, blk): + """ Convert blocks to logo psuedocode. """ + top = find_top_block(blk) + if blk == top: + code = tw.lc.run_blocks(top, tw.block_list.list, False) + return code + else: + return [] -- cgit v0.9.1