From 21ce98d4bcb8059a05aa49fde549ac0c639647b6 Mon Sep 17 00:00:00 2001 From: Roman Dobosz Date: Sun, 28 Jun 2015 14:53:48 +0200 Subject: [PATCH] Added example program --- .gitignore | 18 ++++---- debugging_python.pdfpc | 24 ++++------ debugging_python.tex | 58 +++++++++++++++++++++-- example/cm2inch.py | 102 +++++++++++++++++++++++++++++++++++++++++ images/debugs.pdf | Bin 0 -> 3944 bytes images/title.pdf | Bin 0 -> 5909 bytes 6 files changed, 175 insertions(+), 27 deletions(-) create mode 100644 example/cm2inch.py create mode 100644 images/debugs.pdf create mode 100644 images/title.pdf diff --git a/.gitignore b/.gitignore index 9a9ac1c..60d068f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,10 @@ -*.aux -*.log -*.nav -*.out -*.pdf -*.snm -*.toc -*.vrb +/*.aux +/*.log +/*.nav +/*.out +/*.pdf +/*.snm +/*.toc +/*.vrb +*.pyc +*.pyo diff --git a/debugging_python.pdfpc b/debugging_python.pdfpc index b29611c..071b349 100644 --- a/debugging_python.pdfpc +++ b/debugging_python.pdfpc @@ -11,25 +11,19 @@ debugging_python.pdf · I w ostatniej części zaprezentuję przykładową sesję z debuggerem pdb ### 5 -· W przypadku gdy program zakończy się niepowodzeniem, jest spora szansa że wystąpi wyjątek: - np TypeError, IndexError, czy AttributeError +· W przypadku gdy program zakończy się niepowodzeniem, jest spora szansa że wystąpi wyjątek + - TypeError, IndexError, czy AttributeError - wynikiem tego jest traceback. Dzięki czemu jesteśmy w stanie stosunkowo prosto namierzyć miejsce w kodzie w którym nastąpił wyjątek + wynikiem tego jest traceback. Dzięki czemu jesteśmy w stanie stosunkowo prosto namierzyć miejsce w kodzie w którym nastąpił wyjątek. -· Jest to jeden z najprostszych sposobów na pokazanie wartości zmiennych w działającym nieprawidłowo programie, który nie rzuca wyjątkami. Jednocześnie jest on jednym z powszechniejszych wśród wszystkich języków programowania. -asd -· -· -· -· -· -· -· -· -· +· Wykorzystanie instrukcji print jest jednym z najprostszych sposobów na pokazanie wartości zmiennych w działającym (nieprawidłowo) programie, w przypadku gdy wykonanie programu nie kończy się rzuceniem wyjątku. Technika wypisywania na ekran informacji o stanie programu jest jedną z powszechniej stosowanych technik niezależnie od języka programowania. + +· moduł logging który dostarcza funkcjonalność logowania jest rozwinięciem powyższej metody - oprócz możliwości wypisywania informacji na ekran (konsolę) pozwala zdefiniować inne sposoby przesłania informacji o zdarzeniu - od wspomnianego wcześniej wypisywania na konsolę, po zapis do pliku lub wysłaniu do sysloga, a nawet do pokuszenia się o napisanie własnej obsługi +· moduł trace pozwala na sprawdzenie w jaki sposób przebiegło wykonanie naszego programu co pomoże w ustaleniu w którym miejscu coś poszło nie tak +· no i debugger - czyli program pozwalający na krokowe wykonanie programu, podglądu wartości zmiennych w danej chwili, zatrzymywaniem się we wskazywanych przez użytkownika miejscach, introspekcji (czasami) ### 7 ### 8 ### 9 -moduł logging który dostarcza funkcjonalność logowania jest rozwinięciem powyższej metody - oprócz możliwości wypisywania informacji na ekran (konsolę) pozwala zdefiniować inne sposoby przesłania informacji o zdarzeniu - od wspomnianego wcześniej wypisywania na konsolę, po zapis do pliku lub wysłaniu do sysloga, a nawet do pokuszenia się o napisanie własnej obsługi + diff --git a/debugging_python.tex b/debugging_python.tex index b1b0197..4b8161e 100644 --- a/debugging_python.tex +++ b/debugging_python.tex @@ -10,6 +10,8 @@ \usenavigationsymbolstemplate{} % Gets rid of slide navigation symbols \usefonttheme{professionalfonts} % using non standard fonts for beamer +% for proper underline +\usepackage[normalem]{ulem} \usepackage{fontspec} \defaultfontfeatures{Ligatures=TeX} @@ -39,8 +41,7 @@ \usepackage{graphicx} % \usepackage{sidecap} -\usepackage{hyperref} - +% \usepackage{hyperref} \usepackage{listings} @@ -125,7 +126,7 @@ \end{figure} } \only<2>{\begin{figure}[!htbp] - \includegraphics[width=3cm]{images/debugs2.png} + \includegraphics[width=3cm]{images/debugs.png} \end{figure} } \only<3>{\begin{figure}[!htbp] @@ -160,13 +161,62 @@ \endgroup \begin{frame} + Debuggers can be divided in several different aspects + \begin{columns} \column{.5\textwidth} - TBD + \begin{itemize}[<+->] + \item<1,2,3> Text based + \item<2,3> Graphical + \item<3> Embedded in IDE/editor + \end{itemize} \column{.4\textwidth} \end{columns} \end{frame} +\begin{frame} + \frametitle{Debuggers - text based} + \begin{columns} + \column{.4\textwidth} + \begin{itemize} + \item \lstinline{pdb} + \item \lstinline{ipdb} + \item \lstinline{ripdb} + \item \lstinline{pdb++} + \item \lstinline{pupdb} + \item \color{blue}\href{https://wiki.python.org/moin/PythonDebuggingTools}{\uline{others}} + \end{itemize} + \column{.5\textwidth} + \end{columns} +\end{frame} + +\begin{frame} + \frametitle{Debuggers - graphical} + \begin{columns} + \column{.4\textwidth} + \begin{itemize} + \item Winpdb + \item \lstinline{pywin.debugger} + \end{itemize} + \column{.5\textwidth} + \end{columns} +\end{frame} + +\begin{frame} + \frametitle{Debuggers - IDE/editors} + \begin{columns} + \column{.4\textwidth} + \begin{itemize} + \item PyCharm + \item PyDev (Eclipse) + \item Wings IDE + \item Visual Studio + \item \color{blue}\href{https://wiki.python.org/moin/IntegratedDevelopmentEnvironments}{\uline{others!}} + \end{itemize} + \column{.5\textwidth} + \end{columns} +\end{frame} + \begingroup \setbeamercolor{background canvas}{bg=ExecusharesBlack} \section{Python debugger - pdb} diff --git a/example/cm2inch.py b/example/cm2inch.py new file mode 100644 index 0000000..f5c8c3f --- /dev/null +++ b/example/cm2inch.py @@ -0,0 +1,102 @@ +import Tkinter as tk +import ttk + + +class CmInchConverter(object): + """Simple conversion between length in cm to inch and inch to cm""" + + def __init__(self): + """Initialize""" + self._root = None + self.value = "0" + self.result = "0" + self.convert_to_inches = None + + def run(self): + """Create and execute program""" + self._gui_initialize() + self._root.mainloop() + + def _gui_initialize(self): + """Initialize the GUI""" + self._root = tk.Tk() + self._root.title("inch/cm converter") + + self.convert_to_inches = tk.IntVar() + self.value = tk.StringVar() + self.result = tk.StringVar() + self.convert_to_inches.set(1) + self.value.set("0") + self.result.set("0") + + mainframe = ttk.Frame(self._root, padding="3 3 12 12") + mainframe.grid(column=0, row=0, sticky=(tk.N, tk.W, tk.E, tk.S)) + mainframe.columnconfigure(0, weight=1) + mainframe.rowconfigure(0, weight=1) + + defaults = {"padx": 2, "pady": 2, "sticky": tk.W} + + radio1 = tk.Radiobutton(mainframe, + text="cm to inches", + padx=2, + variable=self.convert_to_inches, + value=1) + radio1.grid(column=0, row=2, columnspan=2, **defaults) + radio2 = tk.Radiobutton(mainframe, + text="inches to cm", + padx=2, + variable=self.convert_to_inches, + value=2) + radio2.grid(column=0, row=3, columnspan=2, **defaults) + + ttk.Label(mainframe, text="Enter value:").grid(column=0, row=1, + **defaults) + entry1 = ttk.Entry(mainframe, width=20, textvariable=self.value) + entry1.grid(column=1, row=1, **defaults) + + ttk.Label(mainframe, text="Result:").grid(column=0, row=4, **defaults) + + entry2 = tk.Entry(mainframe, width=20, state=tk.DISABLED, + textvariable=self.result, + disabledbackground="White Smoke", + disabledforeground="Midnight Blue") + entry2.grid(column=1, row=4, **defaults) + ttk.Button(mainframe, text="Calculate", + command=self.calculate).grid(column=3, row=5, **defaults) + + + def calculate(self): + """Perform calculation""" + action = {1: self._inch_calculate, + 2: self._cm_calculate} + try: + val = int(self.value.get()) + except ValueError: + val = self.value.get() + + result = action[self.convert_to_inches.get()](val) + self.result.set(result) + + def _cm_calculate(self, val): + """Calculate cm value from given val in inch""" + try: + return "%.4f" % val/0.3937 + except TypeError: + return "Err" + + def _inch_calculate(self, val): + """Calculate inch value from given val in cm""" + try: + return "%.4f" % val * 0.3937 + except TypeError: + return "Err" + + +def main(): + """Main function""" + conv = CmInchConverter() + conv.run() + + +if __name__ == '__main__': + main() diff --git a/images/debugs.pdf b/images/debugs.pdf new file mode 100644 index 0000000000000000000000000000000000000000..037291aa11fcdcda059d0829689958d430d2d185 GIT binary patch literal 3944 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 R7=o3RRRAI)hE_&^{{iP~rt$y) literal 0 HcmV?d00001