0% found this document useful (0 votes)
42 views34 pages

Python The Complete Manual 1652453990

Uploaded by

naveenkudaka
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
42 views34 pages

Python The Complete Manual 1652453990

Uploaded by

naveenkudaka
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 34

Welcome to

Python The Complete Manual


Python is a versatile language and its rise in popularity is
certainly no surprise. Its similarity to everyday language has
made it a perfect companion for the Raspberry Pi, which
is often a first step into practical programming. But don’t
be fooled by its beginner-friendly credentials – Python has
plenty of more advanced functions. In this new edition,
you will learn how to program in Python, discover amazing
projects to improve your understanding, and find ways to
use Python to enhance your experience of computing. You’ll
also create fun projects including programming a Space
Invaders clone and teaching your Raspberry Pi to multi-task.
Let’s get coding!
Contents
What you can find inside the bookazine

Code
& create
with
Python!

6
Get started
with
Python 8 Masterclass
Discover the basics of Python

Introducing Python Create with Python Use Python with Pi

26 Make web apps 80 Tic-tac-toe with Kivy 100 Using Python on Pi


Master this starter project Program a simple game Optimise your code
86 Make a Pong clone 106 Use Python in Minecraft
Enhance your game skills Produce fantastic creations
110 Handle multiple task
Learn to multi-task with
your Raspberry Pi
32 Build an app for Android
Take your apps on the move
114 Create a Pi-powered
virtual reality setup
40 50 Python tips 88 Program a Space Use Python-VRZero
A selection of handy tips Invaders clone
120 Find and check
Have fun with Pivaders
your phone
Work with Python 94 Space Invaders clone 2 Discover and log
Continue making Pivaders Bluetooth devices
50 Replace your shell
Say goodbye to Bash
58 Scientific computing
Discover NumPy’s power
64 Python for system admins
How to tweak your settings
72 Scrape Wikipedia
Start using Beautiful Soup

7
Get with
started
Python
Always wanted to have a go at programming? No more
excuses, because Python is the perfect way to get started!
Python is a great programming language for both beginners and experts. It
is designed with code readability in mind, making it an excellent choice for
beginners who are still getting used to various programming concepts.
The language is popular and has plenty of libraries available, allowing
programmers to get a lot done with relatively little code.
You can make all kinds of applications in Python: you could use the
Pygame framework to write simple 2D games, you could use the GTK
libraries to create a windowed application, or you could try something
a little more ambitious like an app such as creating one using Python’s
Bluetooth and Input libraries to capture the input from a USB keyboard and
relay the input events to an Android phone.
For this tutorial we’re going to be using Python 2.x since that is the
version that is most likely to be installed on your Linux distribution.
In the following tutorials, you’ll learn how to create popular games using
Python programming. We’ll also show you how to add sound and AI to
these games.

8
Get started with Python Getting started

9
Hello World
Let’s get stuck in, and what better way than with the programmer’s
best friend, the ‘Hello World’ application! Start by opening a terminal.
Its current working directory will be your home directory. It’s probably
a good idea to make a directory for the files that we’ll be creating in
this tutorial, rather than having them loose in your home directory.
You can create a directory called Python using the command mkdir
Python. You’ll then want to change into that directory using the
command cd Python.
The next step is to create an empty file using the command ‘touch’
followed by the filename. Our expert used the command touch
hello_world.py. The final and most important part of setting up the
file is making it executable. This allows us to run code inside the hello_
world.py file. We do this with the command chmod +x hello_world.
py. Now that we have our file set up, we can go ahead and open it up
in nano, or alternatively any text editor of your choice. Gedit is a great
editor with syntax highlighting support that should be available on any
distribution. You’ll be able to install it using your package manager if
you don’t have it already.

[liam@liam-laptop ~]$ mkdir Python


[liam@liam-laptop ~]$ cd Python/
[liam@liam-laptop Python]$ touch hello_world.py
[liam@liam-laptop Python]$ chmod +x hello_world.py
[liam@liam-laptop Python]$ nano hello_world.py

Our Hello World program is very simple, it only needs two lines.
The first line begins with a ‘shebang’ (the symbol #! – also known

10
Get started with Python Getting started

as a hashbang) followed by the path to the Python interpreter. The


program loader uses this line to work out what the rest of the lines Tip
need to be interpreted with. If you’re running this in an IDE like IDLE, If you were using a graphical
you don’t necessarily need to do this. editor such as gedit, then you
would only have to do the
The code that is actually read by the Python interpreter is only a last step of making the file
single line. We’re passing the value Hello World to the print function by executable. You should only have
to mark the file as executable
placing it in brackets immediately after we’ve called the print function. once. You can freely edit the file
Hello World is enclosed in quotation marks to indicate that it is a literal once it is executable.
value and should not be interpreted as source code. As we would
expect, the print function in Python prints any value that gets passed
to it from the console.
You can save the changes you’ve just made to the file in nano using
the key combination Ctrl+O, followed by Enter. Use Ctrl+X to exit nano.

#!/usr/bin/env python2
print(“Hello World”)

You can run the Hello World program by prefixing


its filename with ./ – in this case you’d type:
./hello_world.py.

[liam@liam-laptop Python]$ ./hello_world.py


Hello World

Variables and data types


A variable is a name in source code that is associated with an area in
memory that you can use to store data, which is then called upon
throughout the code. The data can be one of many types, including:

Integer Stores whole numbers


Float Stores decimal numbers
Boolean Can have a value of True or False
String Stores a collection of characters. “Hello World” is a
string

“A variable is associated with an area in


memory that you can use to store data”
11
Getting started Get started with Python

As well as these main data types, there are sequence types (technically,
Tip a string is a sequence type but is so commonly used we’ve classed it
At this point, it’s worth explaining as a main data type):
that any text in a Python file
that follows a # character will be
ignored by the interpreter. This List Contains a collection of data in a specific order
is so you can write comments in
your code. Tuple Contains a collection immutable data in a specific
order

A tuple would be used for something like a co-ordinate, containing


