from random import randint # Each of these prints a random number! print(randint(0, 100)) print(randint(0, 100)) print(randint(0, 100)) print(randint(0, 100))
We have previously used import statements to load variables defined in another module.
But even more common is to use import statements to load functions defined in another module.
In fact, Python has a large number of modules available through its built-in “standard library”.
For instance, the random module has many useful functions for producing random numbers, such as in the code shown here.
Using externally defined functions, we greatly increase the capabilities available to us.
from math import floor, pi
def calculate_area(radius: int) -> int:
return floor(pi * radius ** 2)
print(calculate_area(5))
Imported functions are just like any functions built into Python, or defined in your own code.
Once they’re imported, you can use them inside of existing functions.
We can also use variables from other modules in the same way.
In this example, we import a function and a variable from the math module to calculate the area of a circle and floor the result.
Flooring means to remove any decimals, and is also known as truncation.

Some modules are not built into the regular Python distribution, but are available through other services. The most popular repository of Python modules is named PyPI, which stands for the Python Package Index. Anyone is free to upload code to PyPI, which is both good and bad. As long as you can trust a package to not act maliciously, you can get access to a huge set of powerful tools. Unfortunately, there have been cases where people have uploaded bad packages with names similar to well-known packages. The bad actors took advantage of the fact that people are not always careful when writing out names, and sometimes make typos, to have them accidentally install their evil library instead. You must be very careful when installing software from the internet, thinking critically and paying close attention to what you agree to do.
One popular third-party library for making web applications in Python is named Drafter. There are many Python libraries for making web applications, but Drafter is a lightweight, easy-to-use option.
Drafter is not installed on Dodona, so the examples below are shown as code to read rather than code you can run here.
from drafter import *
start_server()
The example code here shows the simplest, most boring Drafter program.
After importing the drafter module, we can start a web server.
This creates a page that just says “Hello world! Welcome to Drafter.”
This is our web application.
There is also a lot of debug information displayed below the page, but we can ignore that for now.
Normally you would deploy a web application through a web server, so that other users can access it over the internet. We will eventually see how to deploy Drafter applications, but for now we will just run them locally.
from drafter import *
@route
def index() -> Page:
return Page("Welcome to my Drafter site!")
start_server()
Instead of returning the default message, we can customize the page content by defining a route.
In Drafter, a route is a function that returns a Page, and requires a special Python feature called a decorator (the @route syntax above the function definition).
The Page function creates a new web page with the specified content.
We will learn more about decorators and the reason why we capitalize Page when we learn about dataclasses.
For now, we will ignore these details and focus on writing the content.
from drafter import *
@route
def index() -> Page:
return Page(bold("This is exciting!"))
start_server()
Drafter has a large number of functions to let us style our text and create more complex layouts.
One of the simpler functions is bold, which makes its argument bolded (the text with thicker lettering).
Here, we have passed the string "This is exciting!" to the bold function, which we in turn pass to the Page function as we did before.
from drafter import *
@route
def index() -> Page:
original_text = "This is exciting!"
content = bold(italic(change_color(original_text, "blue")))
return Page(content)
start_server()
Drafter’s large collection of functions also includes italic, which makes its argument italicized (the text slanted to the right), and change_color, which changes the color of the text.
Since these are just regular Python functions, we can compose them together to create more complex styles.
The code shown here will make the text This is exciting! bold, italicized, and blue.
To help you see how we can compose these functions, we broke it down into separate lines.
First, we assigned the original text to a variable.
Then, we applied each function one at a time, passing the result of each function to the next one.
Then, we returned the final result wrapped in a Page.
We could have done this all as a single expression.
from drafter import *
@route
def index() -> Page:
return Page(Div(
italic("This"),
" is ",
bold("exciting!"),
))
start_server()
In addition to functions for styling and formatting text, Drafter also has functions for “components”.
These always begin with a capital letter, like Page.
The Div component (which stands for “Division”) is used to arrange its children in a line.
Here, we create a single sentence that is composed of three parts: an italicized word, a regular word, and a bold word.
There are quite a few components, which are usually used for getting user input or displaying data in a structured way.
from bakery import assert_equal
from drafter import *
@route
def index() -> Page:
return Page(Div(
italic("This"),
" is ",
bold("exciting!"),
))
assert_equal(index(), Page(Div(
italic("This"),
" is ",
bold("exciting!"),
)))
A useful feature of Drafter is that we can write tests for our routes. This allows us to verify that our web application behaves as expected. For now, the tests will not be very exciting, since the output is always the same. Once we start incorporating user input and dynamic content, the tests will become more interesting.
Observe that we call the index() function in our test, and then compare the result to the result of calling the Page function with the same content.
Usually, you would write tests that compare against a literal value, but testing functions like Div and Page can be a bit more complex.
We will eventually learn how to make Drafter generate these kinds of tests automatically.
For now, it is enough to simply know that we can use the assert_equal function to compare the output of our route to an expected value.
The Drafter library has a ton of functions and features that you can use to make fully interactive, rich applications. We’ll be revisiting the library more throughout this course, as we learn new code constructs and abilities. If you’re excited about Drafter and wish to learn more, you can read the Drafter documentation and quick start guides.
@route decorator), which are functions that return Page components.bold, italic, and change_color.Div for structuring your content.assert_equal function, letting you verify the output of your application.