Source code for aiidalab_widgets_base.misc

"""Some useful classes used acrross the repository."""

import io
import tokenize

import ipywidgets as ipw
from traitlets import Unicode


[docs] class CopyToClipboardButton(ipw.Button): """Button to copy text to clipboard.""" value = Unicode(allow_none=True) # Traitlet that contains a string to copy.
[docs] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) super().on_click(self.copy_to_clipboard)
[docs] def copy_to_clipboard(self, change=None): # pylint:disable=unused-argument """Copy text to clipboard.""" from IPython.display import Javascript, display javas = Javascript( f""" function copyStringToClipboard (str) {{ // Create new element var el = document.createElement('textarea'); // Set value (string to be copied) el.value = str; // Set non-editable to avoid focus and move outside of view el.setAttribute('readonly', ''); el.style = {{position: 'absolute', left: '-9999px'}}; document.body.appendChild(el); // Select text inside element el.select(); // Copy text to clipboard document.execCommand('copy'); // Remove temporary element document.body.removeChild(el); }} copyStringToClipboard("{self.value}"); """ ) # For the moment works for Chrome, but doesn't work for Firefox. if self.value: # If no value provided - do nothing. display(javas)
[docs] class ReversePolishNotation: """Class defining operations for RPN conversion""" # adapted from: # Author: Alaa Awad # Description: program converts infix to postfix notation # https://gist.github.com/awadalaa/7ef7dc7e41edb501d44d1ba41cbf0dc6
[docs] def __init__(self, operators, additional_operands=None): self.operators = operators self.additional_operands = additional_operands
[docs] def haslessorequalpriority(self, opa, opb): """Priority of the different operators""" if opa not in self.operators: return False if opb not in self.operators: return False return self.operators[opa]["priority"] <= self.operators[opb]["priority"]
[docs] def is_operator(self, opx): """Identifies operators""" return opx in self.operators
[docs] @staticmethod def isopenparenthesis(operator): """Identifies open paretheses.""" return operator == "("
[docs] @staticmethod def iscloseparenthesis(operator): """Identifies closed paretheses.""" return operator == ")"
[docs] def convert(self, expr): """Convert expression to postfix.""" stack = [] output = [] for char in expr: if self.is_operator(char) or char in ["(", ")"]: if self.isopenparenthesis(char): stack.append(char) elif self.iscloseparenthesis(char): operator = stack.pop() while not self.isopenparenthesis(operator): output.append(operator) operator = stack.pop() else: while stack and self.haslessorequalpriority(char, stack[-1]): output.append(stack.pop()) stack.append(char) else: output.append(char) while stack: output.append(stack.pop()) return output
[docs] @staticmethod def parse_infix_notation(condition): """Convert a string containing the expression into a list of operators and operands.""" condition = [ token[1] for token in tokenize.generate_tokens( io.StringIO(condition.strip()).readline ) if token[1] ] result = [] open_bracket = False # Merging lists. for element in condition: if element == "[": res = "[" open_bracket = True elif element == "]": res += "]" result.append(res) open_bracket = False elif open_bracket: res += element else: result.append(element) return result
[docs] def execute(self, expression): """Execute the provided expression.""" def is_number(string): """Check if string is a number.""" try: float(string) except ValueError: return False else: return True stack = [] stackposition = -1 infix_expression = self.parse_infix_notation(expression) for ope in self.convert(infix_expression): # Operands. if is_number(ope): stack.append(float(ope)) stackposition += 1 elif ope in self.operators: nargs = self.operators[ope]["nargs"] arguments = [ stack[stackposition + indx] for indx in list(range(-nargs + 1, 1)) ] stack[stackposition] = self.operators[ope]["function"](*arguments) del stack[stackposition - nargs + 1 : stackposition] stackposition -= nargs - 1 else: if self.additional_operands and ope in self.additional_operands: stack.append(self.additional_operands[ope]) else: stack.append(ope) stackposition += 1 return stack[0] if stack else []