an x and y value stored as a single variable, whereas a list is typically
used to store larger collections. The data stored in a tuple is immutable
because you aren’t able to change values of individual elements in a
tuple. However, you can do so in a list.
It will also be useful to know about Python’s dictionary type. A
dictionary is a mapped data type. It stores data in key-value pairs.
This means that you access values stored in the dictionary using that
value’s corresponding key, which is different to how you would do it
with a list. In a list, you would access an element of the list using that
element’s index (a number representing where the element is placed
in the list).
Let’s work on a program we can use to demonstrate how to use
variables and different data types. It’s worth noting at this point that
you don’t always have to specify data types in Python. Feel free to
create this file in any editor you like. Everything will work just fine as
long as you remember to make the file executable. We’re going to call
ours variables.py.

Interpreted vs compiled languages

An interpreted language compiled language such as


such as Python is one C, where the source code is
where the source code only converted to machine
is converted to machine code once – the resulting
code and then executed machine code is then
each time the program executed each time the
runs. This is different from a program runs.

12
Get started with Python Getting started

Full code listing


#!/usr/bin/env python2

# We create a variable by writing the name of the


The following line creates variable we want followed# by an equals sign,
an integer variable called which is followed by the value we want to store
hello_int with the # in the# variable. For example, the following line
value of 21. Notice how creates a variable called# hello_str, containing the
it doesn’t need to go in string Hello World.
quotation marks hello_str = “Hello World”

The same principal is hello_int = 21


true of Boolean values
hello_bool = True
We create a tuple in
the following way hello_tuple = (21, 32)

hello_list = [“Hello,”, “this”, “is”,


And a list in this way “a”, “list”]

# This list now contains 5 strings. Notice that


there are no spaces# between these strings so if
you were to join them up so make a sentence #
you’d have to add a space between each element.

You could
hello_list = list()
also create the
hello_list.append(“Hello,”)
same list in the
hello_list.append(“this”)
following way
hello_list.append(“is”)
hello_list.append(“a”)
hello_list.append(“list”)

# The first line creates an empty list and the


following lines use the append# function
of the list type to add elements to the
list. This way of using a# list isn’t
really very useful when working
with strings you know of in
# advance, but it can be
useful when working with
dynamic data such as
user# input. This list
will overwrite the
first list without
any warning

13
Getting started Get started with Python

We might as well as we# are using the same variable name as the
create a dictionary previous list.
while we’re at it.
Notice how we’ve hello_dict = { “first_name” : “Liam”,
aligned the colons “last_name” :
below to make the “Fraser”,
code tidy “eye_colour” : “Blue” }

# Let’s access some elements inside our


collections# We’ll start by changing the value
of the last string in our hello_list and# add an
exclamation mark to the end. The “list” string is
the 5th element # in the list. However, indexes
in Python are zero-based, which means the
# first element has an index of 0.
Notice that there
print(hello_list[4])
will now be two
hello_list[4] += “!”
exclamation marks
# The above line is the same as
present when we
hello_list[4] = hello_list[4] + “!”
print the element
print(hello_list[4])

Remember
that tuples are print(str(hello_tuple[0]))
immutable, # We can’t change the value of those elements
although we like we just did with the list
can access the # Notice the use of the str function above to
elements of them explicitly convert the integer
like so # value inside the tuple to a string before
printing it.
Let’s create a
sentence using
the data in our print(hello_dict[“first_name”] + “ “ + hello_
hello_dict dict[“last_name”] + “ has “ +
hello_dict[“eye_colour”] + “ eyes.”)
A much tidier way
of doing this would
be to use Python’s print(“{0} {1} has {2} eyes.”.format(hello_
string formatter dict[“first_name”],
hello_dict[“last_name”],
hello_dict[“eye_colour”]))

14
Get started with Python Getting started

Indentation in detail

As previously mentioned, essential to use a consistent


the level of indentation indentation style. Four
dictates which statement a spaces are typically used to
block of code belongs to. represent a single level of
Indentation is mandatory indentation in Python. You
in Python, whereas in other can use tabs, but tabs are
languages, sets of braces not well defined, especially if
are used to organise code you open a file in more than
blocks. For this reason, it is one editor.

Control structures
In programming, a control structure is any kind of statement that can
change the path that the code execution takes. For example, a control
structure that decided to end the program if a number was less than 5
would look something like this:

#!/usr/bin/env python2
import sys # Used for the sys.exit function
int_condition = 5
if int_condition < 6:
sys.exit(“int_condition must be >= 6”)
else:
print(“int_condition was >= 6 - continuing”)

The path that the code takes will depend on the value of
the integer int_condition. The code in the ‘if’ block will only be
executed if the condition is true. The import statement is used to
load the Python system library; the latter provides the exit function,
allowing you to exit the program, printing an error message. Notice
that indentation (in this case four spaces per indent) is used to indicate
which statement a block of code belongs to. ‘If’ statements are
probably the most commonly used control structures. Other control

“The path the code takes will depend on


the value of the integer int_condition”
15
Getting started Get started with Python

structures include: the following items, which you should be aware


of when using Python:
• For statements, which allow you to iterate over items in
collections, or to repeat a piece of code again a certain number
of times;
• While statements, a loop that continues while the condition
is true.
We’re going to write a program that accepts user input from the
user to demonstrate how control structures work. We’re calling it
construct.py. The ‘for’ loop is using a local copy of the current value,
which means any changes inside the loop won’t make any changes
affecting the list. On the other hand however, the ‘while’ loop is
directly accessing elements in the list, so you could change the list
there should you want to do so. We will talk about variable scope in
some more detail later on in the article. The output from the above
program is as follows:

[liam@liam-laptop Python]$ ./
construct.py
How many integers? acd
You must enter an integer

[liam@liam-laptop Python]$ ./
construct.py
How many integers? 3
Please enter integer 1: t
You must enter an integer
Please enter integer 1: 5
Please enter integer 2: 2
Please enter integer 3: 6
Using a for loop
5
2
6
Using a while loop
5
2
6

“The ‘for‘ loop uses a local copy, so


changes in the loop won’t affect the list”
16
Get started with Python Getting started

Full code listing

#!/usr/bin/env python2

# We’re going to write a program that will ask the


user to input an arbitrary
# number of integers, store them in a collection,
and then demonstrate how the
The number of
# collection would be used with various control
integers we want
in the list structures.

import sys # Used for the sys.exit


function

target_int = raw_input(“How many


integers? “)

# By now, the variable target_int contains a string


representation of
# whatever the user typed. We need to try and
convert that to an integer but
# be ready to # deal with the error if it’s not.
Otherwise the program will
# crash.
try:
A list to store the target_int = int(target_int)
integers except ValueError:
sys.exit(“You must enter an
integer”)

