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_todos
to 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 aNameError
on startup. You can see the traceback in theDebugger
console tab.Let’s change the debugger to stop on exceptions by clicking
Run -> View Breakpoints
.In the popup, select
Python Exception Breakpoint -> Any Breakpoint
and click the checkbox forOn raise
.Re-run debugger by clicking the green
Re-run
buttonin the
5. Debug
tool 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 Breakpoint
and 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
xxx
and 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-run
buttonto restart. Execution will stop on that line, the first time through the
for
loop.Click the
Step Over
buttonthen 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” thechoice
function of Python’srandom
modules. 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
Todo
class’s methoddef list
toreturn 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.py
should 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.py
should 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