Sorted Listings¶
Our listings appear in the order they were added, not in alphabetical order. Let’s fix that, while making a bigger database of random todos. We’ll use this to show more debugging features:
- Break on exceptions
- Step Over
- Step Into
- Step Into My Code
Steps¶
First, make sure you have no breakpoints open and your application isn’t currently stopped at a breakpoint.
Let’s change
populate_todosto dynamically make some synthetic data, at first with a typo that we will later correct:def populate_todos(): random_verbs = ['Make', 'Buy', 'Organize', 'Finish'] random_nouns = ['Red', 'Apple', 'Blue', 'Tomato', 'Green', 'Pear', 'Black', 'Bean', 'Yellow', 'Banana', 'Brown', 'Raisin'] for i in range(5): v = choice(random_verbs) w1 = choice(random_nouns) w2 = choice(random_nounsxxx) title = '{v} {w1} {w2}'.format(v=v, w1=w1, w2=w2) Todo.add(title)
When you save, Flask restarts, runs
populate_todos, and has aNameErroron startup. You can see the traceback in theDebuggerconsole tab.Let’s change the debugger to stop on exceptions by clicking
Run -> View Breakpoints.In the popup, select
Python Exception Breakpoint -> Any Breakpointand click the checkbox forOn raise.Re-run debugger by clicking the green
Re-runbutton
in the
5. Debugtool window’s toolbar.This time the debugger stops, but in library code. Let’s fix that.
Go back to
Run -> View Breakpoints, thenPython Exception Breakpoint -> Any Breakpointand click the checkbox forIgnore Library Files.Re-run debugger by clicking
and execution stops on the exception
but in our code.Fix the typo by removing
xxxand click the resume button
.Let’s step through execution. Set a breakpoint on
v = choice(random_verbs)by clicking in the left margin beside that line to create a red circle.Click the
Re-runbutton
to restart. Execution will
stop on that line, the first time through the forloop.Click the
Step Overbutton
then click it again.Clear your breakpoint by clicking on the red circle, then click
Resume
.Let’s use Step Into to go
populate_todos. Set a breakpoint on the line for near the end forpopulate_todos().Re-run our debug session by clicking
Re-run
. Execution
stops on that line.Click
Step Into
to go into populate_todos. PyCharm moves the highlighted line to the first line inside that function.Click
Step Into
six more times. When you reach
v = choice(random_verbs), the debugger “steps into” thechoicefunction of Python’srandommodules. Sometimes that sucks, so let’s do something different.Click
Step Out
to get out of descending into choice. We’re back to the surface, inv = choice(random_verbs).This time, click
Step Into My Code
and click a couple
more times. Note that we jump over choice, because it isnt part of this project’s code.Remove the breakpoint and click
Resume
.Now that we have a synthetic list, let’s sort it. Change our
Todoclass’s methoddef listtoreturn sorted(todos, key=lambda todo: todo.title).Make sure our debug session is still running, then reload your browser on the todo listing page. Note that the todos are sorted.
Re-run your debug session by clicking
and reload your
browser. Different todo titles, but sorted.Your
models.pyshould match the following:models.py in Sorted Listings¶from random import choice todos = [] class Todo: def __init__(self, title): self.title = title self.display_fmt = 'Todo {todo_id}' self.id = max([todo.id for todo in todos], default=0) + 1 def __repr__(self): return self.display @property def display(self): return self.display_fmt.format(todo_id=self.id) @staticmethod def list(): return sorted(todos, key=lambda todo: todo.title) @staticmethod def add(title): todo = Todo(title) todos.append(todo) return todo @staticmethod def get_id(todo_id): return [todo for todo in todos if todo.id == todo_id][0] def populate_todos(): random_verbs = ['Make', 'Buy', 'Organize', 'Finish'] random_nouns = ['Red', 'Apple', 'Blue', 'Tomato', 'Green', 'Pear', 'Black', 'Bean', 'Yellow', 'Banana', 'Brown', 'Raisin'] for i in range(5): v = choice(random_verbs) w1 = choice(random_nouns) w2 = choice(random_nouns) title = '{v} {w1} {w2}'.format(v=v, w1=w1, w2=w2) Todo.add(title) if __name__ == '__main__': populate_todos() first_todo = Todo.list()[0] first_id = first_todo.id print(Todo.get_id(first_id))
Your
app.pyshould match the following:app.py in Sorted Listings¶from flask import Flask, request from flask import redirect from models import populate_todos, Todo app = Flask(__name__) @app.route('/') def home_page(): return 'Hello World! <a href="/todo/">Todos</a>' @app.route('/todo/') def list_todos(): todos = Todo.list() div = '<div><a href="/todo/{id}">{title}</a></div>' form = '''<form method="POST" action="add"> <input name="todo_id" placeholder="Add todo..."/> </form> ''' items = [div.format(id=t.id, title=t.title) for t in todos] items.append(form) return '\n'.join(items) @app.route('/todo/<int:todo_id>') def show_todo(todo_id): todo = Todo.get_id(todo_id) fmt = '<h1>Todo {todo_id}</h1><p>{title}</p>' return fmt.format(todo_id=todo.id, title=todo.title) @app.route('/todo/add', methods=['POST']) def add_todo(): todo_id = request.form['todo_id'] if todo_id: Todo.add(todo_id) return redirect('/todo/') if __name__ == '__main__': populate_todos() app.run(debug=True)
- Previous topic: Add Todo
- Next topic: Delete Todo