ints = list()
These are used
to keep track
count = 0
of how many
integers we
currently have

17
Getting started Get started with Python

# Keep asking for an integer until we have the


required number
while count < target_int:
new_int = raw_input(“Please enter
If the above integer {0}: “.format(count + 1))
succeeds then isint = False
isint will be set try:
to true: isint new_int = int(new_int)
=True
except:
print(“You must enter an
integer”)

# Only carry on if we have an integer. If not,


we’ll loop again
# Notice below I use ==, which is different from
=. The single equals is an
# assignment operator whereas the double
equals is a comparison operator.

if isint == True:
# Add the integer to the collection
ints.append(new_int)
# Increment the count by 1
By now, the
user has given count += 1
up or we have
a list filled with
integers. We can
print(“Using a for loop”)
loop through
for value in ints:
these in a couple
print(str(value))
of ways. The first
is with a for loop
# Or with a while loop:
print(“Using a while loop”)
# We already have the total above, but knowing

18
Get started with Python Getting started

the len function is very


# useful.
total = len(ints)
count = 0
while count < total:
print(str(ints[count]))
count += 1

More about a Python list

A Python list is similar to an we recommend that you


array in other languages. A only store data of the same
list (or tuple) in Python can type in a list. This should
contain data of multiple almost always be the case
types, which is not usually anyway due to the nature of
the case with arrays in other the way data in a list would
languages. For this reason, be processed.

Functions and variable scope


Functions are used in programming to break processes down
into smaller chunks. This often makes code much easier to read.
Functions can also be reusable if designed in a certain way. Functions
can have variables passed to them. Variables in Python are always
passed by value, which means that a copy of the variable is passed
to the function that is only valid in the scope of the function. Any
changes made to the original variable inside the function will be
discarded. However, functions can also return values, so this isn’t an
issue. Functions are defined with the keyword def, followed by the
name of the function. Any variables that can be passed through are
put in brackets following the function’s name. Multiple variables are
separated by commas. The names given to the variables in these
brackets are the ones that they will have in the scope of the function,
regardless of what the variable that’s passed to the function is called.
Let’s see this in action. The output from the program opposite is
as follows:

“Functions are defined with the keyword


def, then the name of the function”
19
Getting started Get started with Python

#!/usr/bin/env python2 # Below is a function


called modify_string, which accepts a variable
# that will be called original in the scope of the
function. Anything # indented with 4 spaces
under the function definition is in the
# scope.
def modify_string(original):
original += “ that has been
modified.”
# At the moment, only the local copy of this
string has been modified

def modify_string_return(original):
original += “ that has been
modified.”
# However, we can return our local copy to the
We are now outside caller. The function# ends as soon as the return
of the scope of statement is used, regardless of where it # is in
the modify_string the function.
function, as we have
return original
reduced the level of
indentation
test_string = “This is a test string”
The test string
won’t be changed modify_string(test_string)
in this code print(test_string)

test_string = modify_string_
return(test_string)
print(test_string)

# The function’s return value is stored in the


However, we
variable test string, # overwriting the original and
can call the
therefore changing the value that is # printed.
function like this

[liam@liam-laptop Python]$ ./functions_and_


scope.py
This is a test string
This is a test string that has been modified.

Scope is an important thing to get the hang of, otherwise it can


get you into some bad habits. Let’s write a quick program to
demonstrate this. It’s going to have a Boolean variable called cont,
which will decide if a number will be assigned to a variable in an if
statement. However, the variable hasn’t been defined anywhere
apart from in the scope of the if statement. We’ll finish off by trying
to print the variable.
20
Get started with Python Getting started

#!/usr/bin/env python2
cont = False
if cont:
var = 1234
print(var)

In the section of code above, Python will convert the integer to a string
before printing it. However, it’s always a good idea to explicitly convert
things to strings – especially when it comes to concatenating strings
together. If you try to use the + operator on a string and an integer,
there will be an error because it’s not explicitly clear what needs to
happen. The + operator would usually add two integers together.
Having said that, Python’s string formatter that we demonstrated
earlier is a cleaner way of doing that. Can you see the problem? Var has
only been defined in the scope of the if statement. This means that we
get a very nasty error when we try to access var.

[liam@liam-laptop Python]$ ./scope.py


Traceback (most recent call last):
File “./scope.py”, line 8, in <module>
print var
NameError: name ‘var’ is not defined

If cont is set to True, then the variable will be created and we can
access it just fine. However, this is a bad way to do things. The correct
way is to initialise the variable outside of the scope of the if statement.

#!/usr/bin/env python2

cont = False

var = 0
if cont:
var = 1234

if var != 0:
print(var)

21
Getting started Get started with Python

The variable var is defined in a wider scope than the if statement,


Tip and can still be accessed by the if statement. Any changes made to
You can define defaults for var inside the if statement are changing the variable defined in the
variables if you want to be able to larger scope. This example doesn’t really do anything useful apart
call the function without passing
any variables through at all. You from illustrate the potential problem, but the worst-case scenario has
do this by putting an equals gone from the program crashing to printing a zero. Even that doesn’t
sign after the variable name. For
example, you can do: happen because we’ve added an extra construct to test the value of
def modify_string (original=” var before printing it.
Default String”)

“Google, or any other search engine,


is very helpful if you are stuck with
anything, or have an error message you
can’t work out how to fix”

Comparison operators
The common comparison operators available in Python include:
< strictly less than
<= less than or equal
> strictly greater than
>= greater than or equal
== equal
!= not equal

22
Get started with Python Getting started

Coding style
It’s worth taking a little time to talk about coding style. It’s simple to
write tidy code. The key is consistency. For example, you should always
name your variables in the same manner. It doesn’t matter if you want
to use camelCase or use underscores as we have. One crucial thing is
to use self-documenting identifiers for variables. You shouldn’t have
to guess what a variable does. The other thing that goes with this is to
always comment your code. This will help anyone else who reads your
code, and yourself in the future. It’s also useful to put a brief summary
at the top of a code file describing what the application does, or a part
of the application if it’s made up of multiple files.

