aboutsummaryrefslogtreecommitdiffstats
path: root/klippy/extras/display/menu.py
diff options
context:
space:
mode:
Diffstat (limited to 'klippy/extras/display/menu.py')
-rw-r--r--klippy/extras/display/menu.py344
1 files changed, 177 insertions, 167 deletions
diff --git a/klippy/extras/display/menu.py b/klippy/extras/display/menu.py
index e7723a7e..717b6084 100644
--- a/klippy/extras/display/menu.py
+++ b/klippy/extras/display/menu.py
@@ -21,33 +21,33 @@ class error(Exception):
class MenuElement(object):
def __init__(self, manager, config, **kwargs):
if type(self) is MenuElement:
- raise error(
- 'Abstract MenuElement cannot be instantiated directly')
+ raise error("Abstract MenuElement cannot be instantiated directly")
self._manager = manager
- self._cursor = '>'
+ self._cursor = ">"
# set class defaults and attributes from arguments
- self._index = kwargs.get('index', None)
- self._enable = kwargs.get('enable', True)
- self._name = kwargs.get('name', None)
+ self._index = kwargs.get("index", None)
+ self._enable = kwargs.get("enable", True)
+ self._name = kwargs.get("name", None)
self._enable_tpl = self._name_tpl = None
if config is not None:
# overwrite class attributes from config
- self._index = config.getint('index', self._index)
+ self._index = config.getint("index", self._index)
self._name_tpl = manager.gcode_macro.load_template(
- config, 'name', self._name)
+ config, "name", self._name
+ )
try:
- self._enable = config.getboolean('enable', self._enable)
+ self._enable = config.getboolean("enable", self._enable)
except config.error:
- self._enable_tpl = manager.gcode_macro.load_template(
- config, 'enable')
+ self._enable_tpl = manager.gcode_macro.load_template(config, "enable")
# item namespace - used in relative paths
- self._ns = str(" ".join(config.get_name().split(' ')[1:])).strip()
+ self._ns = str(" ".join(config.get_name().split(" ")[1:])).strip()
else:
# ns - item namespace key, used in item relative paths
# $__id - generated id text variable
- __id = '__menu_' + hex(id(self)).lstrip("0x").rstrip("L")
- self._ns = Template(
- 'menu ' + kwargs.get('ns', __id)).safe_substitute(__id=__id)
+ __id = "__menu_" + hex(id(self)).lstrip("0x").rstrip("L")
+ self._ns = Template("menu " + kwargs.get("ns", __id)).safe_substitute(
+ __id=__id
+ )
self._last_heartbeat = None
self.__scroll_pos = None
self.__scroll_request_pending = False
@@ -71,14 +71,15 @@ class MenuElement(object):
"""Load script template from config or callback from dict"""
if name in self._scripts:
logging.info(
- "Declaration of '%s' hides "
- "previous script declaration" % (name,))
+ "Declaration of '%s' hides " "previous script declaration" % (name,)
+ )
option = option or name
if isinstance(config, dict):
self._scripts[name] = config.get(option, None)
else:
self._scripts[name] = self.manager.gcode_macro.load_template(
- config, option, '')
+ config, option, ""
+ )
# override
def is_editing(self):
@@ -105,9 +106,7 @@ class MenuElement(object):
def get_context(self, cxt=None):
# get default menu context
context = self.manager.get_context(cxt)
- context['menu'].update({
- 'ns': self.get_ns()
- })
+ context["menu"].update({"ns": self.get_ns()})
return context
def eval_enable(self, context):
@@ -153,7 +152,7 @@ class MenuElement(object):
def __slice_name(self, name, index):
chunks = []
- for i, text in enumerate(re.split(r'(\~.*?\~)', name)):
+ for i, text in enumerate(re.split(r"(\~.*?\~)", name)):
if i & 1 == 0: # text
chunks += text
else: # glyph placeholder
@@ -168,18 +167,16 @@ class MenuElement(object):
self.__reset_scroller()
return name
- def get_ns(self, name='.'):
+ def get_ns(self, name="."):
name = str(name).strip()
- if name.startswith('..'):
- name = ' '.join(
- [(' '.join(str(self._ns).split(' ')[:-1])), name[2:]])
- elif name.startswith('.'):
- name = ' '.join([str(self._ns), name[1:]])
+ if name.startswith(".."):
+ name = " ".join([(" ".join(str(self._ns).split(" ")[:-1])), name[2:]])
+ elif name.startswith("."):
+ name = " ".join([str(self._ns), name[1:]])
return name.strip()
def send_event(self, event, *args):
- return self.manager.send_event(
- "%s:%s" % (self.get_ns(), str(event)), *args)
+ return self.manager.send_event("%s:%s" % (self.get_ns(), str(event)), *args)
def get_script(self, name):
if name in self._scripts:
@@ -187,7 +184,7 @@ class MenuElement(object):
return None
def _run_script(self, name, context):
- _render = getattr(self._scripts[name], 'render', None)
+ _render = getattr(self._scripts[name], "render", None)
# check template
if _render is not None and callable(_render):
return _render(context)
@@ -199,16 +196,14 @@ class MenuElement(object):
return self._scripts[name]
def run_script(self, name, **kwargs):
- event = kwargs.get('event', None)
- context = kwargs.get('context', None)
- render_only = kwargs.get('render_only', False)
+ event = kwargs.get("event", None)
+ context = kwargs.get("context", None)
+ render_only = kwargs.get("render_only", False)
result = ""
# init context
if name in self._scripts:
context = self.get_context(context)
- context['menu'].update({
- 'event': event or name
- })
+ context["menu"].update({"event": event or name})
result = self._run_script(name, context)
if not render_only:
# run result as gcode
@@ -234,13 +229,13 @@ class MenuElement(object):
class MenuContainer(MenuElement):
"""Menu container abstract class"""
+
def __init__(self, manager, config, **kwargs):
if type(self) is MenuContainer:
- raise error(
- 'Abstract MenuContainer cannot be instantiated directly')
+ raise error("Abstract MenuContainer cannot be instantiated directly")
super(MenuContainer, self).__init__(manager, config, **kwargs)
- self._populate_cb = kwargs.get('populate', None)
- self._cursor = '>'
+ self._populate_cb = kwargs.get("populate", None)
+ self._cursor = ">"
self.__selected = None
self._allitems = []
self._names = []
@@ -307,8 +302,9 @@ class MenuContainer(MenuElement):
self._parents.append(parents)
def assert_recursive_relation(self, parents=None):
- assert self not in (parents or self._parents), \
- "Recursive relation of '%s' container" % (self.get_ns(),)
+ assert self not in (
+ parents or self._parents
+ ), "Recursive relation of '%s' container" % (self.get_ns(),)
def insert_item(self, s, index=None):
self._insert_item(s, index)
@@ -343,11 +339,10 @@ class MenuContainer(MenuElement):
if self._populate_cb is not None and callable(self._populate_cb):
self._populate_cb(self)
# send populate event
- self.send_event('populate', self)
+ self.send_event("populate", self)
def update_items(self):
- _a = [(item, name) for item, name in self._allitems
- if item.is_enabled()]
+ _a = [(item, name) for item, name in self._allitems if item.is_enabled()]
self._items, self._names = zip(*_a) or ([], [])
# select methods
@@ -416,7 +411,7 @@ class MenuContainer(MenuElement):
class MenuDisabled(MenuElement):
def __init__(self, manager, config, **kwargs):
- super(MenuDisabled, self).__init__(manager, config, name='')
+ super(MenuDisabled, self).__init__(manager, config, name="")
def is_enabled(self):
return False
@@ -425,30 +420,32 @@ class MenuDisabled(MenuElement):
class MenuCommand(MenuElement):
def __init__(self, manager, config, **kwargs):
super(MenuCommand, self).__init__(manager, config, **kwargs)
- self._load_script(config or kwargs, 'gcode')
+ self._load_script(config or kwargs, "gcode")
class MenuInput(MenuCommand):
def __init__(self, manager, config, **kwargs):
super(MenuInput, self).__init__(manager, config, **kwargs)
# set class defaults and attributes from arguments
- self._input = kwargs.get('input', None)
- self._input_min = kwargs.get('input_min', -999999.0)
- self._input_max = kwargs.get('input_max', 999999.0)
- self._input_step = kwargs.get('input_step', 1.0)
- self._realtime = kwargs.get('realtime', False)
+ self._input = kwargs.get("input", None)
+ self._input_min = kwargs.get("input_min", -999999.0)
+ self._input_max = kwargs.get("input_max", 999999.0)
+ self._input_step = kwargs.get("input_step", 1.0)
+ self._realtime = kwargs.get("realtime", False)
self._input_tpl = self._input_min_tpl = self._input_max_tpl = None
if config is not None:
# overwrite class attributes from config
- self._realtime = config.getboolean('realtime', self._realtime)
- self._input_tpl = manager.gcode_macro.load_template(
- config, 'input')
+ self._realtime = config.getboolean("realtime", self._realtime)
+ self._input_tpl = manager.gcode_macro.load_template(config, "input")
self._input_min_tpl = manager.gcode_macro.load_template(
- config, 'input_min', str(self._input_min))
+ config, "input_min", str(self._input_min)
+ )
self._input_max_tpl = manager.gcode_macro.load_template(
- config, 'input_max', str(self._input_max))
+ config, "input_max", str(self._input_max)
+ )
self._input_step = config.getfloat(
- 'input_step', self._input_step, above=0.)
+ "input_step", self._input_step, above=0.0
+ )
def init(self):
super(MenuInput, self).init()
@@ -474,22 +471,25 @@ class MenuInput(MenuCommand):
def heartbeat(self, eventtime):
super(MenuInput, self).heartbeat(eventtime)
- if (self._is_dirty is True
- and self.__last_change is not None
- and self._input_value is not None
- and (eventtime - self.__last_change) > 0.250):
+ if (
+ self._is_dirty is True
+ and self.__last_change is not None
+ and self._input_value is not None
+ and (eventtime - self.__last_change) > 0.250
+ ):
if self._realtime is True:
- self.run_script('gcode', event='change')
- self.run_script('change')
+ self.run_script("gcode", event="change")
+ self.run_script("change")
self._is_dirty = False
def get_context(self, cxt=None):
context = super(MenuInput, self).get_context(cxt)
- value = (self._eval_value(context) if self._input_value is None
- else self._input_value)
- context['menu'].update({
- 'input': value
- })
+ value = (
+ self._eval_value(context)
+ if self._input_value is None
+ else self._input_value
+ )
+ context["menu"].update({"input": value})
return context
def is_enabled(self):
@@ -499,8 +499,7 @@ class MenuInput(MenuCommand):
def _eval_min(self, context):
try:
if self._input_min_tpl is not None:
- return float(ast.literal_eval(
- self._input_min_tpl.render(context)))
+ return float(ast.literal_eval(self._input_min_tpl.render(context)))
return float(self._input_min)
except ValueError:
logging.exception("Input min value evaluation error")
@@ -508,8 +507,7 @@ class MenuInput(MenuCommand):
def _eval_max(self, context):
try:
if self._input_max_tpl is not None:
- return float(ast.literal_eval(
- self._input_max_tpl.render(context)))
+ return float(ast.literal_eval(self._input_max_tpl.render(context)))
return float(self._input_max)
except ValueError:
logging.exception("Input max value evaluation error")
@@ -517,8 +515,7 @@ class MenuInput(MenuCommand):
def _eval_value(self, context):
try:
if self._input_tpl is not None:
- return float(ast.literal_eval(
- self._input_tpl.render(context)))
+ return float(ast.literal_eval(self._input_tpl.render(context)))
return float(self._input)
except ValueError:
logging.exception("Input value evaluation error")
@@ -532,17 +529,21 @@ class MenuInput(MenuCommand):
self._input_value = None
self._input_min = self._eval_min(context)
self._input_max = self._eval_max(context)
- self._input_value = min(self._input_max, max(
- self._input_min, self._eval_value(context)))
+ self._input_value = min(
+ self._input_max, max(self._input_min, self._eval_value(context))
+ )
self._value_changed()
def _reset_value(self):
self._input_value = None
def _get_input_step(self, fast_rate=False):
- return ((10.0 * self._input_step) if fast_rate and (
- (self._input_max - self._input_min) / self._input_step > 100.0)
- else self._input_step)
+ return (
+ (10.0 * self._input_step)
+ if fast_rate
+ and ((self._input_max - self._input_min) / self._input_step > 100.0)
+ else self._input_step
+ )
def inc_value(self, fast_rate=False):
last_value = self._input_value
@@ -551,8 +552,9 @@ class MenuInput(MenuCommand):
input_step = self._get_input_step(fast_rate)
self._input_value += abs(input_step)
- self._input_value = min(self._input_max, max(
- self._input_min, self._input_value))
+ self._input_value = min(
+ self._input_max, max(self._input_min, self._input_value)
+ )
if last_value != self._input_value:
self._value_changed()
@@ -564,8 +566,9 @@ class MenuInput(MenuCommand):
input_step = self._get_input_step(fast_rate)
self._input_value -= abs(input_step)
- self._input_value = min(self._input_max, max(
- self._input_min, self._input_value))
+ self._input_value = min(
+ self._input_max, max(self._input_min, self._input_value)
+ )
if last_value != self._input_value:
self._value_changed()
@@ -585,9 +588,9 @@ class MenuList(MenuContainer):
def _cb(el, context):
el.manager.back()
+
# create back item
- self._itemBack = self.manager.menuitem_from(
- 'command', name='..', gcode=_cb)
+ self._itemBack = self.manager.menuitem_from("command", name="..", gcode=_cb)
def _names_aslist(self):
return self.manager.lookup_children(self.get_ns())
@@ -619,7 +622,7 @@ class MenuList(MenuContainer):
suffix = ""
if row < len(self):
current = self[row]
- selected = (row == selected_row)
+ selected = row == selected_row
if selected:
current.heartbeat(eventtime)
text = current.render_name(selected)
@@ -627,12 +630,12 @@ class MenuList(MenuContainer):
if selected and not current.is_editing():
prefix = current.cursor
elif selected and current.is_editing():
- prefix = '*'
+ prefix = "*"
else:
- prefix = ' '
+ prefix = " "
# add suffix (folder indicator)
if isinstance(current, MenuList):
- suffix += '>'
+ suffix += ">"
# draw to display
plen = len(prefix)
slen = len(suffix)
@@ -642,8 +645,7 @@ class MenuList(MenuContainer):
# draw item name
tpos = display.draw_text(y, ppos, text.ljust(width), eventtime)
# check scroller
- if (selected and tpos > self.manager.cols
- and current.is_scrollable()):
+ if selected and tpos > self.manager.cols and current.is_scrollable():
# scroll next
current.need_scroller(True)
else:
@@ -651,12 +653,11 @@ class MenuList(MenuContainer):
current.need_scroller(None)
# draw item suffix
if suffix:
- display.draw_text(
- y, self.manager.cols - slen, suffix, eventtime)
+ display.draw_text(y, self.manager.cols - slen, suffix, eventtime)
# next display row
y += 1
except Exception:
- logging.exception('List drawing error')
+ logging.exception("List drawing error")
class MenuVSDList(MenuList):
@@ -665,20 +666,23 @@ class MenuVSDList(MenuList):
def _populate(self):
super(MenuVSDList, self)._populate()
- sdcard = self.manager.printer.lookup_object('virtual_sdcard', None)
+ sdcard = self.manager.printer.lookup_object("virtual_sdcard", None)
if sdcard is not None:
files = sdcard.get_file_list()
for fname, fsize in files:
- self.insert_item(self.manager.menuitem_from(
- 'command', name=repr(fname), gcode='M23 /%s' % str(fname)))
+ self.insert_item(
+ self.manager.menuitem_from(
+ "command", name=repr(fname), gcode="M23 /%s" % str(fname)
+ )
+ )
menu_items = {
- 'disabled': MenuDisabled,
- 'command': MenuCommand,
- 'input': MenuInput,
- 'list': MenuList,
- 'vsdlist': MenuVSDList
+ "disabled": MenuDisabled,
+ "command": MenuCommand,
+ "input": MenuInput,
+ "list": MenuList,
+ "vsdlist": MenuVSDList,
}
@@ -693,33 +697,32 @@ class MenuManager:
self.children = {}
self.display = display
self.printer = config.get_printer()
- self.pconfig = self.printer.lookup_object('configfile')
- self.gcode = self.printer.lookup_object('gcode')
+ self.pconfig = self.printer.lookup_object("configfile")
+ self.gcode = self.printer.lookup_object("gcode")
self.gcode_queue = []
self.context = {}
self.root = None
- self._root = config.get('menu_root', '__main')
+ self._root = config.get("menu_root", "__main")
self.cols, self.rows = self.display.get_dimensions()
- self.timeout = config.getint('menu_timeout', 0)
+ self.timeout = config.getint("menu_timeout", 0)
self.timer = 0
# reverse container navigation
- self._reverse_navigation = config.getboolean(
- 'menu_reverse_navigation', False)
+ self._reverse_navigation = config.getboolean("menu_reverse_navigation", False)
# load printer objects
- self.gcode_macro = self.printer.load_object(config, 'gcode_macro')
+ self.gcode_macro = self.printer.load_object(config, "gcode_macro")
# register itself for printer callbacks
- self.printer.add_object('menu', self)
+ self.printer.add_object("menu", self)
self.printer.register_event_handler("klippy:ready", self.handle_ready)
# register for key events
menu_keys.MenuKeys(config, self.key_event)
# Load local config file in same directory as current module
- self.load_config(os.path.dirname(__file__), 'menu.cfg')
+ self.load_config(os.path.dirname(__file__), "menu.cfg")
# Load items from main config
self.load_menuitems(config)
# Load menu root
self.root = self.lookup_menuitem(self._root)
# send init event
- self.send_event('init', self)
+ self.send_event("init", self)
def handle_ready(self):
# start timer
@@ -731,8 +734,11 @@ class MenuManager:
return eventtime + TIMER_DELAY
def timeout_check(self, eventtime):
- if (self.is_running() and self.timeout > 0
- and isinstance(self.root, MenuContainer)):
+ if (
+ self.is_running()
+ and self.timeout > 0
+ and isinstance(self.root, MenuContainer)
+ ):
if self.timer >= self.timeout:
self.exit()
else:
@@ -751,7 +757,7 @@ class MenuManager:
self.timer = 0
if isinstance(self.root, MenuContainer):
# send begin event
- self.send_event('begin', self)
+ self.send_event("begin", self)
self.update_context(eventtime)
if isinstance(self.root, MenuContainer):
self.root.init_selection()
@@ -764,10 +770,10 @@ class MenuManager:
def get_status(self, eventtime):
return {
- 'timeout': self.timeout,
- 'running': self.running,
- 'rows': self.rows,
- 'cols': self.cols
+ "timeout": self.timeout,
+ "running": self.running,
+ "rows": self.rows,
+ "cols": self.cols,
}
def _action_back(self, force=False, update=True):
@@ -787,10 +793,10 @@ class MenuManager:
def update_context(self, eventtime):
# menu default jinja2 context
self.context = self.gcode_macro.create_template_context(eventtime)
- self.context['menu'] = {
- 'eventtime': eventtime,
- 'back': self._action_back,
- 'exit': self._action_exit
+ self.context["menu"] = {
+ "eventtime": eventtime,
+ "back": self._action_back,
+ "exit": self._action_exit,
}
def stack_push(self, container):
@@ -800,9 +806,9 @@ class MenuManager:
top = self.stack_peek()
if top is not None:
if isinstance(top, MenuList):
- top.run_script('leave')
+ top.run_script("leave")
if isinstance(container, MenuList):
- container.run_script('enter')
+ container.run_script("enter")
if not container.is_editing():
container.update_items()
container.init_selection()
@@ -822,12 +828,12 @@ class MenuManager:
top.update_items()
top.init_selection()
if isinstance(container, MenuList):
- container.run_script('leave')
+ container.run_script("leave")
if isinstance(top, MenuList):
- top.run_script('enter')
+ top.run_script("enter")
else:
if isinstance(container, MenuList):
- container.run_script('leave')
+ container.run_script("leave")
return container
def stack_size(self):
@@ -905,25 +911,26 @@ class MenuManager:
if self.running and isinstance(container, MenuContainer):
self.timer = 0
current = container.selected_item()
- if (not force and isinstance(current, MenuInput)
- and current.is_editing()):
+ if not force and isinstance(current, MenuInput) and current.is_editing():
return
if isinstance(container, MenuList):
- container.run_script('leave')
- self.send_event('exit', self)
+ container.run_script("leave")
+ self.send_event("exit", self)
self.running = False
def push_container(self, menu):
container = self.stack_peek()
if self.running and isinstance(container, MenuContainer):
- if (isinstance(menu, MenuContainer)
- and not container.is_editing()
- and menu is not container):
+ if (
+ isinstance(menu, MenuContainer)
+ and not container.is_editing()
+ and menu is not container
+ ):
self.stack_push(menu)
return True
return False
- def press(self, event='click'):
+ def press(self, event="click"):
container = self.stack_peek()
if self.running and isinstance(container, MenuContainer):
self.timer = 0
@@ -932,10 +939,10 @@ class MenuManager:
self.stack_push(current)
elif isinstance(current, MenuInput):
if current.is_editing():
- current.run_script('gcode', event=event)
+ current.run_script("gcode", event=event)
current.run_script(event)
elif isinstance(current, MenuCommand):
- current.run_script('gcode', event=event)
+ current.run_script("gcode", event=event)
current.run_script(event)
else:
# current is None, no selection. passthru to container
@@ -960,8 +967,10 @@ class MenuManager:
def menuitem_from(self, type, **kwargs):
if type not in menu_items:
- raise error("Choice '%s' for option '%s'"
- " is not a valid choice" % (type, menu_items))
+ raise error(
+ "Choice '%s' for option '%s'"
+ " is not a valid choice" % (type, menu_items)
+ )
return menu_items[type](self, None, **kwargs)
def add_menuitem(self, name, item):
@@ -969,18 +978,18 @@ class MenuManager:
if name in self.menuitems:
existing_item = True
logging.info(
- "Declaration of '%s' hides "
- "previous menuitem declaration" % (name,))
+ "Declaration of '%s' hides " "previous menuitem declaration" % (name,)
+ )
self.menuitems[name] = item
if isinstance(item, MenuElement):
- parent = item.get_ns('..')
+ parent = item.get_ns("..")
if parent and not existing_item:
if item.index is not None:
self.children.setdefault(parent, []).insert(
- item.index, item.get_ns())
+ item.index, item.get_ns()
+ )
else:
- self.children.setdefault(parent, []).append(
- item.get_ns())
+ self.children.setdefault(parent, []).append(item.get_ns())
def lookup_menuitem(self, name, default=sentinel):
if name is None:
@@ -988,8 +997,7 @@ class MenuManager:
if name in self.menuitems:
return self.menuitems[name]
if default is sentinel:
- raise self.printer.config_error(
- "Unknown menuitem '%s'" % (name,))
+ raise self.printer.config_error("Unknown menuitem '%s'" % (name,))
return default
def lookup_children(self, ns):
@@ -1003,18 +1011,19 @@ class MenuManager:
try:
cfg = self.pconfig.read_config(filename)
except Exception:
- raise self.printer.config_error(
- "Cannot load config '%s'" % (filename,))
+ raise self.printer.config_error("Cannot load config '%s'" % (filename,))
if cfg:
self.load_menuitems(cfg)
return cfg
def load_menuitems(self, config):
- for cfg in config.get_prefix_sections('menu '):
- type = cfg.get('type')
+ for cfg in config.get_prefix_sections("menu "):
+ type = cfg.get("type")
if type not in menu_items:
- raise error("Choice '%s' for option '%s'"
- " is not a valid choice" % (type, menu_items))
+ raise error(
+ "Choice '%s' for option '%s'"
+ " is not a valid choice" % (type, menu_items)
+ )
item = menu_items[type](self, cfg)
self.add_menuitem(item.get_ns(), item)
@@ -1026,19 +1035,19 @@ class MenuManager:
self.begin(eventtime)
def key_event(self, key, eventtime):
- if key == 'click':
+ if key == "click":
self._click_callback(eventtime, key)
- elif key == 'long_click':
+ elif key == "long_click":
self._click_callback(eventtime, key)
- elif key == 'up':
+ elif key == "up":
self.up(False)
- elif key == 'fast_up':
+ elif key == "fast_up":
self.up(True)
- elif key == 'down':
+ elif key == "down":
self.down(False)
- elif key == 'fast_down':
+ elif key == "fast_down":
self.down(True)
- elif key == 'back':
+ elif key == "back":
self.back()
self.display.request_redraw()
@@ -1048,8 +1057,9 @@ class MenuManager:
def stripliterals(cls, s):
"""Literals are beginning or ending by the double or single quotes"""
s = str(s)
- if (s.startswith('"') and s.endswith('"')) or \
- (s.startswith("'") and s.endswith("'")):
+ if (s.startswith('"') and s.endswith('"')) or (
+ s.startswith("'") and s.endswith("'")
+ ):
s = s[1:-1]
return s
@@ -1058,10 +1068,10 @@ class MenuManager:
if isinstance(s, str):
return s
elif isinstance(s, unicode):
- return unicode(s).encode('latin-1', 'ignore')
+ return unicode(s).encode("latin-1", "ignore")
else:
return str(s)
@classmethod
def asflat(cls, s):
- return cls.stripliterals(''.join(cls.aslatin(s).splitlines()))
+ return cls.stripliterals("".join(cls.aslatin(s).splitlines()))