class ExternalFieldExpression(ExternalField): def __init__(self, name, electric_or_magnetic, expression_x, expression_y, expression_z): super().__init__(name, electric_or_magnetic) self.expression_x = expression_x self.expression_y = expression_y self.expression_z = expression_z self._ev = SimpleEval(functions={ "sin": math.sin, "cos": math.cos, "sqrt": math.sqrt }) # todo: inherit SimpleEval and define math functions inside # todo: add r, theta, phi names def _field_at_position(self, pos): self._ev.names["x"] = pos[0] self._ev.names["y"] = pos[1] self._ev.names["z"] = pos[2] fx = self._ev.eval(self.expression_x) fy = self._ev.eval(self.expression_y) fz = self._ev.eval(self.expression_z) return fx, fy, fz def get_at_points(self, positions, time): positions = np.asarray(positions) self._ev.names["t"] = time if positions.shape == (3, ): return np.array(self._field_at_position(positions)) else: return np.array( [self._field_at_position(pos) for pos in positions])
class FieldExpression(Field): @safe_default_inject @inject.params(xp=numpy) def __init__(self, name, electric_or_magnetic, expression_x, expression_y, expression_z, xp=numpy): super().__init__(name, electric_or_magnetic) self._xp = xp self.expression_x = expression_x self.expression_y = expression_y self.expression_z = expression_z self._ev = SimpleEval(functions={ "sin": xp.sin, "cos": xp.cos, "sqrt": xp.sqrt }, operators={ ast.Add: op.add, ast.Sub: op.sub, ast.Mult: op.mul, ast.Div: op.truediv, ast.FloorDiv: op.floordiv, ast.Pow: op.pow, ast.Mod: op.mod, ast.Eq: op.eq, ast.NotEq: op.ne, ast.Gt: op.gt, ast.Lt: op.lt, ast.GtE: op.ge, ast.LtE: op.le, ast.Not: op.not_, ast.USub: op.neg, ast.UAdd: op.pos, ast.In: lambda x, y: op.contains(y, x), ast.NotIn: lambda x, y: not op.contains(y, x), ast.Is: lambda x, y: x is y, ast.IsNot: lambda x, y: x is not y, }) # todo: inherit SimpleEval and define math functions inside # todo: add r, theta, phi names def get_at_points(self, positions, time: float) -> numpy.ndarray: positions = self._xp.asarray(positions) self._ev.names["t"] = time self._ev.names["x"] = positions[:, 0] self._ev.names["y"] = positions[:, 1] self._ev.names["z"] = positions[:, 2] result = self._xp.empty_like(positions) result[:, 0] = self._ev.eval(self.expression_x) result[:, 1] = self._ev.eval(self.expression_y) result[:, 2] = self._ev.eval(self.expression_z) return result
def test_no_names(self): # does not work on current Py3, True et al. are keywords now self.s.eval('True') # with self.assertRaises(NameNotDefined): s = SimpleEval(names={}) if sys.version_info < (3, ): with self.assertRaises(NameNotDefined): s.eval('True') else: s.eval('True')
def visit_typedecl(self, node): """ Visit a node. """ if node.declname in self.names: c_gen = c_generator.CGenerator() pins = {} operators = DEFAULT_OPERATORS operators[ast.BitOr] = lambda a, b: a | b operators[ast.LShift] = lambda a, b: a << b operators[ast.RShift] = lambda a, b: a << b evaluator = SimpleEval(DEFAULT_OPERATORS) for pin in node.type.values.enumerators: expr = c_gen.visit(pin.value) if "(int)" in expr: expr = expr.replace('(int)', '') if expr in pins: pins[pin.name] = pins[expr] else: pins[pin.name] = evaluator.eval(expr.strip()) return pins
def evaluate_context(self, context, verbose=True, allowed_missing=()): evaluator = SimpleEval( functions={ **DEFAULT_FUNCTIONS, 'log': np.log, 'log2': np.log2, 'log10': np.log10, 'sqrt': np.sqrt, 'abs': np.abs, 'ord': ord, }) evaluator.names.update(context) evaluator.names.update(self._constants) allowed_missing = set(allowed_missing) for name, code in self._evaluables.items(): try: result = evaluator.eval(code) if isinstance(code, str) else code except NameNotDefined as error: if error.name in allowed_missing: allowed_missing.add(name) log.debug(f'Skipped evaluating: {name}') continue else: raise if verbose: log.debug(f'Evaluated: {name} = {repr(result)}') evaluator.names[name] = context[name] = result
def parse_entry(self, parsed_data): if parsed_data[0] == 0: # concatenation if len(parsed_data) == 1: return element = parsed_data[1] remainder = parsed_data[2:] remainder.insert(0, 0) if type(element) is str: result = None for result in self.parse_entry(remainder): yield element + result if result is None: yield element else: element_result = None for element_result in self.parse_entry(element): remainder_result = None for remainder_result in self.parse_entry(remainder): yield element_result + remainder_result if remainder_result is None: yield element_result if element_result is None: for remainder_result in self.parse_entry(remainder): yield remainder_result elif parsed_data[0] == 1: # random choice [a,b,c] element = parsed_data[random.randint(1, len(parsed_data) - 1)] if type(element) is not str: for result in self.parse_entry(element): yield result else: yield element elif parsed_data[0] == 2: # multiple response {a,b,c} for element in parsed_data[1:]: if type(element) is str: yield element else: for result in self.parse_entry(element): yield result elif parsed_data[0] == 3: # dynamic variable ${variable} variable_name = parsed_data[1] if type(variable_name) is not str: variable_name = next(self.parse_entry(variable_name), '') evaluator = SimpleEval(names=self.variables.copy(), functions=EVAL_FUNCTIONS, operators=EVAL_OPERATORS) evaluator.names['variables'] = evaluator.names evaluator.functions['eval'] = evaluator.eval try: yield str(evaluator.eval(variable_name)) except GeneratorExit: pass except: yield '[Error: {0}]'.format(''.join( traceback.format_exception_only( sys.exc_info()[0], sys.exc_info()[1])).strip())
class DRYTest(unittest.TestCase): ''' Stuff we need to do every test, let's do here instead.. Don't Repeat Yourself. ''' def setUp(self): ''' initialize a SimpleEval ''' self.s = SimpleEval() def t(self, expr, shouldbe): #pylint: disable=invalid-name ''' test an evaluation of an expression against an expected answer ''' return self.assertEqual(self.s.eval(expr), shouldbe)
def test_functions_are_disallowed_in_expressions(self): DISALLOWED = [type, isinstance, eval, getattr, setattr, help, repr, compile, open] if simpleeval.PYTHON3: exec('DISALLOWED.append(exec)') # exec is not a function in Python2... for f in simpleeval.DISALLOW_FUNCTIONS: assert f in DISALLOWED DF = simpleeval.DEFAULT_FUNCTIONS.copy() for x in DISALLOWED: simpleeval.DEFAULT_FUNCTIONS = DF.copy() with self.assertRaises(FeatureNotAvailable): s = SimpleEval() s.functions['foo'] = x s.eval('foo(42)') simpleeval.DEFAULT_FUNCTIONS = DF.copy()
class DRYTest(unittest.TestCase): """ Stuff we need to do every test, let's do here instead.. Don't Repeat Yourself. """ def setUp(self): """ initialize a SimpleEval """ self.s = SimpleEval() def t(self, expr, shouldbe): # pylint: disable=invalid-name """ test an evaluation of an expression against an expected answer """ return self.assertEqual(self.s.eval(expr), shouldbe)
def parse_entry(self, parsed_data): if parsed_data[0] == 0: # concatenation if len(parsed_data) == 1: return element = parsed_data[1] remainder = parsed_data[2:] remainder.insert(0, 0) if type(element) is str: result = None for result in self.parse_entry(remainder): yield element + result if result is None: yield element else: element_result = None for element_result in self.parse_entry(element): remainder_result = None for remainder_result in self.parse_entry(remainder): yield element_result + remainder_result if remainder_result is None: yield element_result if element_result is None: for remainder_result in self.parse_entry(remainder): yield remainder_result elif parsed_data[0] == 1: # random choice [a,b,c] element = parsed_data[random.randint(1, len(parsed_data) - 1)] if type(element) is not str: for result in self.parse_entry(element): yield result else: yield element elif parsed_data[0] == 2: # multiple response {a,b,c} for element in parsed_data[1:]: if type(element) is str: yield element else: for result in self.parse_entry(element): yield result elif parsed_data[0] == 3: # dynamic variable ${variable} variable_name = parsed_data[1] if type(variable_name) is not str: variable_name = next(self.parse_entry(variable_name), '') evaluator = SimpleEval(names=self.variables.copy(), functions=EVAL_FUNCTIONS, operators=EVAL_OPERATORS) evaluator.names['variables'] = evaluator.names evaluator.functions['eval'] = evaluator.eval try: yield str(evaluator.eval(variable_name)) except GeneratorExit: pass except: yield '[Error: {0}]'.format(''.join(traceback.format_exception_only(sys.exc_info()[0], sys.exc_info()[1])).strip())
def eval_statements(statement, variable_context): """Evaluates math statements and returns the value args statement: a simple python-like math statement variable_context: a dict with variable names as key and assigned values as dict values """ # variable values should be numbers var_types = set(type(value) for value in variable_context.values()) if not var_types.issubset({int, float, long, Decimal, date, datetime, NoneType, bool}): raise InvalidExpression evaluator = SimpleEval(operators=SAFE_OPERATORS, names=variable_context, functions=FUNCTIONS) return evaluator.eval(statement)
def eval_statements(statement, variable_context): """Evaluates math statements and returns the value args statement: a simple python-like math statement variable_context: a dict with variable names as key and assigned values as dict values """ # variable values should be numbers var_types = set(type(value) for value in variable_context.values()) if not var_types.issubset(set([int, float, long])): raise InvalidExpression evaluator = SimpleEval(operators=SAFE_OPERATORS, names=variable_context) return evaluator.eval(statement)
class BooleanQueryType(click.ParamType): name = "query" def __init__(self): super().__init__() # Create a sandboxed evaluator allowing to use the Q object, # and the "|", "&" and "~" operators. # See: https://github.com/danthedeckie/simpleeval self.evaluator = SimpleEval( functions={"Q": Q}, operators={ ast.BitOr: operator.or_, ast.BitAnd: operator.and_, ast.Invert: operator.invert, }, ) def convert(self, value, param, ctx) -> Q: try: return self.evaluator.eval(value) # 🤯 except Exception as exc: raise click.BadParameter(str(exc))
#!/usr/bin/env python3 # -*- coding: utf-8 -*- __author__ = 'ipetrash' # pip install simpleeval from simpleeval import SimpleEval def get_from_file(file_name): with open(file_name) as f: return f.read() my_eval = SimpleEval() my_eval.functions['get'] = get_from_file print(my_eval.eval("get('a_value.txt') + get('b_value.txt')")) # '12345' print(my_eval.eval("int(get('a_value.txt')) + int(get('b_value.txt'))")) # 168
class CardDeck(CardPile): def __init__( self, card_pile_id, mat_center, mat_size, mat_boundary, card_size, card_offset, mat_color, size_scaler, update_event_handle, per_deck_cards, #initial_num_of_decks=None, face_down=True, enable_generation=None, num_of_decks_per_generation=1, enable_auto_distribution=None, destination_piles_and_cards=None, title_property=None, other_properties=None, *args, **kwargs): super().__init__(card_pile_id, mat_center, mat_size, mat_boundary, card_size, card_offset, mat_color, size_scaler, sorting_rule=None, auto_sort_setting=None, enable_sort_button=False, enable_recover_last_removed_cards=False, update_event_handle=update_event_handle, title_property=title_property, other_properties=other_properties, *args, **kwargs) self._simple_eval = SimpleEval() self.enable_auto_distribution = enable_auto_distribution self._destination_piles_and_cards = destination_piles_and_cards self._ui_destination_piles_and_cards = {} self.per_deck_cards = per_deck_cards #self.initial_num_of_decks=initial_num_of_decks self._enable_generation = enable_generation self._num_of_decks_per_generation = num_of_decks_per_generation self._ui_num_of_decks_per_generation = None self._enable_auto_distribution = enable_auto_distribution self._per_deck_cards = per_deck_cards self.face_down = face_down self._generation_button = None self._auto_distribution_button = None self.setup_vertical_ui_elements() @property def num_of_decks_per_generation(self): if self._ui_num_of_decks_per_generation is None: return None else: c_value = self._ui_num_of_decks_per_generation.text if not c_value.isdigit(): return None else: return int(c_value) @num_of_decks_per_generation.setter def num_of_decks_per_generation(self, value): if value is not None: #if self._ui_num_of_decks_per_generation.text!=str(value): self._ui_num_of_decks_per_generation.sync_text(str(value)) @property def destination_piles_and_cards(self): output_dict = {} for key, ui_input in self._ui_destination_piles_and_cards.items(): c_value = ui_input.text if not c_value.isdigit(): return None else: output_dict[key] = int(c_value) return output_dict @destination_piles_and_cards.setter def destination_piles_and_cards(self, value: dict): for key, val in value.items(): #c_value =self._ui_destination_piles_and_cards[key].text #if c_value != str(val): self._ui_destination_piles_and_cards[key].sync_text(str(val)) def update_ui_property(self, ui_property): if 'num_of_decks_per_generation' in ui_property: self.num_of_decks_per_generation = ui_property[ 'num_of_decks_per_generation'] if 'destination_piles_and_cards' in ui_property: self.destination_piles_and_cards = ui_property[ 'destination_piles_and_cards'] def deal_cards(self): if 'pile_tag_to_pile_id' in self.other_properties: card_values = self.to_valuelist() destination_piles_and_cards = self.destination_piles_and_cards if destination_piles_and_cards is not None: all_cards_to_distribute_count = sum([ len(self.other_properties['pile_tag_to_pile_id'][key]) * self._eval_expression(val) for key, val in destination_piles_and_cards.items() ]) if all_cards_to_distribute_count <= len(card_values): starting_index = 0 for key, val in destination_piles_and_cards.items(): n_cards = self._eval_expression(val) for card_pile_id in self.other_properties[ 'pile_tag_to_pile_id'][key]: new_event = gamestate.Event( type='Move', src_pile=self.card_pile_id, dst_pile=card_pile_id, cards=card_values[ starting_index:starting_index + n_cards]) self._update_event_handle(new_event, local_fast_update=False) starting_index += n_cards def _eval_expression(self, x): if isinstance(x, str): temp_str = x for key, val in self.other_properties['constants'].items(): temp_str = temp_str.replace(key, str(val)) return self._simple_eval.eval(temp_str) else: return x def generate_cards(self): """ Send gnerate new cards event :return: """ random.seed(a=None) n_deck_per_generation = self.num_of_decks_per_generation if n_deck_per_generation is not None: new_cards = [ j * MAX_DECK_SIZE + w for j in range(n_deck_per_generation) for w in self.per_deck_cards ] face_value = 'D' if self.face_down else 'U' card_status = {w: face_value for w in new_cards} random.shuffle(new_cards) new_event = gamestate.EventAddNewCards(type='AddNewCards', dst_pile=self.card_pile_id, cards=new_cards, cards_status=card_status) self._update_event_handle(new_event, local_fast_update=False) def _on_change_num_of_decks_per_generation(self, value): num_of_decks_per_generation = self.num_of_decks_per_generation if num_of_decks_per_generation is not None: new_event = gamestate.Event(type='UIElementChange', dst_pile=self.card_pile_id, property={ 'num_of_decks_per_generation': num_of_decks_per_generation }) self._update_event_handle(new_event, local_fast_update=False) def _on_change_destination_piles_and_cards(self, value): destination_piles_and_cards = self.destination_piles_and_cards if destination_piles_and_cards is not None: new_event = gamestate.Event(type='UIElementChange', dst_pile=self.card_pile_id, property={ 'destination_piles_and_cards': destination_piles_and_cards }) self._update_event_handle(new_event, local_fast_update=False) def setup_vertical_ui_elements(self): #num_vertical_button = 0 if self._enable_generation: if self._generation_button is None: text_label = ResizableGameTextLabel( width=self._vertical_button_width / 2, height=self._vertical_button_height, center_x=self._mat_center[0] + self._mat_size[0] / 2 + self._vertical_button_width / 4, center_y=self._mat_center[1] + self._mat_size[1] / 2 - (self._vertical_button_count * 2 + 1) / 2 * self._vertical_button_height, size_scaler=self._size_scaler, font_size=height_to_font_size( self._vertical_button_height), text=str('#decks')) c_text_input = SyncedResizableUIInputBox( width=self._vertical_button_width / 2, height=self._vertical_button_height, center_x=self._mat_center[0] + self._mat_size[0] / 2 + self._vertical_button_width / 4 * 3, center_y=self._mat_center[1] + self._mat_size[1] / 2 - (self._vertical_button_count * 2 + 1) / 2 * self._vertical_button_height, size_scaler=self._size_scaler, font_size=height_to_font_size( self._vertical_button_height), text=str( self._eval_expression( self._num_of_decks_per_generation)), on_text_update_hanlder=self. _on_change_num_of_decks_per_generation) self._ui_num_of_decks_per_generation = c_text_input self._vertical_button_count += 1 self._ui_elements.append(text_label) self._ui_elements.append(c_text_input) self._generation_button = self._add_vertical_buttons( self.generate_cards, 'GENERATE') if self._enable_auto_distribution: if self._auto_distribution_button is None: for key, val in self._destination_piles_and_cards.items(): text_label = ResizableGameTextLabel( width=self._vertical_button_width / 2, height=self._vertical_button_height, center_x=self._mat_center[0] + self._mat_size[0] / 2 + self._vertical_button_width / 4, center_y=self._mat_center[1] + self._mat_size[1] / 2 - (self._vertical_button_count * 2 + 1) / 2 * self._vertical_button_height, size_scaler=self._size_scaler, font_size=height_to_font_size( self._vertical_button_height), text=str(key)) c_text_input = SyncedResizableUIInputBox( width=self._vertical_button_width / 2, height=self._vertical_button_height, center_x=self._mat_center[0] + self._mat_size[0] / 2 + self._vertical_button_width / 4 * 3, center_y=self._mat_center[1] + self._mat_size[1] / 2 - (self._vertical_button_count * 2 + 1) / 2 * self._vertical_button_height, size_scaler=self._size_scaler, font_size=height_to_font_size( self._vertical_button_height), text=str(self._eval_expression(val)), on_text_update_hanlder=self. _on_change_destination_piles_and_cards) self._ui_destination_piles_and_cards[key] = c_text_input self._vertical_button_count += 1 self._ui_elements.append(text_label) self._ui_elements.append(c_text_input) self._auto_distribution_button = self._add_vertical_buttons( self.deal_cards, 'DEAL')
def evaluate_context(self, context): evaluator = SimpleEval() evaluator.names.update(context) for name, code in self._evaluables.items(): result = evaluator.eval(code) if isinstance(code, str) else code evaluator.names[name] = context[name] = result
#!/usr/bin/env python3 # -*- coding: utf-8 -*- __author__ = 'ipetrash' # pip install simpleeval from simpleeval import SimpleEval def get_from_url(value): import requests rs = requests.get('https://httpbin.org/get', params={'value': value}) return rs.json()['args']['value'] my_eval = SimpleEval() my_eval.functions['get'] = get_from_url print(my_eval.eval("get('123') + get('45')")) # '12345' print(my_eval.eval("int(get('123')) + int(get('45'))")) # 168
#!/usr/bin/env python3 # -*- coding: utf-8 -*- __author__ = 'ipetrash' # SOURCE: https://github.com/danthedeckie/simpleeval#operators # pip install simpleeval from simpleeval import SimpleEval import ast import operator as op s = SimpleEval() s.operators[ast.BitXor] = op.xor # # OR: # s.operators[ast.BitXor] = lambda a, b: a ^ b print(s.eval("2 ^ 10")) # 8
class Launcher (DirectObject): def __init__(self, app, setup_data, custom_functions={}): #we keep the 'main' application class to call some functions there self.app=app #load the config self.setup_data=setup_data self.cfg=Configer(path+self.setup_data['basic']['config_file']) #setup the window for the launcher wp = WindowProperties.getDefault() wp.setFixedSize(True) wp.setFullscreen(False) wp.setUndecorated(self.setup_data['basic']['undecorated']) wp.setOrigin(-2,-2) wp.setTitle(self.setup_data['basic']['title']) wp.setSize(self.setup_data['basic']['window_size'][0],self.setup_data['basic']['window_size'][1]) base.openMainWindow(props = wp) base.win.setCloseRequestEvent('exit_program') #a root node for ell the widgets self.root=pixel2d.attachNewNode('launcher_root') #set the bacground image self.background=DirectFrame(frameSize=_rec2d(self.setup_data['basic']['window_size'][0],self.setup_data['basic']['window_size'][1]), frameColor=(1,1,1, 1), frameTexture=path+self.setup_data['basic']['background'], parent=self.root) _resetPivot(self.background) self.background.setPos(_pos2d(0,0)) #some vars used later self.last_click_time=0.0 self.shouldExit =False self.last_button=None self.last_select_button=None self.last_select=None self.last_button_group=0 self.fonts={} self.buttons=[] self.last_slider_config_name=None self.last_slider_name=None #make the needed buttons #needed for the updater part... self.update_label=self.makeLabel("", 'wait') x=self.setup_data['basic']["window_size"][0]/2 x-=self.setup_data['style']['default']["size"][0]/2 y=self.setup_data['basic']["window_size"][1]-self.setup_data['style']['default']["size"][1]*1.5 pos=[x,y] self.update_done_button=self.makeButton(self.setup_data['basic']['msg']['ok'], {"style": "default","pos": pos,"func": "updateDone()"}) self.update_done_button.hide() #needed for the loadscreen self.loading_label=self.makeLabel(self.setup_data['basic']['msg']['loading'], 'loading') #needed for the slider screen self.slider = DirectSlider(frameSize=_rec2d(self.setup_data['style']['slider']["size"][0]*0.8, self.setup_data['style']['slider']["size"][1]), range=(0.0,1.0), value=0.5, thumb_relief=DGG.FLAT, thumb_frameTexture=path+self.setup_data['style']['slider']['thumb_img'], thumb_frameSize=(self.setup_data['style']['slider']['thumb_size'][0]/2, -self.setup_data['style']['slider']['thumb_size'][0]/2, -self.setup_data['style']['slider']['thumb_size'][1]/2, self.setup_data['style']['slider']['thumb_size'][1]/2), frameTexture=path+self.setup_data['style']['slider']['img'], frameVisibleScale=(1.25,1), command=self.setSliderValue, parent=self.root) x=self.setup_data['basic']["window_size"][0]/2 x+=(self.setup_data['style']['slider']["size"][0]*0.8)/2 y=self.setup_data['basic']["window_size"][1]/2 y+=self.setup_data['style']['slider']["size"][1]/2 self.slider.setPos(_pos2d(x,y)) self.slider.setTransparency(TransparencyAttrib.MDual) self.slider.hide() self.slider_done_button=self.makeButton(self.setup_data['basic']['msg']['ok'], {"style": "default","pos": pos,"func": "sliderDone()"}) self.slider_done_button.hide() self.slider_label=self.makeLabel("") #needed for key input self.key_input_label=self.makeLabel("") self.key_input_current_label=self.makeLabel("", "key_input") self.key_input_done=self.makeButton(self.setup_data['basic']['msg']['ok'], {"style": "default","pos": pos,"func": "keyInputDone()"}) self.key_input_done.hide() #the rest self.select_screens={} self.select_names={} self.select_labels={} for select_group in self.setup_data["select"]: self.select_screens[select_group]=[] self.select_names[select_group]={} for label in self.setup_data["select"][select_group]: self.select_names[select_group][self.setup_data["select"][select_group][label]]=label self.select_screens[select_group].append(self.makeSelectButton(label)) self.packSelectButtons(self.select_screens[select_group]) i=0 for button_group in self.setup_data["buttons"]: self.buttons.append({}) for button_name in button_group: self.buttons[i][button_name]=self.makeButton(button_name, button_group[button_name]) if i != 0: self.buttons[i][button_name].hide() i+=1 #SimpleEval stuff names={'None': None} functions={ 'Vec3':Vec3, 'startGame':self.startGame, 'exitGame':self.exitGame, 'updateGame':self.updateGame, 'updateDone':self.updateDone, 'toggleButtonGroup':self.toggleButtonGroup, 'showButton':self.showButton, 'select':self.showSelectScreen, 'slide':self.showSlideScreen, 'key':self.showKeyInputScreen, 'keyInputDone':self.keyInputDone, 'sliderDone':self.sliderDone, 'selectItem':self.selectItem, 'saveConfig':self.saveConfig } for key in custom_functions: functions[key]=custom_functions[key] self.simple_eval = SimpleEval(names=names, functions=functions) #events self.accept('exit_program',self.exitGame) base.buttonThrowers[0].node().setButtonDownEvent('buttonDown') self.accept('buttonDown', self.getKey) #tasks taskMgr.add(self.update, 'launcher_update') def disable(self): #destroy all buttons for button_group in self.buttons: for button_name in button_group: button_group[button_name].destroy() for button_group in self.select_screens: for button in self.select_screens[button_group]: button.destroy() for label in self.select_labels: self.select_labels[label].destroy() self.key_input_label.destroy() self.key_input_current_label.destroy() self.key_input_done.destroy() self.update_done_button.destroy() self.loading_label.destroy() self.update_label.destroy() self.background.destroy() #ignore all events self.ignoreAll() #remove task taskMgr.remove('launcher_update') #remove root node self.root.removeNode() #clear data del self.select_names del self.setup_data del self.last_click_time del self.shouldExit del self.last_button del self.last_select_button del self.last_select del self.last_button_group del self.fonts del self.buttons del self.last_slider_config_name del self.last_slider_name def getKey(self, keyname): self.last_key=keyname self.key_input_current_label['text']=keyname def renderSomeFrames(self, frames=1): for i in range(frames): base.graphicsEngine.renderFrame() def startGame(self): self.toggleButtonGroup(-1) self.loading_label.show() #print "starting game" self.app.startGame() def hide(self): self.root.hide() def updateDone(self): self.toggleButtonGroup(0) self.update_done_button.hide() self.update_label['text']="" self.update_label.hide() def updateGame(self, wait_txt): url=self.setup_data['basic']['update_url'] self.downloadUpdates(url) self.toggleButtonGroup(-1) self.update_label.show() self.update_label['text'] def downloadUpdates(self, url): self.files_to_download=[] self.http = HTTPClient() self.channel = self.http.makeChannel(True) self.files_to_download.append({'url':url, 'target':path+'update.json'}) self.channel.beginGetDocument(DocumentSpec(url)) self.channel.downloadToFile(Filename(path+'update.json')) self.update_label['text']+=self.setup_data['basic']['msg']['collect'] #add a task that will do the lifting taskMgr.add(self.downloadTask, 'downloadTask') def downloadTask(self, task): if self.files_to_download: if self.channel.run(): #print 'running...' return task.cont else: if not self.channel.isDownloadComplete(): #print "Error downloading file." self.update_label['text']+=self.setup_data['basic']['msg']['download_error'] self.update_label['text']+="\n"+str(self.channel.getStatusString()) else: #if the downloaded file is named 'update.json' #we get the files and urls there and add them to #the download quene last_file=self.files_to_download[0]['target'] #print "downloaded", last_file self.update_label['text']+=self.setup_data['basic']['msg']['download_ok'] +last_file self.renderSomeFrames(8) if last_file == path+'update.json': with open(path+'update.json') as f: try: file_list=json.load(f) #print "loaded json file" except: #print "Error reading file" self.update_label['text']+=self.setup_data['basic']['msg']['read_error'] #we only download files on the list that we don't have (by name) for f in file_list: #print f if not os.path.exists(path+f['target']): self.files_to_download.append({'url':f['url'], 'target':path+f['target']}) #if it's a zipfile we extract elif is_zipfile(last_file): #print "extracting" self.update_label['text']+=self.setup_data['basic']['msg']['unzip'] self.renderSomeFrames(8) with ZipFile(last_file) as zf: zf.extractall(Filename(path).toOsSpecific()) #remove zero sized files self.update_label['text']+=self.setup_data['basic']['msg']['clean_up'] self.renderSomeFrames(8) for dirpath, dirs, files in os.walk(path): for file in files: full_path = Filename(os.path.join(dirpath, file)).toOsSpecific() #print full_path if os.stat(full_path).st_size == 0: os.remove(full_path) else: self.update_label['text']+=path+last_file self.update_label['text']+="\n - not a zip file!" #remove the last file from the list and get a next one self.files_to_download.pop(0) if self.files_to_download: next_file=self.files_to_download[0] #print "next_file", next_file self.channel.beginGetDocument(DocumentSpec(next_file['url'])) self.channel.downloadToFile(Filename(next_file['target'])) return task.cont #print "done" self.update_label['text']+=self.setup_data['basic']['msg']['done'] self.update_done_button.show() return task.done def update(self, task): #calling exit from a sequence will crash the game if self.shouldExit: self.app.exit() return task.cont def exe(self, command): if command: command=command.split(";") for cmd in command: try: #print cmd self.simple_eval.eval(cmd.strip()) except Exception as e: print e def runClickAnim(self, button): old_pos=button.getPos() new_pos=old_pos+_pos2d(0, 3) Sequence(LerpPosInterval(button, 0.05,new_pos),LerpPosInterval(button, 0.05,old_pos)).start() def onButtonClick(self, button, func, event=None): time=globalClock.getFrameTime() if (time-self.last_click_time) >0.11: self.last_button=button self.runClickAnim(button) Sequence(Wait(0.1),Func(self.exe, func)).start() self.last_click_time=time def doNothing(self, arg=None): print "nop" def saveConfig(self): self.toggleButtonGroup(0) config_file=path+self.setup_data['basic']['config_file'] self.cfg.saveConfig(config_file) def exitGame(self): #self.app.exit() self.shouldExit=True def showButton(self, group, button_name): self.buttons[group][button_name].show() def selectItem(self, button_name): #set the new value in the cfg self.cfg.setCfgValueFromString(self.last_select, self.setup_data['select'][self.last_select][button_name]) #print self.cfg[self.last_select] #update the button self.last_select_button['text']=self.last_select_button.getPythonTag("name")+" "+button_name #hide the select screen self.hideSelectScreen() #show the last group self.toggleButtonGroup(self.last_button_group) def setSliderValue(self): if self.last_slider_config_name: round_to=self.setup_data['slide'][self.last_slider_config_name]["round"] mini=self.setup_data['slide'][self.last_slider_config_name]["min"] maxi=self.setup_data['slide'][self.last_slider_config_name]["max"] self.slider_value=mini+self.slider['value']*(maxi-mini) if round_to==0: self.slider_value=int(self.slider_value) else: self.slider_value=round(self.slider_value,round_to) self.slider_label['text']=self.last_slider_name+'\n'+str(self.slider_value) def sliderDone(self): self.toggleButtonGroup(self.last_button_group) self.slider_label.hide() self.slider.hide() self.slider_done_button.hide() self.buttons[self.last_button_group][self.last_slider_name]['text']=self.last_slider_name+str(self.slider_value) self.cfg[self.last_slider_config_name]=self.slider_value cmd="slide('"+self.last_slider_config_name+"', '"+self.last_slider_name+"', "+str(self.slider_value)+")" self.buttons[self.last_button_group][self.last_slider_name].bind(DGG.B1PRESS, self.onButtonClick, [self.buttons[self.last_button_group][self.last_slider_name], cmd]) def showSlideScreen(self, config_name, name, value): self.last_slider_config_name=config_name self.last_slider_name=name for button_group in self.buttons: for button_name in button_group: button_group[button_name].hide() self.slider_label.show() self.slider_label['text']=name self.slider.show() self.slider_done_button.show() mini=self.setup_data['slide'][self.last_slider_config_name]["min"] maxi=self.setup_data['slide'][self.last_slider_config_name]["max"] self.slider['value']=float(value)/float(maxi-mini) self.setSliderValue() def showSelectScreen(self, screen): self.last_select=screen self.last_select_button=self.last_button for button_group in self.buttons: for button_name in button_group: button_group[button_name].hide() for button in self.select_screens[screen]: button.show() for label in self.select_labels: if label == screen: self.select_labels[label].show() else: self.select_labels[label].hide() def keyInputDone(self): self.toggleButtonGroup(self.last_button_group) self.key_input_label.hide() self.key_input_current_label.hide() self.key_input_done.hide() self.buttons[self.last_button_group][self.last_key_name]['text']=self.last_key_name+self.last_key self.cfg[self.last_key_config_name]=self.last_key cmd="key('"+self.last_key_config_name+"', '"+self.last_key_name+"', '"+self.last_key+"')" self.buttons[self.last_button_group][self.last_key_name].bind(DGG.B1PRESS, self.onButtonClick, [self.buttons[self.last_button_group][self.last_key_name], cmd]) def showKeyInputScreen(self, config_name, name, value): self.last_key_config_name=config_name self.last_key_name=name for button_group in self.buttons: for button_name in button_group: button_group[button_name].hide() self.key_input_label.show() self.key_input_current_label.show() self.key_input_done.show() self.key_input_label['text']=self.setup_data['basic']['msg']['new_key'].format(name) self.key_input_current_label['text']=value def hideSelectScreen(self): for screen in self.select_screens: for button in self.select_screens[screen]: button.hide() for label in self.select_labels: self.select_labels[label].hide() def toggleButtonGroup(self, group): self.last_button_group=group i=0 for button_group in self.buttons: for button_name in button_group: if i==group: button_group[button_name].show() else: button_group[button_name].hide() i+=1 def getFont(self, font_name, font_size): if font_name in self.fonts: if font_size in self.fonts[font_name]: font=self.fonts[font_name][font_size] else: font=self.addFontSize(font_name, font_size) else: font=self.addFont(font_name, font_size) return font def addFont(self, font_name, font_size): font=loader.loadFont(path+font_name) font.setPixelsPerUnit(font_size) font.setMinfilter(Texture.FTNearest ) font.setMagfilter(Texture.FTNearest ) self.fonts[font_name]={font_size:font} return font def addFontSize(self, font_name, font_size): #a bit of a hack to get a font of any size font=self.fonts[font_name].itervalues().next() new_font=font.makeCopy() new_font.setPixelsPerUnit(font_size) self.fonts[font_name][font_size]=new_font return new_font def getTextAlign(self, align): a=align.strip().lower() if a == 'center': return TextNode.ACenter elif a == 'left': return TextNode.ALeft elif a == 'right': return TextNode.ARight elif a == 'boxed_left': return TextNode.ABoxedLeft elif a == 'boxed_right': return TextNode.ABoxedRight elif a == 'boxed_center': return TextNode.ABoxedCenter else: return TextNode.ALeft def packSelectButtons(self, button_list): label_y=self.setup_data['style']["label"]["size"][1] x_offset=0 y_offset=0 button_x=self.setup_data['style']["select"]["size"][0] button_y=self.setup_data['style']["select"]["size"][1] window_x=self.setup_data['basic']["window_size"][0] window_y=self.setup_data['basic']["window_size"][1]+label_y button_count=len(button_list) last_row_x_offset=0 #how many buttons can I fit side by side? buttons_per_row=window_x/button_x #how much space is left unused? x_offset=(window_x%button_x)/2 #can all the buttons fit in one row? if button_count <= buttons_per_row: y_offset=window_y/2-button_y/2 row_count=1 x_offset+=(window_x-(button_count*button_x))/2 else: row_count=button_count/buttons_per_row if button_count%buttons_per_row != 0: row_count+=1 y_offset=(window_y-((row_count)*button_y))/2 if y_offset<0 or x_offset<0: print "(warning) Select buttons can't fit the window" #is the last row full? if row_count > 1 and buttons_per_row*row_count > button_count: last_row_x_offset=(buttons_per_row*row_count-button_count)*button_x/2 #start packing the buttons i=0 row=-1 for button in button_list: column=i%buttons_per_row if column==0: row+=1 x=x_offset+button_x*column y=y_offset+button_y*row if row==row_count-1: #this is the last row x+=last_row_x_offset button.setPos(_pos2d(x,y)) i+=1 def makeLabel(self, name, style_name="label"): style=self.setup_data['style'][style_name] button=self.makeStyleButton(style) button['state'] = DGG.DISABLED button['text']=name x=self.setup_data['basic']["window_size"][0]/2 x-=style["size"][0]/2 button.setPos(_pos2d(x,0)) button.hide() return button def makeSelectButton(self, name): style=self.setup_data['style']["select"] button=self.makeStyleButton(style) button['text']=name button.bind(DGG.B1PRESS, self.onButtonClick, [button, "selectItem('"+name+"')"]) button.hide() return button def makeButton(self, name, config): style=self.setup_data['style'][config["style"]] button=self.makeStyleButton(style) button['text']=name button.setPos(_pos2d(config["pos"][0], config["pos"][1])) if "select" in config: self.select_labels[config["select"]]=self.makeLabel(name) current_value=self.cfg.getCfgValueAsString(config["select"]) if current_value in self.select_names[config["select"]]: label_txt=self.select_names[config["select"]][current_value] else: label_txt=current_value +"*" button['text']=name+" "+label_txt button.bind(DGG.B1PRESS, self.onButtonClick, [button, "select('"+config["select"]+"')"]) button.setPythonTag("name", name) elif "slide" in config: current_value=self.cfg.getCfgValueAsString(config["slide"]) if current_value == "None": current_value=str(self.setup_data['slide'][config["slide"]]['default']) self.cfg[config["slide"]]=self.setup_data['slide'][config["slide"]]['default'] button['text']+=current_value button.bind(DGG.B1PRESS, self.onButtonClick, [button, "slide('"+config["slide"]+"', '"+name+"', "+current_value+")"]) elif "key" in config: current_value=self.cfg.getCfgValueAsString(config["key"]) if current_value == "None": current_value=str(self.setup_data['key'][config["key"]]) self.cfg[config["key"]]=current_value button['text']+=current_value button.bind(DGG.B1PRESS, self.onButtonClick, [button, "key('"+config["key"]+"', '"+name+"', '"+current_value+"')"]) elif "func" in config: button.bind(DGG.B1PRESS, self.onButtonClick, [button,config["func"] ]) return button def makeStyleButton(self, config): align=self.getTextAlign(config["text_align"]) if align in (TextNode.ACenter, TextNode.ABoxedCenter): text_offset=[ -config["size"][0]/2+config["text_offset"][0], config["size"][1]/2+config["text_offset"][1] ] elif align in (TextNode.ALeft, TextNode.ABoxedLeft): text_offset=[ -config["size"][0]+config["text_offset"][0], config["size"][1]/2+config["text_offset"][1] ] else: text_offset=[ +config["text_offset"][0], config["size"][1]/2+config["text_offset"][1] ] button=DirectFrame(frameSize=_rec2d(config["size"][0],config["size"][1]), frameColor=(1,1,1, 1), frameTexture=path+config["img"], text_font=self.getFont(config["font"],config["text_size"]), text=" ", text_scale=config["text_size"], text_align=align, text_pos=text_offset, text_fg=config["text_color"], state=DGG.NORMAL, parent=self.root) _resetPivot(button) button.setTransparency(TransparencyAttrib.MDual) return button
#!/usr/bin/env python3 # -*- coding: utf-8 -*- __author__ = 'ipetrash' # SOURCE: https://github.com/danthedeckie/simpleeval#operators # pip install simpleeval from simpleeval import SimpleEval import ast import operator as op expr = "((2 + 2 * 2) / 3) ** 10 - 24" s = SimpleEval() print(s.eval(expr)) # 1000.0 # Mad s.operators[ast.Add] = op.mul s.operators[ast.Sub] = op.add s.operators[ast.Mult] = op.pow s.operators[ast.Pow] = op.sub print(s.eval(expr)) # 16.666666666666664
def test_no_operators(self): self.s.eval('1+2') with self.assertRaises(OperatorNotDefined): s = SimpleEval(operators={}) s.eval('1+2')
# If you want to allow creation of these, the EvalWithCompoundTypes class works. Just replace any use of # SimpleEval with that. # """ # pip install simpleeval from simpleeval import simple_eval, SimpleEval, EvalWithCompoundTypes # SimpleEval and simple_eval NOT WORK with compound types try: print(simple_eval('[1, 2, 3, 4]')) except Exception as e: print(e) # Sorry, List is not available in this evaluator try: my_eval = SimpleEval() print(my_eval.eval('[1, 2, 3, 4]')) except Exception as e: print(e) # Sorry, List is not available in this evaluator print() # Compound Types my_compound_types_eval = EvalWithCompoundTypes() my_compound_types_eval.functions['len'] = len # list print(my_compound_types_eval.eval('[1, 2, 3, 4]')) # [1, 2, 3, 4] print(my_compound_types_eval.eval('[1, 2] + [3, 4]')) # [1, 2, 3, 4] print(my_compound_types_eval.eval('len([1, 2, 3, 4])')) # 4 print(my_compound_types_eval.eval('[1, 2, 1, 3, 4].count(1)')) # 2 print(my_compound_types_eval.eval('list("1234")')) # ['1', '2', '3', '4']
class Launcher(DirectObject): def __init__(self, app, setup_data, custom_functions={}): #we keep the 'main' application class to call some functions there self.app = app #load the config self.setup_data = setup_data self.cfg = Configer(path + self.setup_data['basic']['config_file']) #setup the window for the launcher wp = WindowProperties.getDefault() wp.setFixedSize(True) wp.setFullscreen(False) wp.setUndecorated(self.setup_data['basic']['undecorated']) wp.setOrigin(-2, -2) wp.setTitle(self.setup_data['basic']['title']) wp.setSize(self.setup_data['basic']['window_size'][0], self.setup_data['basic']['window_size'][1]) base.openMainWindow(props=wp) base.win.setCloseRequestEvent('exit_program') #a root node for ell the widgets self.root = pixel2d.attachNewNode('launcher_root') #set the bacground image self.background = DirectFrame( frameSize=_rec2d(self.setup_data['basic']['window_size'][0], self.setup_data['basic']['window_size'][1]), frameColor=(1, 1, 1, 1), frameTexture=path + self.setup_data['basic']['background'], parent=self.root) _resetPivot(self.background) self.background.setPos(_pos2d(0, 0)) #some vars used later self.last_click_time = 0.0 self.shouldExit = False self.last_button = None self.last_select_button = None self.last_select = None self.last_button_group = 0 self.fonts = {} self.buttons = [] self.last_slider_config_name = None self.last_slider_name = None #make the needed buttons #needed for the updater part... self.update_label = self.makeLabel("", 'wait') x = self.setup_data['basic']["window_size"][0] / 2 x -= self.setup_data['style']['default']["size"][0] / 2 y = self.setup_data['basic']["window_size"][ 1] - self.setup_data['style']['default']["size"][1] * 1.5 pos = [x, y] self.update_done_button = self.makeButton( self.setup_data['basic']['msg']['ok'], { "style": "default", "pos": pos, "func": "updateDone()" }) self.update_done_button.hide() #needed for the loadscreen self.loading_label = self.makeLabel( self.setup_data['basic']['msg']['loading'], 'loading') #needed for the slider screen self.slider = DirectSlider( frameSize=_rec2d( self.setup_data['style']['slider']["size"][0] * 0.8, self.setup_data['style']['slider']["size"][1]), range=(0.0, 1.0), value=0.5, thumb_relief=DGG.FLAT, thumb_frameTexture=path + self.setup_data['style']['slider']['thumb_img'], thumb_frameSize=( self.setup_data['style']['slider']['thumb_size'][0] / 2, -self.setup_data['style']['slider']['thumb_size'][0] / 2, -self.setup_data['style']['slider']['thumb_size'][1] / 2, self.setup_data['style']['slider']['thumb_size'][1] / 2), frameTexture=path + self.setup_data['style']['slider']['img'], frameVisibleScale=(1.25, 1), command=self.setSliderValue, parent=self.root) x = self.setup_data['basic']["window_size"][0] / 2 x += (self.setup_data['style']['slider']["size"][0] * 0.8) / 2 y = self.setup_data['basic']["window_size"][1] / 2 y += self.setup_data['style']['slider']["size"][1] / 2 self.slider.setPos(_pos2d(x, y)) self.slider.setTransparency(TransparencyAttrib.MDual) self.slider.hide() self.slider_done_button = self.makeButton( self.setup_data['basic']['msg']['ok'], { "style": "default", "pos": pos, "func": "sliderDone()" }) self.slider_done_button.hide() self.slider_label = self.makeLabel("") #needed for key input self.key_input_label = self.makeLabel("") self.key_input_current_label = self.makeLabel("", "key_input") self.key_input_done = self.makeButton( self.setup_data['basic']['msg']['ok'], { "style": "default", "pos": pos, "func": "keyInputDone()" }) self.key_input_done.hide() #the rest self.select_screens = {} self.select_names = {} self.select_labels = {} for select_group in self.setup_data["select"]: self.select_screens[select_group] = [] self.select_names[select_group] = {} for label in self.setup_data["select"][select_group]: self.select_names[select_group][self.setup_data["select"] [select_group][label]] = label self.select_screens[select_group].append( self.makeSelectButton(label)) self.packSelectButtons(self.select_screens[select_group]) i = 0 for button_group in self.setup_data["buttons"]: self.buttons.append({}) for button_name in button_group: self.buttons[i][button_name] = self.makeButton( button_name, button_group[button_name]) if i != 0: self.buttons[i][button_name].hide() i += 1 #SimpleEval stuff names = {'None': None} functions = { 'Vec3': Vec3, 'startGame': self.startGame, 'exitGame': self.exitGame, 'updateGame': self.updateGame, 'updateDone': self.updateDone, 'toggleButtonGroup': self.toggleButtonGroup, 'showButton': self.showButton, 'select': self.showSelectScreen, 'slide': self.showSlideScreen, 'key': self.showKeyInputScreen, 'keyInputDone': self.keyInputDone, 'sliderDone': self.sliderDone, 'selectItem': self.selectItem, 'saveConfig': self.saveConfig } for key in custom_functions: functions[key] = custom_functions[key] self.simple_eval = SimpleEval(names=names, functions=functions) #events self.accept('exit_program', self.exitGame) base.buttonThrowers[0].node().setButtonDownEvent('buttonDown') self.accept('buttonDown', self.getKey) #tasks taskMgr.add(self.update, 'launcher_update') def disable(self): #destroy all buttons for button_group in self.buttons: for button_name in button_group: button_group[button_name].destroy() for button_group in self.select_screens: for button in self.select_screens[button_group]: button.destroy() for label in self.select_labels: self.select_labels[label].destroy() self.key_input_label.destroy() self.key_input_current_label.destroy() self.key_input_done.destroy() self.update_done_button.destroy() self.loading_label.destroy() self.update_label.destroy() self.background.destroy() #ignore all events self.ignoreAll() #remove task taskMgr.remove('launcher_update') #remove root node self.root.removeNode() #clear data del self.select_names del self.setup_data del self.last_click_time del self.shouldExit del self.last_button del self.last_select_button del self.last_select del self.last_button_group del self.fonts del self.buttons del self.last_slider_config_name del self.last_slider_name def getKey(self, keyname): self.last_key = keyname self.key_input_current_label['text'] = keyname def renderSomeFrames(self, frames=1): for i in range(frames): base.graphicsEngine.renderFrame() def startGame(self): self.toggleButtonGroup(-1) self.loading_label.show() #print "starting game" self.app.startGame() def hide(self): self.root.hide() def updateDone(self): self.toggleButtonGroup(0) self.update_done_button.hide() self.update_label['text'] = "" self.update_label.hide() def updateGame(self, wait_txt): url = self.setup_data['basic']['update_url'] self.downloadUpdates(url) self.toggleButtonGroup(-1) self.update_label.show() self.update_label['text'] def downloadUpdates(self, url): self.files_to_download = [] self.http = HTTPClient() self.channel = self.http.makeChannel(True) self.files_to_download.append({ 'url': url, 'target': path + 'update.json' }) self.channel.beginGetDocument(DocumentSpec(url)) self.channel.downloadToFile(Filename(path + 'update.json')) self.update_label['text'] += self.setup_data['basic']['msg']['collect'] #add a task that will do the lifting taskMgr.add(self.downloadTask, 'downloadTask') def downloadTask(self, task): if self.files_to_download: if self.channel.run(): #print 'running...' return task.cont else: if not self.channel.isDownloadComplete(): #print "Error downloading file." self.update_label['text'] += self.setup_data['basic'][ 'msg']['download_error'] self.update_label['text'] += "\n" + str( self.channel.getStatusString()) else: #if the downloaded file is named 'update.json' #we get the files and urls there and add them to #the download quene last_file = self.files_to_download[0]['target'] #print "downloaded", last_file self.update_label['text'] += self.setup_data['basic'][ 'msg']['download_ok'] + last_file self.renderSomeFrames(8) if last_file == path + 'update.json': with open(path + 'update.json') as f: try: file_list = json.load(f) #print "loaded json file" except: #print "Error reading file" self.update_label['text'] += self.setup_data[ 'basic']['msg']['read_error'] #we only download files on the list that we don't have (by name) for f in file_list: #print f if not os.path.exists(path + f['target']): self.files_to_download.append({ 'url': f['url'], 'target': path + f['target'] }) #if it's a zipfile we extract elif is_zipfile(last_file): #print "extracting" self.update_label['text'] += self.setup_data['basic'][ 'msg']['unzip'] self.renderSomeFrames(8) with ZipFile(last_file) as zf: zf.extractall(Filename(path).toOsSpecific()) #remove zero sized files self.update_label['text'] += self.setup_data['basic'][ 'msg']['clean_up'] self.renderSomeFrames(8) for dirpath, dirs, files in os.walk(path): for file in files: full_path = Filename( os.path.join(dirpath, file)).toOsSpecific() #print full_path if os.stat(full_path).st_size == 0: os.remove(full_path) else: self.update_label['text'] += path + last_file self.update_label['text'] += "\n - not a zip file!" #remove the last file from the list and get a next one self.files_to_download.pop(0) if self.files_to_download: next_file = self.files_to_download[0] #print "next_file", next_file self.channel.beginGetDocument( DocumentSpec(next_file['url'])) self.channel.downloadToFile( Filename(next_file['target'])) return task.cont #print "done" self.update_label['text'] += self.setup_data['basic']['msg']['done'] self.update_done_button.show() return task.done def update(self, task): #calling exit from a sequence will crash the game if self.shouldExit: self.app.exit() return task.cont def exe(self, command): if command: command = command.split(";") for cmd in command: try: #print cmd self.simple_eval.eval(cmd.strip()) except Exception as e: print e def runClickAnim(self, button): old_pos = button.getPos() new_pos = old_pos + _pos2d(0, 3) Sequence(LerpPosInterval(button, 0.05, new_pos), LerpPosInterval(button, 0.05, old_pos)).start() def onButtonClick(self, button, func, event=None): time = globalClock.getFrameTime() if (time - self.last_click_time) > 0.11: self.last_button = button self.runClickAnim(button) Sequence(Wait(0.1), Func(self.exe, func)).start() self.last_click_time = time def doNothing(self, arg=None): print "nop" def saveConfig(self): self.toggleButtonGroup(0) config_file = path + self.setup_data['basic']['config_file'] self.cfg.saveConfig(config_file) def exitGame(self): #self.app.exit() self.shouldExit = True def showButton(self, group, button_name): self.buttons[group][button_name].show() def selectItem(self, button_name): #set the new value in the cfg self.cfg.setCfgValueFromString( self.last_select, self.setup_data['select'][self.last_select][button_name]) #print self.cfg[self.last_select] #update the button self.last_select_button['text'] = self.last_select_button.getPythonTag( "name") + " " + button_name #hide the select screen self.hideSelectScreen() #show the last group self.toggleButtonGroup(self.last_button_group) def setSliderValue(self): if self.last_slider_config_name: round_to = self.setup_data['slide'][ self.last_slider_config_name]["round"] mini = self.setup_data['slide'][ self.last_slider_config_name]["min"] maxi = self.setup_data['slide'][ self.last_slider_config_name]["max"] self.slider_value = mini + self.slider['value'] * (maxi - mini) if round_to == 0: self.slider_value = int(self.slider_value) else: self.slider_value = round(self.slider_value, round_to) self.slider_label['text'] = self.last_slider_name + '\n' + str( self.slider_value) def sliderDone(self): self.toggleButtonGroup(self.last_button_group) self.slider_label.hide() self.slider.hide() self.slider_done_button.hide() self.buttons[self.last_button_group][ self.last_slider_name]['text'] = self.last_slider_name + str( self.slider_value) self.cfg[self.last_slider_config_name] = self.slider_value cmd = "slide('" + self.last_slider_config_name + "', '" + self.last_slider_name + "', " + str( self.slider_value) + ")" self.buttons[self.last_button_group][self.last_slider_name].bind( DGG.B1PRESS, self.onButtonClick, [self.buttons[self.last_button_group][self.last_slider_name], cmd]) def showSlideScreen(self, config_name, name, value): self.last_slider_config_name = config_name self.last_slider_name = name for button_group in self.buttons: for button_name in button_group: button_group[button_name].hide() self.slider_label.show() self.slider_label['text'] = name self.slider.show() self.slider_done_button.show() mini = self.setup_data['slide'][self.last_slider_config_name]["min"] maxi = self.setup_data['slide'][self.last_slider_config_name]["max"] self.slider['value'] = float(value) / float(maxi - mini) self.setSliderValue() def showSelectScreen(self, screen): self.last_select = screen self.last_select_button = self.last_button for button_group in self.buttons: for button_name in button_group: button_group[button_name].hide() for button in self.select_screens[screen]: button.show() for label in self.select_labels: if label == screen: self.select_labels[label].show() else: self.select_labels[label].hide() def keyInputDone(self): self.toggleButtonGroup(self.last_button_group) self.key_input_label.hide() self.key_input_current_label.hide() self.key_input_done.hide() self.buttons[self.last_button_group][ self.last_key_name]['text'] = self.last_key_name + self.last_key self.cfg[self.last_key_config_name] = self.last_key cmd = "key('" + self.last_key_config_name + "', '" + self.last_key_name + "', '" + self.last_key + "')" self.buttons[self.last_button_group][self.last_key_name].bind( DGG.B1PRESS, self.onButtonClick, [self.buttons[self.last_button_group][self.last_key_name], cmd]) def showKeyInputScreen(self, config_name, name, value): self.last_key_config_name = config_name self.last_key_name = name for button_group in self.buttons: for button_name in button_group: button_group[button_name].hide() self.key_input_label.show() self.key_input_current_label.show() self.key_input_done.show() self.key_input_label['text'] = self.setup_data['basic']['msg'][ 'new_key'].format(name) self.key_input_current_label['text'] = value def hideSelectScreen(self): for screen in self.select_screens: for button in self.select_screens[screen]: button.hide() for label in self.select_labels: self.select_labels[label].hide() def toggleButtonGroup(self, group): self.last_button_group = group i = 0 for button_group in self.buttons: for button_name in button_group: if i == group: button_group[button_name].show() else: button_group[button_name].hide() i += 1 def getFont(self, font_name, font_size): if font_name in self.fonts: if font_size in self.fonts[font_name]: font = self.fonts[font_name][font_size] else: font = self.addFontSize(font_name, font_size) else: font = self.addFont(font_name, font_size) return font def addFont(self, font_name, font_size): font = loader.loadFont(path + font_name) font.setPixelsPerUnit(font_size) font.setMinfilter(Texture.FTNearest) font.setMagfilter(Texture.FTNearest) self.fonts[font_name] = {font_size: font} return font def addFontSize(self, font_name, font_size): #a bit of a hack to get a font of any size font = self.fonts[font_name].itervalues().next() new_font = font.makeCopy() new_font.setPixelsPerUnit(font_size) self.fonts[font_name][font_size] = new_font return new_font def getTextAlign(self, align): a = align.strip().lower() if a == 'center': return TextNode.ACenter elif a == 'left': return TextNode.ALeft elif a == 'right': return TextNode.ARight elif a == 'boxed_left': return TextNode.ABoxedLeft elif a == 'boxed_right': return TextNode.ABoxedRight elif a == 'boxed_center': return TextNode.ABoxedCenter else: return TextNode.ALeft def packSelectButtons(self, button_list): label_y = self.setup_data['style']["label"]["size"][1] x_offset = 0 y_offset = 0 button_x = self.setup_data['style']["select"]["size"][0] button_y = self.setup_data['style']["select"]["size"][1] window_x = self.setup_data['basic']["window_size"][0] window_y = self.setup_data['basic']["window_size"][1] + label_y button_count = len(button_list) last_row_x_offset = 0 #how many buttons can I fit side by side? buttons_per_row = window_x / button_x #how much space is left unused? x_offset = (window_x % button_x) / 2 #can all the buttons fit in one row? if button_count <= buttons_per_row: y_offset = window_y / 2 - button_y / 2 row_count = 1 x_offset += (window_x - (button_count * button_x)) / 2 else: row_count = button_count / buttons_per_row if button_count % buttons_per_row != 0: row_count += 1 y_offset = (window_y - ((row_count) * button_y)) / 2 if y_offset < 0 or x_offset < 0: print "(warning) Select buttons can't fit the window" #is the last row full? if row_count > 1 and buttons_per_row * row_count > button_count: last_row_x_offset = (buttons_per_row * row_count - button_count) * button_x / 2 #start packing the buttons i = 0 row = -1 for button in button_list: column = i % buttons_per_row if column == 0: row += 1 x = x_offset + button_x * column y = y_offset + button_y * row if row == row_count - 1: #this is the last row x += last_row_x_offset button.setPos(_pos2d(x, y)) i += 1 def makeLabel(self, name, style_name="label"): style = self.setup_data['style'][style_name] button = self.makeStyleButton(style) button['state'] = DGG.DISABLED button['text'] = name x = self.setup_data['basic']["window_size"][0] / 2 x -= style["size"][0] / 2 button.setPos(_pos2d(x, 0)) button.hide() return button def makeSelectButton(self, name): style = self.setup_data['style']["select"] button = self.makeStyleButton(style) button['text'] = name button.bind(DGG.B1PRESS, self.onButtonClick, [button, "selectItem('" + name + "')"]) button.hide() return button def makeButton(self, name, config): style = self.setup_data['style'][config["style"]] button = self.makeStyleButton(style) button['text'] = name button.setPos(_pos2d(config["pos"][0], config["pos"][1])) if "select" in config: self.select_labels[config["select"]] = self.makeLabel(name) current_value = self.cfg.getCfgValueAsString(config["select"]) if current_value in self.select_names[config["select"]]: label_txt = self.select_names[config["select"]][current_value] else: label_txt = current_value + "*" button['text'] = name + " " + label_txt button.bind(DGG.B1PRESS, self.onButtonClick, [button, "select('" + config["select"] + "')"]) button.setPythonTag("name", name) elif "slide" in config: current_value = self.cfg.getCfgValueAsString(config["slide"]) if current_value == "None": current_value = str( self.setup_data['slide'][config["slide"]]['default']) self.cfg[config["slide"]] = self.setup_data['slide'][ config["slide"]]['default'] button['text'] += current_value button.bind(DGG.B1PRESS, self.onButtonClick, [ button, "slide('" + config["slide"] + "', '" + name + "', " + current_value + ")" ]) elif "key" in config: current_value = self.cfg.getCfgValueAsString(config["key"]) if current_value == "None": current_value = str(self.setup_data['key'][config["key"]]) self.cfg[config["key"]] = current_value button['text'] += current_value button.bind(DGG.B1PRESS, self.onButtonClick, [ button, "key('" + config["key"] + "', '" + name + "', '" + current_value + "')" ]) elif "func" in config: button.bind(DGG.B1PRESS, self.onButtonClick, [button, config["func"]]) return button def makeStyleButton(self, config): align = self.getTextAlign(config["text_align"]) if align in (TextNode.ACenter, TextNode.ABoxedCenter): text_offset = [ -config["size"][0] / 2 + config["text_offset"][0], config["size"][1] / 2 + config["text_offset"][1] ] elif align in (TextNode.ALeft, TextNode.ABoxedLeft): text_offset = [ -config["size"][0] + config["text_offset"][0], config["size"][1] / 2 + config["text_offset"][1] ] else: text_offset = [ +config["text_offset"][0], config["size"][1] / 2 + config["text_offset"][1] ] button = DirectFrame(frameSize=_rec2d(config["size"][0], config["size"][1]), frameColor=(1, 1, 1, 1), frameTexture=path + config["img"], text_font=self.getFont(config["font"], config["text_size"]), text=" ", text_scale=config["text_size"], text_align=align, text_pos=text_offset, text_fg=config["text_color"], state=DGG.NORMAL, parent=self.root) _resetPivot(button) button.setTransparency(TransparencyAttrib.MDual) return button
print( simple_eval("abs(sin(3) * cos(3))", functions={ 'sin': math.sin, 'cos': math.cos, 'abs': abs })) # 0.13970774909946293 def my_md5(value): import hashlib return hashlib.md5(bytes(value, 'utf-8')).hexdigest() print(simple_eval("md5('Hello World!')", functions={'md5': my_md5})) # ed076287532e86365e841e92bfc50d8c print(simple_eval("list('1234')", functions={'list': list})) # ['1', '2', '3', '4'] print() # Using SimpleEval class from simpleeval import SimpleEval my_eval = SimpleEval() my_eval.names['a'] = 2 my_eval.functions['square'] = lambda x: x * x print(my_eval.eval('1 + 1 * a')) # 3 print(my_eval.eval('square(1 + 1 * a)')) # 9
import ast import operator as op SUPPORTED_OPERATORS = { ast.Add: op.add, ast.Sub: op.sub, } print(simple_eval("2 + 2 - 1", operators=SUPPORTED_OPERATORS)) # 3 try: print(simple_eval( "2 + 2 * 2", operators=SUPPORTED_OPERATORS)) # KeyError: <class '_ast.Mult'> except Exception as e: print(repr(e)) print() s = SimpleEval(operators=SUPPORTED_OPERATORS) # # OR: # s = SimpleEval() # s.operators = SUPPORTED_OPERATORS print(s.eval("2 + 2 - 1")) # 3 try: print(s.eval("2 + 2 * 2")) # KeyError: <class '_ast.Mult'> except Exception as e: print(repr(e))
#!/usr/bin/env python3 # -*- coding: utf-8 -*- __author__ = 'ipetrash' # pip install simpleeval from simpleeval import SimpleEval my_functions = { 'dict': dict, 'list': list, 'set': set, 'tuple': tuple, 'str': str, 'sorted': sorted, } my_eval = SimpleEval(functions=my_functions) print(my_eval.eval('dict(a="1", b=2)["a"]')) # "1" print(my_eval.eval('list("123")[0]')) # "1" print(my_eval.eval('sorted(set("12213"))[0]')) # "1" print(my_eval.eval('tuple("123")[0]')) # "1" print(my_eval.eval('str(123)[0]')) # "1" print(my_eval.eval('sorted("43198")[0]')) # "1" print() print(my_eval.eval('"1234567890"[:3]')) # 123 print(my_eval.eval('list("1234567890")[:3]')) # ['1', '2', '3'] print(my_eval.eval('"+".join(list("1234567890")[:3])')) # 1+2+3
#!/usr/bin/env python3 # -*- coding: utf-8 -*- __author__ = 'ipetrash' # pip install simpleeval from simpleeval import simple_eval my_functions = { 'my_pos': lambda: { 'x': 12, 'y': 10 }, 'map': map, 'str': str, } print(simple_eval('my_pos()["x"] * my_pos()["y"]', functions=my_functions)) # 120 print(simple_eval('"x".join(map(str, my_pos().values()))', functions=my_functions)) # 12x10 print() # OR: from simpleeval import SimpleEval my_eval = SimpleEval(functions=my_functions) print(my_eval.eval('my_pos()["x"] * my_pos()["y"]')) # 120 print(my_eval.eval('"x".join(map(str, my_pos().values()))')) # 12x10
def test_no_functions(self): self.s.eval('int(42)') with self.assertRaises(FunctionNotDefined): s = SimpleEval(functions={}) s.eval('int(42)')
class Reminder(object): """ Base Reminder object to handle watch and notification for a single reminder. """ watcher_type_map = {'http': HTTPWatcher, 'mqtt': MQTTWatcher} alerter_type_map = {'log': LogAlerter} def __init__(self, condition, daemon=None, watcher=None, alerter=None): """ Create Reminder object. :param str condition: An expression to indicate that an alert should be sent. Should evaluate to True or False only. :param ReminderDaemon daemon: A ReminderDaemon instance where jobs will be scheduled. :param Watcher watcher: A Watcher instance to handle resource monitoring. :param Alerter alerter: An Alerter instance to handle sending notifications for Reminder. """ self._logger = logging.getLogger(__name__) self._daemon = daemon try: self._logger.setLevel(self._daemon.logger.level) except AttributeError: pass self.jobs = [] self.job_ids = [] self.condition = condition if watcher: self._logger.debug('creating watcher from: %s', watcher) watcher['reminder'] = self WatcherClass = getattr( importlib.import_module('reminders.watchers'), watcher.get('type')) self.watcher = WatcherClass(**watcher) jobs = self.watcher.schedules for job in jobs: job['func'] = self.check self._logger.debug('added job to jobs: %s', job) self.jobs.append(job) if alerter: self._logger.debug('creating alerter from: %s', alerter) alerter['reminder'] = self AlerterClass = getattr( importlib.import_module('reminders.alerters'), alerter.get('type')) self.alerter = AlerterClass(**alerter) self.simple_eval = SimpleEval() self.simple_eval.names.update({ 'status': self.status, 'now': self.now, }) self.simple_eval.functions = { 'pendulum': pendulum, 'date': pendulum.instance } @property def now(self): """Shortcut for expression evaluation against current time""" return pendulum.now() @property def status(self): if self.watcher: try: d = dateparse(self.watcher.update(), settings={'STRICT_PARSING': True}) if d: return d else: return self.watcher.update() except TypeError: return None else: self._logger.error('No watcher associated', exc_info=True) return None def test_condition(self): """ .. deprecated:: 0.1 Use :func:`eval` instead. """ results = {} condition = self.condition.replace('$status', self.watcher.update()) prefix, comparator, postfix = re.split(r'\s([<>(<=)(>=)(==)(!=)])\s', condition) prefix = "pendulum.instance(dateparse('{}'))".format( prefix) if dateparse(prefix, settings={ 'STRICT_PARSING': True }) else "'{}'".format(prefix) if ( isinstance(prefix, str) and not prefix.isnumeric()) else prefix postfix = "pendulum.instance(dateparse('{}'))".format( postfix) if dateparse(postfix, settings={ 'STRICT_PARSING': True }) else "'{}'".format(postfix) if (isinstance( postfix, str) and not postfix.isnumeric()) else postfix expression = "results['content'] = {} {} {}".format( prefix, comparator, postfix) exec(expression) return results['content'] def eval(self): """ Evaluate self.expression :returns: True if alert should be started :rtype: bool """ try: return self.simple_eval.eval(self.condition) except TypeError: self._logger.error('Error evaluating expression.', exc_info=True) return None def check(self): """Runs self.test_condition() and sends Alert if True.""" if self.eval() and self.alerter: self._logger.debug('activating alert') self.alerter.activate() else: self._logger.debug('checked successfully - no alert necessary') def activate(self): """TBD - May be unnecessary at this level.""" raise NotImplementedError("activate() hasn't been implemented yet") def deactivate(self): """TBD - May be unnecessary at this level.""" raise NotImplementedError("deactivate() hasn't been implemented yet")
#!/usr/bin/env python3 # -*- coding: utf-8 -*- __author__ = 'ipetrash' # SOURCE: https://github.com/danthedeckie/simpleeval/blob/master/README.rst#creating-an-evaluator-class # pip install simpleeval from simpleeval import SimpleEval # Evaluator class my_eval = SimpleEval() print(my_eval.eval("1 + 1")) # 2 print(my_eval.eval('100 * 10')) # 1000 # Append functions def boo(): return 'Boo!' my_eval.functions["boo"] = boo # Set names my_eval.names['fortytwo'] = 42 print(my_eval.eval('fortytwo * 4')) # 168 print() # this actually means you can modify names (or functions) with functions, if you really feel so inclined: def set_val(name, value):