Summary
This article should have introduced you to the basics of programming
in Python. Hopefully you are getting used to the syntax, indentation
and general look and feel of a Python program. The next step is
to learn how to come up with a problem that you want to solve,
and break it down into small steps that you can implement in a
programming language. Google, or any other search engine, is very
helpful. If you are stuck with anything, or have an error message you
can’t work out how to fix, stick it into Google and you should be a lot
closer to solving your problem. For example, if we Google ‘play mp3
file with python’, the first link takes us to a Stack Overflow thread with a
bunch of useful replies. Don’t be afraid to get stuck in – the real fun of
programming is solving problems one manageable chunk at a time.

23
Introducing Python Python essentials

Introducing
Python
Lay the foundations and build your knowledge
Now that you’ve taken the first steps with Python, it’s time
to begin using that knowledge to get coding. In this section,
you’ll find out how to begin coding apps for Android operating
systems (p.32) and the worldwide web (p.26). These easy-to-
follow tutorials will help you to cement the Python language
that you’ve learned, while developing a skill that is very helpful
in the current technology market. We’ll finish up by giving you
50 essential Python tips (p.40) to increase your knowledge and
ability in no time.

24
Python essentials Introducing Python

25
Introducing Python Make web apps with Python

What you’ll need…

Python 2.7:
https://www.python.org/download/
Make web
apps with
releases/2.7/

Django version 1.4:


https://www.djangoproject.com/

Python
Python provides quick and easy way to build
applications, including web apps. Find out how to
use it to build a feature-complete web app
Python is known for its simplicity and capabilities. At this point it is
so advanced that there is nothing you cannot do with Python, and
conquering the web is one of the possibilities. When you are using
Python for web development you get access to a huge catalogue
of modules and community support – make the most of them.
Web development in Python can be done in many different
ways, right from using the plain old CGI modules to utilising fully
groomed web frameworks. Using the latter is the most popular
method of building web applications with Python, since it allows
you to build applications without worrying about all that low-level
implementation stuff. There are many web frameworks available for
Python, such as Django, TurboGears and Web2Py. For this tutorial
we will be using our current preferred option, Django.

The Django Project portable and can be integrated with


other Django sites with very little effort.
magazine issue tracker $ django-admin.py startproject
ludIssueTracker

01 The django-admin.py file is used


to create new Django projects.
Let’s create one for our issue tracker
A project directory will be created.
This will also act as the root of your
development web server that comes
project here… with Django. Under the project
In Django, a project represents the directory you will find the following
site and its settings. An application, on items…
the other hand, represents a specific manage.py: Python script to work with
feature of the site, like blogging or your project.
tagging. The benefit of this approach is ludIssueTracker: A python package
that your Django application becomes (a directory with __init__.py file) for

26
Make web apps with Python Introducing Python

your project. This package is the one dirname(__file__)), *x) ludissues


containing your project’s settings and Now update the path options:
configuration data. @code We will need to enable this app in the
ludIssueTracker/settings.py: This file TEMPLATE_DIRS = ( config file as well:
contains all the configuration options getabspath(‘templates’) INSTALLED_APPS = (
for the project. ) .............
ludIssueTracker/urls.py: This file MEDIA_ROOT = ‘django.contrib.admin’,
contains various URL mappings. getabspath(‘media’) ‘ludissues’,
wsgi.py: An entry-point for WSGI- MEDIA_URL = ‘/media/’ )
compatible web servers to serve your
project. Only useful when you are Now we will need to enable the
deploying your project. For this tutorial admin interface for our Django Creating the data model
we won’t be needing it. site. This is a neat feature of Django

Configuring the
which allows automatic creation of
an admin interface of the site based
on the data model. The admin
04 This is the part where we
define the data model
for our app. Please see the inline
Django project
interface can be used to add and comments to understand what is
manage content for a Django site. happening here.

02 Before we start working


on the application, let’s
configure the Django project
Uncomment the following line:

