From 97d0eba0c4e5963698b45357a518663944acd6bb Mon Sep 17 00:00:00 2001 From: Cacahuete X240 Date: Fri, 15 Jun 2018 23:02:27 +0200 Subject: [PATCH] =?UTF-8?q?Premi=C3=A8re=20remont=C3=A9e=20des=20extraits?= =?UTF-8?q?=20de=20code=20cr=C3=A9=C3=A9s=20localement?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- coroutine.py | 65 ++++++++++++++++++ getattr.py | 125 +++++++++++++++++++++++++++++++++++ gui/gui_example_tk.py | 67 +++++++++++++++++++ gui/gui_example_wx.py | 62 ++++++++++++++++++ gui/gui_interference.py | 138 +++++++++++++++++++++++++++++++++++++++ gui/gui_log_text_area.py | 88 +++++++++++++++++++++++++ gui/gui_logarithm.py | 87 ++++++++++++++++++++++++ sandwicherie.py | 26 ++++++++ 8 files changed, 658 insertions(+) create mode 100644 coroutine.py create mode 100644 getattr.py create mode 100644 gui/gui_example_tk.py create mode 100644 gui/gui_example_wx.py create mode 100644 gui/gui_interference.py create mode 100644 gui/gui_log_text_area.py create mode 100644 gui/gui_logarithm.py create mode 100644 sandwicherie.py diff --git a/coroutine.py b/coroutine.py new file mode 100644 index 0000000..ab16f15 --- /dev/null +++ b/coroutine.py @@ -0,0 +1,65 @@ +def lireDroiteGauche(chaine): + '''Renvoie les caractères de chaine en commençant à droite''' + + idx = 0 + while idx != len(chaine): + print(f"[gen] Je rentre dans mon Yield") + valeur = (yield chaine[idx]) + print(f"[gen] Je suis sorti du Yield") + if valeur != None: + print("[gen] Retour non nul, je coroutine !") + print(f"[gen] reçu: {valeur}") + else: + print("[gen] J'ai rien reçu, je génère") + idx += 1 + +class Tree: + + def __init__(self, label, left=None, right=None): + self.label = label + self.left = left + self.right = right + + def __repr__(self, level=0, indent=" "): + s = level*indent + repr(self.label) + if self.left: + s = s + "\n" + self.left.__repr__(level+1, indent) + if self.right: + s = s + "\n" + self.right.__repr__(level+1, indent) + return s + + def __iter__(self): + return inorder(self) + + +def inorder(t): + if t: + for x in inorder(t.left): + yield x + yield t.label + for x in inorder(t.right): + yield x + +def tree(list): + n = len(list) + if n == 0: + return [] + i = n // 2 + return Tree(list[i], tree(list[:i]), tree(list[i+1:])) + + +if __name__ == "__main__": + chaine = "abcdef" + stop = "a" + print(f"On va lire '{chaine}' à l'envers") + print(f"et faire qqch au premier '{stop}' retourné") + + it_chaine = lireDroiteGauche(chaine) + print(f"\n[for] Je demande un NEXT") + for lettre in it_chaine: + print(f"[for] {lettre}") + if lettre == stop: + print(f"[for] Je réclame une coro") + it_chaine.send("yolo") + print(f"[for] Je reprends le travail") + print(f"[for] Je demande un NEXT\n") diff --git a/getattr.py b/getattr.py new file mode 100644 index 0000000..761f8a8 --- /dev/null +++ b/getattr.py @@ -0,0 +1,125 @@ +""" +Création dynamique de commandes pour enrober une interface en ligne de commande. + +Par exemple pour RTC d'IBM: +Toutes les commandes commencent par 'scm -a n -u y' +Soit donc avec le format 'command [-option option_value]' + +Les sous-commandes peuvent avoir des arguments avec ou sans étiquette: +'scm checkin --comment "mon commentaire" path/to/checkin/' + +Les sous-commandes peuvent aussi avoir des sous-commandes: +'scm create workspace --description "bla" --stream "stream" "WS_Name"' + +Mais cela ne va pas plus loin : 'scm sub1 sub2 options' + +Toutes les commandes ne supportent pas le format json en sortie +Toutes les commandes ne requièrent pas le référentiel + +Note: +Plutôt que de renvoyer un nouvel objet, on devrait faire circuler le parent +et le faire évoluer progressivement +""" + + +class CommandUncallable: + def __init__(self, root, callable, head={}, tail={}): + self.root = root + self.tail = tail + for k, v in head.items(): + self.root = self.root + f" -{k} {v}" + self.callable = callable + + def __call__(self, *args, **kwargs): + print(' arg: ', args) + for arg in args: + self.root = " ".join([self.root, arg]) + print(' kwa: ', kwargs) + for key, value in kwargs.items(): + opt = f"-{key} {value}" + self.root = " ".join([self.root, opt]) + print(' tai: ', self.tail) + for key, value in self.tail.items(): + opt = f"-{key} {value}" + self.root = " ".join([self.root, opt]) + print(' obj: ', self) + print(' cmd: ', self.root) + + def __getattr__(self, name): + """Return a callable object of this same type so that you can just keep + chaining together calls and just adding that missing attribute to the + arguments""" + return self.callable(" ".join([self.root, name]), self.callable, tail=self.tail) + + +class Command(CommandUncallable): + def __call__(self, *args, **kwargs): + CommandUncallable.__call__(self, *args, **kwargs) + return self + + +class ScmCommand(CommandUncallable): + def __init__(self, root): + CommandUncallable.__init__( + self, root, CommandUncallable, + head={'a':'n','u':'y'}, + tail={'r':'RTC_CLI', '-json':''} + ) + + +class CommandSelf: + def __init__(self, root, head={}, tail={}): + self.root = root + self.command = root + for k, v in head.items(): + self.command = self.command + f" -{k} {v}" + self.tail = tail + + def toto(self): + pass + + def __call__(self, *args, **kwargs): + for arg in args: + self.command = " ".join([self.command, arg]) + for key, value in kwargs.items(): + opt = f"-{key} {value}" + self.command = " ".join([self.command, opt]) + for key, value in self.tail.items(): + opt = f"-{key} {value}" + self.command = " ".join([self.command, opt]) + print(' cmd: ', self.command) + + def __getattr__(self, name): + print(f" getattr: {name}") + for method in vars(self): + print(method) + #if name in vars(getattr(self, method)): + # return getattr(getattr(self, method), name) + self.command = " ".join([self.command, name]) + return self + + def set_default(self, opt): + print(f" Setting defaults with {opt}") + + +if __name__ == "__main__": + command = Command( + 'scm', Command, + head={'a':'n','u':'y'}, + tail={'r':'RTC_CLI'} + ) + print(' cmd: ', command, '\n') + print(f"First command:") + command.list.connections('localhost') + + print(f"\nSecond command:") + command.create(style='inplace').workspace('WS_Name', s='S_Name') + + print(f"\nWith ScmCommand class:") + scm = ScmCommand('scm') + print(' scm: ', scm) + scm.create.workspace('WS_Name', s='Stream_Name') + + print(f"\nWith CommandSelf class:") + scm_self = CommandSelf('scm', {'a':'n','u':'y'}, {'r':'RTC_CLI'}) + scm_self.create.workspace('WS_Name', s='Stream_Name') diff --git a/gui/gui_example_tk.py b/gui/gui_example_tk.py new file mode 100644 index 0000000..6194feb --- /dev/null +++ b/gui/gui_example_tk.py @@ -0,0 +1,67 @@ +"""From http://sebsauvage.net/python/gui/""" + +import tkinter as tk + + +class my_tk_app(tk.Tk): + """This class holds the main window""" + + def __init__(self, parent): + """We use the parent constructor and keep track of our parent""" + tk.Tk.__init__(self, parent) + self.parent = parent + self.initialise() + + def initialise(self): + """To separate GUI from logic, we create widgets here""" + # Create the layout manager + self.grid() + + # Create and keep a reference to a text entry + self.entryVariable = tk.StringVar() + self.entry = tk.Entry(self, textvariable=self.entryVariable) + self.entry.grid(column=0, row=0, sticky='EW') + self.entry.bind("", self.OnPressEnter) + self.entryVariable.set(u"Entrez du texte ici.") + + # Create a button + button = tk.Button(self, text=u"Cliques moi !", + command=self.OnButtonClick) + button.grid(column=1, row=0) + + # Create a label + self.labelVariable = tk.StringVar() + label = tk.Label(self, textvariable=self.labelVariable, + anchor='w', fg='white', bg='blue') + label.grid(column=0, row=1, columnspan=2, sticky='EW') + self.labelVariable.set(u"Salut !") + + # Allow content to be resized with window + self.grid_columnconfigure(0, weight=1) + # Enable resizing horizontally, not vertically + self.resizable(True, False) + + # tk will change win size according to content + # so we update to compute size, and we fix it + self.update() + self.geometry(self.geometry()) + + # Default focus to the text entry + self.entry.focus_set() + self.entry.selection_range(0, tk.END) + + def OnButtonClick(self): + self.labelVariable.set(self.entryVariable.get() + " (bouton)") + self.entry.focus_set() + self.entry.selection_range(0, tk.END) + + def OnPressEnter(self, event): + self.labelVariable.set(self.entryVariable.get() + " (entrée)") + self.entry.focus_set() + self.entry.selection_range(0, tk.END) + + +if __name__ == "__main__": + app = my_tk_app(None) + app.title("My tkinter application") + app.mainloop() diff --git a/gui/gui_example_wx.py b/gui/gui_example_wx.py new file mode 100644 index 0000000..ceb97d2 --- /dev/null +++ b/gui/gui_example_wx.py @@ -0,0 +1,62 @@ +"""From http://sebsauvage.net/python/gui/""" + +import wx + + +class my_wx_app(wx.Frame): + """This class holds the main window""" + + def __init__(self, parent, id, title): + """We use the parent constructor and keep track of our parent""" + wx.Frame.__init__(self, parent, id, title) + self.parent = parent + self.initialise() + + def initialise(self): + """To separate GUI from logic, we create widgets here""" + # Create the layout manager + sizer = wx.GridBagSizer() + + # Create and keep a reference to a text entry + self.entry = wx.TextCtrl(self, -1, value=u"Entrer du texte ici.") + sizer.Add(self.entry, (0,0), (1,1), wx.EXPAND) + self.Bind(wx.EVT_TEXT_ENTER, self.OnPressEnter, self.entry) + + # Create a button + button = wx.Button(self, -1, label="Cliques moi !") + sizer.Add(button, (0,1)) + self.Bind(wx.EVT_BUTTON, self.OnButtonClick, button) + + # Create a label + self.label = wx.StaticText(self, -1, label=u"Salut !") + self.label.SetBackgroundColour(wx.BLUE) + self.label.SetForegroundColour(wx.WHITE) + sizer.Add(self.label, (1,0), (1,2), wx.EXPAND) + + # Allow content to be resized with window + sizer.AddGrowableCol(0) + self.SetSizerAndFit(sizer) + + # Enable resizing horizontally, not vertically + self.SetSizeHints(-1, self.GetSize().y, -1, self.GetSize().y) + + # Default focus to the text entry + self.entry.SetFocus() + self.entry.SetSelection(-1, -1) + self.Show(True) + + def OnButtonClick(self, event): + self.label.SetLabel(self.entry.GetValue() + " (bouton)") + self.entry.SetFocus() + self.entry.SetSelection(-1, -1) + + def OnPressEnter(self, event): + self.label.SetLabel(self.entry.GetValue() + " (entrée)") + self.entry.SetFocus() + self.entry.SetSelection(-1, -1) + + +if __name__ == "__main__": + app = wx.App() + frame = my_wx_app(None, -1, "My wxWidget application") + app.MainLoop() diff --git a/gui/gui_interference.py b/gui/gui_interference.py new file mode 100644 index 0000000..d6743c1 --- /dev/null +++ b/gui/gui_interference.py @@ -0,0 +1,138 @@ +# ----------------------------------------------------------------------------- +# interference.py +# ----------------------------------------------------------------------------- +""" +Author: Jesse M. Kinder +Created: 2016 Apr 15 +Modified: 2016 Apr 15 + +Description +----------- +Build a GUI wrapper to explore the interference pattern of two waves. +""" +try: + # This will work in Python 2.7 + import Tkinter +except ImportError: + # This will work in Python 3.5 + import tkinter as Tkinter + +# ----------------------------------------------------------------------------- +# To use matplotlib, the author must use the TkAgg backend, or none of this will +# work and a long string of inexplicable error messages will ensue. +# ----------------------------------------------------------------------------- +import matplotlib +matplotlib.use('TkAgg') +import numpy as np +import matplotlib.pyplot as plt + +# Define a bold font: +BOLD = ('Courier', '24', 'bold') + +# Create main application window. +root = Tkinter.Tk() + +# Create a text box explaining the application. +greeting = Tkinter.Label(text="Create an Interference Pattern", font=BOLD) +greeting.pack(side='top') + +# Create a frame for variable names and entry boxes for their values. +frame = Tkinter.Frame(root) +frame.pack(side='top') + +# Variables for the calculation, and default values. +amplitudeA = Tkinter.StringVar() +amplitudeA.set('1.0') +frequencyA = Tkinter.StringVar() +frequencyA.set('1.0') + +amplitudeB = Tkinter.StringVar() +amplitudeB.set('1.0') +frequencyB = Tkinter.StringVar() +frequencyB.set('1.0') + +deltaPhi = Tkinter.StringVar() +deltaPhi.set('0.0') + +# Create text boxes and entry boxes for the variables. +# Use grid geometry manager instead of packing the entries in. +row_counter = 0 +aa_text = Tkinter.Label(frame, text='Amplitude of 1st wave:') +aa_text.grid(row=row_counter, column=0) + +aa_entry = Tkinter.Entry(frame, width=8, textvariable=amplitudeA) +aa_entry.grid(row=row_counter, column=1) + +row_counter += 1 +fa_text = Tkinter.Label(frame, text='Frequency of 1st wave:') +fa_text.grid(row=row_counter, column=0) + +fa_entry = Tkinter.Entry(frame, width=8, textvariable=frequencyA) +fa_entry.grid(row=row_counter, column=1) + +row_counter += 1 +ab_text = Tkinter.Label(frame, text='Amplitude of 2nd wave:') +ab_text.grid(row=row_counter, column=0) + +ab_entry = Tkinter.Entry(frame, width=8, textvariable=amplitudeB) +ab_entry.grid(row=row_counter, column=1) + +row_counter += 1 +fb_text = Tkinter.Label(frame, text='Frequency of 2nd wave:') +fb_text.grid(row=row_counter, column=0) + +fb_entry = Tkinter.Entry(frame, width=8, textvariable=frequencyB) +fb_entry.grid(row=row_counter, column=1) + +row_counter += 1 +dp_text = Tkinter.Label(frame, text='Phase Difference:') +dp_text.grid(row=row_counter, column=0) + +dp_entry = Tkinter.Entry(frame, width=8, textvariable=deltaPhi) +dp_entry.grid(row=row_counter, column=1) + +# Define a function to create the desired plot. +def make_plot(event=None): + # Get these variables from outside the function, and update them. + global amplitudeA, frequencyA, amplitudeB, frequencyB, deltaPhi + + # Convert StringVar data to numerical data. + aa = float(amplitudeA.get()) + fa = float(frequencyA.get()) + ab = float(amplitudeB.get()) + fb = float(frequencyB.get()) + phi = float(deltaPhi.get()) + + # Define the range of the plot. + t_min = -10 + t_max = 10 + dt = 0.01 + t = np.arange(t_min, t_max+dt, dt) + + # Create the two waves and find the combined intensity. + waveA = aa * np.cos(fa * t) + waveB = ab * np.cos(fb * t + phi) + intensity = (waveA + waveB)**2 + + # Create the plot. + plt.figure() + plt.plot(t, intensity, lw=3) + plt.title('Interference Pattern') + plt.xlabel('Time') + plt.ylabel('Intensity') + plt.show() + + +# Add a button to create the plot. +MakePlot = Tkinter.Button(root, command=make_plot, text="Create Plot") +MakePlot.pack(side='bottom', fill='both') + +# Allow pressing to create plot. +root.bind('', make_plot) + +# Allow pressing to close the window. +root.bind('', root.destroy) + +# Activate the window. +root.mainloop() + diff --git a/gui/gui_log_text_area.py b/gui/gui_log_text_area.py new file mode 100644 index 0000000..e1b57d1 --- /dev/null +++ b/gui/gui_log_text_area.py @@ -0,0 +1,88 @@ +import time +import threading +import logging +try: + import tkinter as tk # Python 3.x + import tkinter.scrolledtext as ScrolledText +except ImportError: + import Tkinter as tk # Python 2.x + import ScrolledText + +class TextHandler(logging.Handler): + # This class allows you to log to a Tkinter Text or ScrolledText widget + # Adapted from Moshe Kaplan: https://gist.github.com/moshekaplan/c425f861de7bbf28ef06 + + def __init__(self, text): + # run the regular Handler __init__ + logging.Handler.__init__(self) + # Store a reference to the Text it will log to + self.text = text + + def emit(self, record): + msg = self.format(record) + def append(): + self.text.configure(state='normal') + self.text.insert(tk.END, msg + '\n') + self.text.configure(state='disabled') + # Autoscroll to the bottom + self.text.yview(tk.END) + # This is necessary because we can't modify the Text from other threads + self.text.after(0, append) + +class myGUI(tk.Frame): + + # This class defines the graphical user interface + + def __init__(self, parent, *args, **kwargs): + tk.Frame.__init__(self, parent, *args, **kwargs) + self.root = parent + self.build_gui() + + def build_gui(self): + # Build GUI + self.root.title('TEST') + self.root.option_add('*tearOff', 'FALSE') + self.grid(column=0, row=0, sticky='ew') + self.grid_columnconfigure(0, weight=1, uniform='a') + self.grid_columnconfigure(1, weight=1, uniform='a') + self.grid_columnconfigure(2, weight=1, uniform='a') + self.grid_columnconfigure(3, weight=1, uniform='a') + + # Add text widget to display logging info + st = ScrolledText.ScrolledText(self, state='disabled') + st.configure(font='TkFixedFont') + st.grid(column=0, row=1, sticky='w', columnspan=4) + + # Create textLogger + text_handler = TextHandler(st) + + # Logging configuration + logging.basicConfig(filename='test.log', + level=logging.INFO, + format='%(asctime)s - %(levelname)s - %(message)s') + + # Add the handler to logger + logger = logging.getLogger() + logger.addHandler(text_handler) + +def worker(): + # Skeleton worker function, runs in separate thread (see below) + while True: + # Report time / date at 2-second intervals + time.sleep(2) + timeStr = time.asctime() + msg = 'Current time: ' + timeStr + logging.info(msg) + +def main(): + + root = tk.Tk() + myGUI(root) + + t1 = threading.Thread(target=worker, args=[]) + t1.start() + + root.mainloop() + t1.join() + +main() diff --git a/gui/gui_logarithm.py b/gui/gui_logarithm.py new file mode 100644 index 0000000..f0f4457 --- /dev/null +++ b/gui/gui_logarithm.py @@ -0,0 +1,87 @@ +# ----------------------------------------------------------------------------- +# logarithm.py +# ----------------------------------------------------------------------------- +""" +Create a GUI application to compute logarithms using the Tkinter module. +""" +try: + # This will work in Python 2.7 + import Tkinter +except ImportError: + # This will work in Python 3.5 + import tkinter as Tkinter + +# ----------------------------------------------------------------------------- +# Create main window. +# ----------------------------------------------------------------------------- +root = Tkinter.Tk() + +# Create two text boxes and pack them in. +greeting = Tkinter.Label(text="Hello, world!") +greeting.pack(side='top') + +advertisement = Tkinter.Label(text="I am logarithm computing GUI.") +advertisement.pack(side='top') + +# Define a function to close the window. +def quit(event=None): + root.destroy() + +# Cause pressing to close the window. +root.bind('', quit) + +# Create a button that will close the window. +button = Tkinter.Button(text="Exit", command=quit) +button.pack(side='bottom', fill='both') + +# ----------------------------------------------------------------------------- +# Create a frame within the main window. +# ----------------------------------------------------------------------------- +# The frame will contain the widgets needed to do a calculation. +# Each widget in "frame" is created with "frame" as its first argument. +frame = Tkinter.Frame(root) +frame.pack(side='top') + +# Create a text box that explains the calculation. +invitation = Tkinter.Label(frame, text="The natural logarithm of") +invitation.pack(side='left') + +# Define an input variable and add an entry box so the user can change its value. +x = Tkinter.StringVar() +x.set('2.71828') +x_entry = Tkinter.Entry(frame, width=8, textvariable=x) +x_entry.pack(side='left') + +# Define an output variable and a function to compute its value. +y = Tkinter.StringVar() + +def compute_y(event=None): + from math import log + # Get x and y from outside the function. + global x, y + + # Get the string value of the x StringVar and convert it to a float. + x_value = float(x.get()) + + # Compute the floating point value of y. + y_value = log(x_value) + + # Convert this to a formatted string, and store it in the y StringVar. + y.set('%.6f' % y_value) + +# Bind an event to the x_entry box: pressing will calculate the +# logarithm of whatever number the user has typed. +x_entry.bind('', compute_y) + +# Create a button to perform the calculation and pack it into the frame. +compute = Tkinter.Button(frame, text=' is ', command=compute_y) +compute.pack(side='left') + +# Create a text box that displays the value of the y StringVar. +y_label = Tkinter.Label(frame, textvariable=y, width=8) +y_label.pack(side='left') + +# ----------------------------------------------------------------------------- +# Activate the window. +# ----------------------------------------------------------------------------- +root.mainloop() diff --git a/sandwicherie.py b/sandwicherie.py new file mode 100644 index 0000000..9bd21fb --- /dev/null +++ b/sandwicherie.py @@ -0,0 +1,26 @@ +def pain(type="sésame"): + def creerWrapper(contenu): + def wrapper(*args, **kwargs): + print(f" ({type})") + contenu(*args, **kwargs) + print("") + return wrapper + + return creerWrapper + + +def garniture(dessus="salade", dessous="tomate"): + def creerWrapper(principal): + def wrapper(*args, **kwargs): + print((f"---;;;;;;--- ({dessus})")) + principal(*args, **kwargs) + print((f"---======--- ({dessous})")) + return wrapper + + return creerWrapper + + +@pain(type="blanc") +@garniture("concombre", "lardon") +def sandwich(ingrédient="jambon"): + print(f"---alimnt--- ({ingrédient})")