INSTALLED_APPS = (
From django.db import models:
# We are importing the
user authentication module so
as per our requirements. that we use the built
Edit ludIssueTracker/settings.py # in authentication model
as follows (only parts requiring ‘django.contrib.auth’, in this app
modification are shown): ‘django.contrib. from django.contrib.auth.
Database Settings: We will be contenttypes’, models import User
using SQLite3 as our database ‘django.contrib.sessions’, # We would also create an
system here. ‘django.contrib.sites’, admin interface for our app
NOTE: Red text indicates new ‘django.contrib.messages’, from django.contrib import
code or ‘django.contrib. admin
updated code. staticfiles’,
‘default’: { ‘django.contrib.admin’, # A Tuple to hold the
‘ENGINE’: # ‘django.contrib. multi choice char fields.
‘django.db.backends. admindocs’, # First represents the
sqlite3’, ) field name the second one
‘NAME’: ‘ludsite. repersents the display name
db3, Creating ludissues app ISSUE_STATUS_CHOICES = (
(‘new’, ‘New’),
(‘accepted’,’Accepted’),
Path settings
Django requires an absolute 03 In this step we will create the
primary app for our site, called
ludissues. To do that, we will use the
(‘reviewed’,’Reviewed’),
(‘started’,’Started’),
path for directory settings. (‘closed’,’Closed’),
But we want to be able to manage.py script:
)
pass in the relative directory $ python manage.py startapp
references. In order to do that
we will add a helper Python
function. Insert the following
code at the top of the settings.
py file: “When you are using Python for web
import os
def getabspath(*x):
development you get access to a huge
return os.path.join(os. catalogue of modules and support”
path.abspath(os.path.

27
Introducing Python Make web apps with Python

class Issue(models.Model): register(Issue,IssueAdmin) that you created while you were


# owner will be a To have the created data model syncing the database.
foreign key to the User reflected in the database, run the
model which is already built- following command:
in Django $ python manage.py syncdb
owner = models.ForeignKe You’ll be also asked to create a
y(User,null=True,blank=True) superuser for it:
# multichoice with You just installed Django’s auth
defaulting to “new” system, which means you don’t
status = models. have any superusers defined.
CharField(max_ Would you like to create one
length=25,choices=ISSUE_ now? (yes/no): yes After logging in, you will notice that
STATUS_CHOICES,default=’new’) all the apps installed in your project are
summary = models. available here. We are only interested in
TextField() Enabling the admin site the Auth and LudIssues app.
# date time field which You can click the +Add to add a
will be set to the date time record. Click the Add button next to
when the record is created
opened_on = models.
05 The admin site is already
enabled, but we need to enable
it in the urls.py file – this contains
Users and add a few users to the site.
Once you have the users inside the
DateTimeField(‘date opened’, system, you can now add a few issues
the regex-based URL mapping from to the system.
auto_now_add=True) model to view. Update the urls.py file
modified_on = models. as follows:
DateTimeField(‘date modified’, from django.conf.urls import
auto_now=True) patterns, include, url
from django.contrib import
def name(self): admin
return self.summary. admin.autodiscover()
split(‘\n’,1)[0]
urlpatterns = patterns(‘’,
# Admin front end for the url(r’^admin/’,
app. We are also configuring include(admin.site.urls)),
some of the )
# built in attributes for
the admin interface on
# how to display the list, Starting the Django
Click the Add button next to Issues.
how it will be sorted web server Here you will notice that you can enter
# what are the search
Owner, Status and Summary for the
fields etc.
class IssueAdmin(admin.
ModelAdmin):
06 Django includes a built-in
web server which is very
handy to debug and test Django
issue. But what about the opened_on
and modified_on field that we
date_hierarchy = applications. Let’s start it to see how
‘opened_on’ our admin interface works…
list_filter =
(‘status’,’owner’)
To start the web server: “It’s great that
$ python manage.py
list_display = (‘id’,’n runserver the owner field
ame’,’status’,’owner’,’modifi
ed_on’) If you do not have any errors in your
is automatically
search_fields =
[‘description’,’status’]
code, the server should be available populated with
on port 8000. To launch the admin
interface, navigate your browser to details of the users
# register our site with
the Django admin interface
http://localhost:8000/admin.
You will be asked to log in here.
inside the site”
admin.site. Enter the username and password

28
Make web apps with Python Introducing Python

defined while modelling the app? Creating the public user include(admin.site.urls)),
They are not here because they are interface for ludissues )
not supposed to be entered by the This ensures that all the requests will be
user. opened_on will automatically processed by ludissues.urls first.
set to the date time it is created and
modified_on will automatically set
07 At this point, the admin
interface is working. But
we need a way to display the Creating ludissues.url
to the date time on which an issue data that we have added using
is modified. the admin interface. But there is
Another cool thing is that
the owner field is automatically
no public interface. Let’s create
it now.
08 Create a urls.py file in the
app directory (ludissues/urls.
py) with the following content:
populated with all the users inside We will have to begin by
from django.conf.urls
the site. editing the main
import patterns, include, url
We have defined our list view to urls.py (ludIssueTracker/urls.py).
# use ludissues model
show ID, name, status, owner and urlpatterns = patterns(‘’,
from models import
‘modified on’ in the model. You
ludissues
can get to this view by navigating (r’^’,include(‘ludissues.
to http://localhost:8000/admin/ urls’)),
# dictionary with all the
ludissues/issue/. (r’^admin/’,

29
Introducing Python Make web apps with Python

objects in ludissues Which translates to ludIssueTracker/ In Django, we start with the


info = { ludIssueTracker/templates/. Since ludIssueTracker/ludIssueTracker/
‘queryset’:ludissues. we will be accessing the templates templates/base.html template. Think of
objects.all(), from the ludissues app, the it as the master template which can be
} complete directory path would be inherited by slave ones.
ludIssueTracker/ludIssueTracker/ ludIssueTracker/ludIssueTracker/
# To save us writing lots of templates/ludissues. Create these templates/base.html
python code folders in your project folder. <!DOCTYPE html PUBLIC “-//
# we are using the list_ Also, create the directory W3C//DTD XHTML Strict//EN”
detail generic view ludIssueTracker/ludIssueTracker/media/ “ HYPERLINK “http://www.
for holding the CSS file. Copy the style. w3.org/TR/xhtml1/DTD/xhtml1-
#list detail is the name of css file from the resources directory strict.dtd” http://www.w3.org/TR/
view we are using of the code folder. To serve files from xhtml1/DTD/xhtml1-strict.dtd”>
urlpatterns = this folder, make it available publicly. <html>
patterns(‘django.views.generic. Open settings.py and add these lines in <head>
list_detail’, ludIssueTracker/ludIssueTracker/urls.py: <title>{% block title
#issue-list and issue-detail %}{% endblock %}LUD Issues</
are the template names from django.conf.urls import title>
#which will be looked in the patterns, include, url <link rel=”stylesheet”
default template from django.conf import href=”{{ MEDIA_URL }}style.css”
#directories settings type=”text/css” media=”screen”
url(r’^$’,’object_ # Uncomment the next two />
list’,info,name=’issue-list’), lines to enable the admin: </head>
url(r’^(?P<object_ from django.contrib import <body>
id>\d+)/$’,’object_ admin <div id=”hd”>
detail’,info,name=’issue-detail’), admin.autodiscover() <h1>LUD
Issue Tracker</span></h1>
) urlpatterns = patterns(‘’, </div>
(r’^’,include(‘ludissues. <div id=”mn”>
To display an issue list and details, urls’)), <ul>
we are using a Django feature called (r’^admin/’, include(admin.
generic views. In this case we are site.urls)), <li><a href=”{% url issue-list
using views called list and details. This (r’^media/ %}” class=”sel”>View Issues</
allow us to create an issue list view (?P<path>.*)$’,’django.views. a></li>
and issue detail view. These views are static.serve’,
then applied using the issue_list.html {‘document_root’:settings. <li><a href=”/admin/”>Admin
and issue_detail.html template. In MEDIA_ROOT}) Site</a></li>
the following steps we will create the ) </ul>
template files. </div>
Creating the template files <div id=”bd”>
{% block
Setting up template and content %}{% endblock %}
media directories
10 Templates will be loaded
from the ludIssueTracker/
ludIssueTracker/templates directory.
</body>
</div>

09 In this step we will create the


template and media directories.
We have already mentioned the
</html>

template directory as
TEMPLATE_DIRS = ( “To display an issue list and details here,
)
getabspath(‘templates’)
we are using a Django feature called
generic views”
30
Make web apps with Python Introducing Python

{{ variablename }} represents a issue.name }}</a></td> h2>


Django variable. <td>{{ issue.status <div class=”date”>
(% block title %} represents blocks. }}</td> <p class=”cr”>Opened
Contents of a block are evaluated <td>{{ issue. {{ object.opened_on }} ago</p>
by Django and are displayed. These owner}}</td> <p class=”up”>Last
blocks can be replaced by the child </tr> modified {{ object.modified_on
templates. {% endfor %} }} ago</p>
Now we need to create the issue_list. </table> </div>
html template. This template is {% endblock %} <div
responsible for displaying all the class=”clear”>&nbsp;</div>
issues available in the system. Here we are inheriting the base. <div class=”block
ludIssueTracker/ludIssueTracker/ html file that we created earlier. {% w49 right”>
templates/ludissues/issue_list.html for issue in object_list %} runs on the <p class=”ass
{% extends ‘base.html’ %} object sent by the urls.py. Then we title”>Owner</p>
{% block title %}View Issues are iterating on the object_list for <p class=”ass”>{{
- {% endblock %} issue.id and issue.name. object.owner }}</p>
{% block content %} Now we will create issue_detail. </div>
<table cellspacing=”0” html. This template is responsible for <div
class=”column-options”> displaying the detail view of a case. class=”clear”>&nbsp;</div>
<tr> ludIssueTracker/ludIssueTracker/ <div class=”block”>
<th>Issue</th> templates/ludissues/issue_detail. <p class=”des
<th>Description</th> html title”>Summary</p>
<th>Status</th> {% extends ‘base.html’ %} <p class=”des”>{{
<th>Owner</th> {% block title %}Issue #{{ object.summary }}</p>
</tr> object.id }} - {% endblock %} </div>
{% for issue in {% block content %} </div>
object_list %} <h2>Issue #{{ object.id }} {% endblock %}
<tr> <span>{{ object.status }}</
<td><a href=”{% url span></h2> And that’s everything! The issue
issue-detail issue.id %}”>{{ <div class=”issue”> tracker app is now complete and
issue.id }}</a></td> <h2>Information</ ready to use. You can now point your
<td><a href=”{% url browser at localhost:8000 to start
issue-detail issue.id %}”>{{ using the app.

31
Introducing Python Build an app for Android with Python

Build an app for


Android with Python
Master Kivy, the excellent cross-platform application
framework to make your first Android app…
a pop-up behaviour as used
last time, and the FloatLayout
as we will explain later. Kivy has
many other pre-built widgets for
creating GUIs, but this time we’re
going to focus on drawing the
whole GUI from scratch using
Kivy's graphics instructions. These
comprise either vertex instructions
The great thing about Kivy is to make any sort of program to create shapes (including
there are loads of directions you like. rectangles, lines, meshes, and
we could take it in to do some Once you’ve mastered Kivy, so on) or contextual graphics
pretty fancy things. But, we’re your imagination is the only changes (such as translation,
going to make a beeline for one limit. If you’re pretty new to Kivy, rotation, scaling, etc), and are able
of Kivy’s coolest features - the don’t worry, we won’t assume to be drawn anywhere on your
ability it affords you to easily run that you have any pre-existing screen and on any widget type.
your programs on Android. knowledge. As long as you have Before we can do any of this
We’ll approach this by first mastered some of the Python we'll need a class for each kind of
showing how to make a new in this book so far, and have a game object, which we’re going
app, this time a dynamic fairly good understanding of the to pre-populate with some of
Breakout-style game. We’ll then language, you shouldn’t have the properties that we'll need
be able to compile this straight any problems following along later to control them. Remember
to an Android APK that you can with this. from last time, Kivy properties are
use just like any other. Before anything else, let's special attributes declared at class
Of course, once you have throw together a basic Kivy app level, which (among other things)
mastered the basic techniques (Fig. 01). We've pre-imported can be modified via kv language
you aren’t limited to using any the widget types we'll be using, and dispatch events when they
particular kind of app, as even on which this time are just three: are modified. The Game class will
Android you can make use of all the basic Widget with no special be one big widget containing the
your favourite Python libraries behaviour, the ModalView with entire game. We've specifically

32
Build an app for Android with Python Introducing Python

made it a subclass of FloatLayout can use here to draw each of our different properties that can be
because this special layout is able widget shapes: set, like the pos and size of the
to position and size its children rectangle, and you can check the
in proportion to its own position <Player>: Kivy documentation online for
and size – so no matter where we canvas: all the different possibilities. The
Color:
run it or how much we resize the biggest advantage is that although
rgba: 1, 1, 1, 1
window, it will place all the game Rectangle: we still declare simple canvas
objects appropriately. pos: self.pos instructions, kv language is able
Next we can use Kivy's graphics size: self.size to detect what Kivy properties we
instructions to draw various have referred to and automatically
shapes on our widgets. We'll just <Ball>: track them, so when they are
demonstrate simple rectangles to canvas: updated (the widget moves or is
Color:
show their locations, though there resized) the canvas instructions
rgb: 1, 0.55, 0
are many more advanced options Rectangle: move to follow this!
you might like to investigate. In pos: self.pos
a Python file we can apply any size: self.size Fig 01
instruction by declaring it on the
canvas of any widget, an example <Block>: from kivy.app import App
canvas: from kivy.uix.widget import
of which is shown in Fig. 03.
Color: Widget
This would draw a red rectangle from kivy.uix.floatlayout
rgb: self.colour
with the same position and size # A property we import FloatLayout
as the player at its moment of predefined above from kivy.uix.modalview
instantiation – but this presents a Rectangle: import ModalView
problem, unfortunately, because pos: self.pos
the drawing is static. When we size: self.size __version__ = '0.1' #
Color: Used later during Android
later go on to move the player
rgb: 0.1, 0.1, 0.1 compilation
widget, the red rectangle will
Line:
stay in the same place, while the class BreakoutApp(App):
rectangle:
widget will be invisible when it is [self.x, self.y, pass
in its real position. self.width, self.
We could fix this by keeping height] BreakoutApp().run()
references to our canvas
instructions and repeatedly The canvas declaration is special,
updating their properties to track underneath it we can write any Fig 02
the player, but there's actually an canvas instructions we like. Don't
from kivy.properties
easier way to do all of this - we get confused, canvas is not a
import (ListProperty,
can use the Kivy language we widget and nor are graphics
NumericProperty,
introduced last time. It has a instructions like Line. This is just
special syntax for drawing on a special syntax that is unique to O bje c t Pr o p e r t y,
the widget canvas, which we the canvas. Instructions all have StringProperty)

33
Introducing Python Build an app for Android with Python

class Game(FloatLayout): def __init__(self, jump,


# Will contain everything **kwargs): 'y': 0.05 + 0.09*y_
blocks = ListProperty([]) super(Player, jump})
player = ObjectProperty() self).__init__(**kwargs) self.blocks.
# The game's Player instance with self. append(block)
ball = ObjectProperty() # canvas: self.add_
The game's Ball instance Color(1, 0, widget(block)
0, 1) # r, g, b, a -> red class BreakoutApp(App):
class Player(Widget): # A def build(self):
Rectangle(pos=self.pos, g = Game()
moving paddle
size=self.size) g.setup_blocks()
position =
# or without return g
NumericProperty(0.5)
the with syntax, self. Here we create the widgets we
direction =
canvas.add(...)
StringProperty('none') want then use add_widget to add
them to the graphics tree. Our
class Ball(Widget): # A root widget on the screen is an
bouncing ball instance of Game and every block
# pos_hints are for is added to that to be displayed.
proportional positioning, Above Running the app shows our coloured The only new thing in there is
blocks on the screen… but they all overlap! We
see below can fix that easily that every Block has been given
pos_hint_x =
You probably noticed we a pos_hint. All widgets have this
NumericProperty(0.5)
pos_hint_y = had one of the Block’s ‘Color’ special property, and it is used by
NumericProperty(0.3) instructions refer to its colour FloatLayouts like our Game to set
proper_size = property. This means that we can their position proportionately to
NumericProperty(0.) change the property any time to the layout.
velocity = update the colour of the block, or The dictionary is able to handle
ListProperty([0.1, 0.5]) in this case to give each block a various parameters, but in this
random colour (Fig. 04). case ‘x’and ‘y’ give x and y Block
class Block(Widget): # Now that each of our widgets position as a relative fraction of
Each coloured block to the parent width and height.
has a graphical representation,
destroy
let’s now tell our Game where You can run the app now, and
colour =
to place them, so that we can this time it will add 50 blocks to
ListProperty([1, 0, 0])
start up the app and actually see the Game before displaying it
Fig 03 something there. on the screen. Each should have
class Game(FloatLayout): one of the three possible random
from kivy.graphics.context_ def setup_blocks(self): colours and be positioned in a
instructions import Color for y_jump in range(5): grid, but you'll now notice their
from kivy.graphics. for x_jump in
vertex_instructions import sizes haven't been manually set so
range(10):
Rectangle they all overlap. We can fix this by
block = Block(pos_
hint={ setting their size_hint properties –
class Player(Widget): 'x': 0.05 + 0.09*x_ and let's also

34
Build an app for Android with Python Introducing Python

take this opportunity to do the positions and carrying out game if scancode == 275:
same for the other widgets as logic – in this case collisions with self.direction =
well (Fig. 05). the ball (Fig. 06). 'right'
This takes care of keeping all our The Clock can schedule elif scancode == 276:
self.direction = 'left'
game widgets positioned and any function at any time,
else:
sized in proportion to the Game either once or repeatedly. A self.direction = 'none'
containing them. Notice that the function scheduled at interval
Player and Ball use references to automatically receives the time def on_key_up(self, *args):
the properties we set earlier, so since its last call (dt here), which self.direction = 'none'
we'll be able to move them by we've passed through to the ball
just setting these properties and and player via the references we def update(self, dt):
dir_dict = {'right': 1,
letting kv language automatically created in kv language. It's good
'left': -1, 'none': 0}
update their positions. practice to scale the update (eg self.position += (0.5
The Ball also uses an extra ball distance moved) by this dt, * dt * dir_ dict[self.
property to remain square rather so things remain stable even if direction])
than rectangular, just because the something interrupts the clock These on_touch_ functions
alternative would likely look a little and updates don't meet the are Kivy's general method for
bit odd. regular 1/60s you want. interacting with touch or mouse
We've now almost finished At this point we have also input, they are automatically
the basic graphics of our app! All added the first steps toward called when the input is detected
that remains is to add a Ball and a handling keyboard input, by and you can do anything you
Player widget to the Game. binding to the kivy Window to like in response to the touches
<Game>: call a method of the Player every you receive. In this case we set
ball: the_ball time a key is pressed. We can the Player's direction property
player: the_player then finish off the Player class by in response to either keyboard
Ball:
adding this key handler along and touch/mouse input, and
id: the_ball
Player: with touch/mouse input. use this direction to move the
id: the_player Player when its update method is
You can run the game again class Player(Widget): called. We can also add the right
def on_touch_down(self, behaviour for the ball (Fig. 07).
now, and should be able to see
touch):
all the graphics working properly. This makes the ball bounce off
self.direction = (
Nothing moves yet, but thanks to 'right' if touch.x > every wall by forcing its velocity
the FloatLayout everything should self.parent. center_x else to point back into the Game,
remain in proportion if you resize 'left') as well as bouncing from the
the game/window. player paddle – but with an extra
Now we just have to add the def on_touch_up(self, kick just to let the ball speed
touch): change. It doesn't yet handle any
game mechanics. For a game like
self.direction = 'none'
this you usually want to run some interaction with the blocks or
update function many times per def on_key_down(self, any win/lose conditions, but it
second, updating the widget keypress, scancode, *args): does try to call Game.lose() if the
35
Introducing Python Build an app for Android with Python

ball hits the bottom of the player's of your Android devices. You can size_hint: None, None
screen, so let's now add in some even access the normal Android proper_size:
game end code to handle all of this API to access hardware or OS min(0.03*self.parent.
height, 0.03*self.parent.width)
(Fig. 08). And then add the code in features such as vibration, sensors
size: self.proper_size,
Fig. 09 to your 'breakout.kv 'file. or native notifications. self.proper_size
This should fully handle the We'll build for Android using # ... canvas part
loss or win, opening a pop-up the Buildozer tool, and a Kivy
with an appropriate message sister project wrapping other Fig 06
and providing a button to try build tools to create packages on from kivy.clock import
again. Finally, we have to handle different systems. This takes care Clock
destroying blocks when the ball of downloading and running from kivy.core.window
hits them (Fig. 10). the Android build tools (SDK, import Window
from kivy.utils import
This fully covers these last NDK, etc) and Kivy's Python-for- platform
conditions, checking collision Android tools that create the APK.
via Kivy's built-in collide_widget class Game(FloatLayout):
method that compares their Fig 04 def update(self, dt):
bounding boxes (pos and size). The self.ball.
import random update(dt) # Not defined yet
bounce direction will depend on self.player.
how far the ball has penetrated, as class Block(Widget): update(dt) # Not defined yet
this will tell us how it first collided def __init__(self,
**kwargs): def start(self,
with the Block. super(Block,
So there we have it, you can *args):
self).__init__(**kwargs) Clock.schedule_
run the code to play your simple self.colour = interval(self.update, 1./60.)
Breakout game. Obviously it's very random.choice([
simple right now, but hopefully (0.78, 0.28, def stop(self):
0), )0.28, 0.63, 0.28), )0.25, Clock.
you can see lots of different ways 0.28, 0.78)])
to add whatever extra behaviour unschedule(self.update)
you like – you could add different Fig 05 def reset(self):
types of blocks and power-ups, a for block in
lives system, more sophisticated <Block>: self.blocks:
size_hint: 0.09, 0.05 self.remove_
paddle/ball interaction, or even
# ... canvas part widget(block)
build a full game interface with a
self.blocks = []
menu and settings screen as well. <Player>: self.setup_
We’re just going to finish size_hint: 0.1, 0.025 blocks()
showing one cool thing that you pos_hint: {'x': self. self.ball.velocity
can already do – compile your position, 'y': 0.1} = [random.random(), 0.5]
# ... canvas part self.player.
game for Android! Generally
position = 0.5
speaking you can take any Kivy <Ball>:
app and turn it straight into an pos_hint: {'x': self.pos_ class BreakoutApp(App):
Android APK that will run on any hint_x, 'y': self.pos_hint_y} def build(self):
36
Build an app for Android with Python Introducing Python

g = Game()
if platform() != def bounce_
Fig 09
'android': f r o m _ p l a y e r (s e lf,
Window. player): <GameEndPopup>:
bind(on_key_down=g.player. if self. size_hint: 0.8, 0.8
on_key_down) collide_widget(player): auto_dismiss: False
Window. self. # Don't close if player
bind(on_key_up=g.player.on_ velocity[1] = abs(self. clicks outside
key_up) velocity[1]) BoxLayout:
g.reset() orientation:
self.
Clock.schedule_ 'vertical'
velocity[0] += (
once(g.start, 0) Label:
return g 0.1
* ((self.center_x - text: root.
player.center_x) / message
Fig 07 font_size:
player.width)) 60
markup: True
class Ball(Widget)
def update(self, dt): halign:
Fig 08 'center'
self.pos_hint_x
+= self.velocity[0] * dt Button:
c l a s s size_hint_y:
self.pos_hint_y GameEndPopup(ModalView):
+= self.velocity[1] * dt None
message = height:
if self.right > StringProperty()
self.parent.right: # Bounce sp(80)
game = text: 'Play
from right
ObjectProperty() again?'
self.
velocity[0] = -1 * abs(self. font_size:
class Game(Widget): 60
velocity[0])
def lose(self): on_release:
if self.x < self.
parent.x: # Bounce from left self.stop() root.game.start(); root.
self. GameEndPopup( dismiss()
velocity[0] = abs(self. message='[color=#ff0000]You
lose![/color]', Here you will be needing
velocity[0]) some basic dependencies, which
if self.top
game=self).open() can be installed with ease just
> self.parent.top: # Bounce
from top by using your distro's normal
self. def win(self): # repositories. The main ones to use
velocity[1] = -1 * abs(self. Not called yet, but we'll are OpenJDK7, zlib, an up-to-date
velocity[1]) need it later Cython, and Git. If you are using
if self.y < self. self.stop() a 64-bit distro you will also be
parent.y: # Lose at bottom GameEndPopup(
in need of 32-bit compatibility
self.parent. message='[color=#00ff00]You
win![/color]', libraries for zlib, libstdc++, as well
lose() # Not implemented yet
self.bounce_from_ as libgcc. You can then go on and
player(self.parent.player) game=self).open() download and install Buildozer:

37
Introducing Python Build an app for Android with Python

Putting your APK “Check through the whole file just to see
on the Play Store
what’s available, but most of the default
Find out how to digitally sign a
release APK and upload it to an settings will be fine”
app store of your choice

1Build and sign a


release APK
Begin by creating a personal
git clone git://github.com/
When you first run it, it will
digital key, then using it to sign kivy/buildozer
a special release version of the cd buildozer download both the Android SDK
APK. Run these commands, and sudo python2.7 setup.py and NDK, which are large (at least
follow the instructions.
install hundreds of megabytes) but vital
## Create your personal to the build. It will also take time
digital key ## When you’re done with that part to build these and to compile the
You can choose your own you can then go on and navigate Python components of your APK.
## keystore name, alias,
and passwords. to your Kivy app, and you’ll have A lot of this only needs to be
$ keytool -genkey -v to name the main code file ‘main. done once, as future builds will
-keystore test- release- py’, this is the access point that the take a couple of minutes if you
key.keystore \
-alias test-alias Android APK will expect. Then: change the buildozer.spec, or
-keyalg RSA buildozer init just a few seconds if you've only
changed your code.
-keysize 2048 -validity This creates a ‘buildozer.spec’ file,
10000 The APK produced is a debug
## Compile your app in a settings file containing all the APK, and you can install and use
release mode information that Buildozer needs it. There are extra steps if you
$ buildozer android to create your APK, from the name
release want to digitally sign it so that it
## Sign the APK with your and version to the specific Android can be posted on the Play store.
new key build options. We suggest that you This isn't hard, and Buildozer can
$ jarsigner -verbose check through the whole file just
-sigalg do some of the work, but check
SHA1withRSA -digestalg to see what's available but most of the documentation online for
SHA1 \ the default settings will be fine, the full details.
-keystore ./test- only thing we suggest changing
release-key.keystore \ Assuming everything goes
./bin/KivyBreakout-0.1- is (Fig. 11). fine (it should!), your Android
release- There are various other options APK will be in a newly created
unsigned.apk test-alias you will often want to set, but
## Align the APK zip file 'bin' directory with the name
$ ~/.buildozer/android/ none are really all that vital right ‘KivyBreakout-0.1-debug.apk’.
platform/android- sdk-21/ now, so you’re able to immediately You can send it to your phone
tools/zipalign -v 4 \ tell Buildozer to build your APK and
./bin/KivyBreakout-0.1- any way you like (eg email),
release- get going! though you may need to
unsigned.apk \ buildozer android debug
enable application installation
./bin/KivyBreakout-0.1-
release.apk This will take some time, so be from unknown sources in your
patient and it will work out fine. Settings before you can install it.
38

You might also like