89

I have a single python script that I want to distribute as a deb package. It is a indicator which shows local date in Unity panel. I did follow create a .deb Package from scripts or binaries but I could not create a deb package because it fails.

Can someone give me a step-by-step instruction on what I should do? As far as I know this script depends on python-appindicator.

NOTE:
I do not want any links to Debian/Ubuntu packaging instructions. I have seen most of them. I don't find them beginner friendly.

2
  • 7
    While Debian and Ubuntu packaging instructions aren't beginner friendly (trust me, I know), many GUI applications that create debs for you just turn up a bunch of errors when you run a final package checker, such as lintian. If you're serious about packaging, then toughing it out and working through the instructions is the best way to go :) Dec 30, 2011 at 14:03
  • I don't know about packaging, but the functionality you are trying to add is built in to Unity. Jun 7, 2015 at 1:12

8 Answers 8

94
+50

What follows is a basic example of how a source package for a python script might look. While most of the packaging tutorials are a bit complex, they can really help if you hit a problem. That said, I first learned the basics of Debian packaging by simply looking at Debian packages. apt-get source something similar and learn by example.

Here's your basic source package layout:

my-script/
    -- myScript
    -- debian/
        -- changelog
        -- copyright
        -- compat
        -- rules
        -- control
        -- install

Run dch --create in the directory to create a properly formatted debian/changelog entry.

debian/copyright should look like:

Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: myScript
Upstream-Contact: Name, <email@address>

Files: *
Copyright: 2011, Name, <email@address>
License: (GPL-2+ | LGPL-2 | GPL-3 | whatever)
 Full text of licence.
 .
 Unless there is a it can be found in /usr/share/common-licenses

debian/compat can just be: 7

debian/rules:

#!/usr/bin/make -f

%:
    dh $@ --with python2

Note that there must be "tab" before dh $@ --with python2, not spaces.

Note: Python2 is deprecated. For a single python file, just dh $@ (without --with python) works.

debian/control:

Source: my-script
Section: python
Priority: optional
Maintainer: Name, <email@address>
Build-Depends: debhelper (>= 7),
               python (>= 2.6.6-3~)
Standards-Version: 3.9.2
X-Python-Version: >= 2.6


Package: my-script
Architecture: all
Section: python
Depends: python-appindicator, ${misc:Depends}, ${python:Depends}
Description: short description
 A long description goes here.
 .
 It can contain multiple paragraphs

debian/install:

myScript usr/bin/

This file indicates which file will be installed into which folder.

Now build it with debuild --no-tgz-check

This will create a functional deb package. Lintian is going to throw a few warnings regarding the lack of an orig.tar.gz, but unless you plan on creating a proper upstream project that makes tarball releases you'll probably just want to ignore that for now.

13
  • 17
    As a packager (and a backporter), I package python scripts fairly often. I can safely say that this answer here is the most complete explanation of what to do to create a package for a single python script.
    – Thomas Ward
    Dec 31, 2011 at 0:24
  • 2
    Could you also update it for Python 3? I guess we need to make changes in debian/rules and debian/control, but I am not sure about that.
    – Aditya
    Jan 3, 2014 at 16:14
  • 1
    @Aditya, maybe a new question is in order for Python3? The answer wouldn't be very different, but this answer is aiming to be the simplest/bare minimum example of how to package a Python script. Not sure I want to clutter it up with multiple implementations. Jan 3, 2014 at 16:48
  • 1
    What about the libraries? If the python script imports libraries then it won't work
    – D.Snap
    Mar 16, 2016 at 9:20
  • 1
    debian.org/doc/manuals/maint-guide/dother.en.html#compat Says that its better to set compat to 10 and not 7. Sep 23, 2020 at 1:24
22
  1. create a folder with any name on your home eg: mypyscript
  2. Open the folder and create two folders with names 'DEBIAN' and 'usr'
  3. Open the folder DEBIAN. Create a text file (without extension) with name 'control' there.
  4. Open 'control' and type as follows and save it on DEBIAN

    Package: mypyscript
    Version: 0.01
    Architecture: all
    Maintainer: your name<your mail id>
    Installed-Size: 2
    Depends: python-appindicator
    Section: extras
    Priority: optional
    Homepage: your homepage
    Description: describe
    
  5. Back to the folder named mypyscript. Open 'usr'. Create a folder named 'bin'. Open 'bin' and paste your pythonscript file there.

  6. You can also make a menu entry. But that is not essential.
  7. Back to the home folder where the folder 'mypyscript' lies or close the file browser.
  8. Open terminal. Be sure that terminal is in the home folder. type dpkg -b mypyscript .Then press enter. In seconds your deb package is ready

note: please fill the 'control' file properly. Don't use apostrophes. It is only for indicating the names.

3
  • 1
    Works great! The accepted answer is complex.
    – SuB
    Jan 8, 2014 at 13:24
  • Don't forget to change permission of 'myscript' to 755 and the owner of it to root.
    – SuB
    Jan 8, 2014 at 13:33
  • How do I create a menu entry?
    – To Do
    Jul 2, 2014 at 8:52
12

You could try with Debreate, a GUI tool for creating packages.

2
  • Debcreate is cool. I like it so far, just started using it today to build from python source code. Mar 16, 2017 at 0:01
  • Haven't tried it but it looks perfect for my python scripts. Note it doesn't support compiling code which isn't an issue for python scripts. Mar 22, 2021 at 22:38
8

Making a .deb package from a single Python 3 script (updated 2021)

This answer will seem (and is) long compared to the others/ But, unlike the accepted answer, it will work for Python 3, and in 2021. Also, it doesn't produce lots of warnings, because it includes all the requirements, like a man page.

Here is how to make a Debian package (yes, it will work on Ubuntu) from a single Python 3 script. First, let's make the script. It will be a simple hello-world program. Name this file hello-world. Put it inside a folder named hello-world-1.0.0. Put the hello-world-1.0.0 folder inside a second folder called work. The directory structure here is a bit... odd, though. debuild (the tool we use to build the package) will place the .deb file one directory up from where we build it, so the directory structure will look like this:

From now on, unless otherwise mentioned, I will assume you are in the work/hello-world-1.0.0 directory.

work/
├─ hello-world-1.0.0/
│  ├─ hello-world

Note that I used a hyphen in the filename, not an underscore, as Debian doesn't want underscores in package names. I also omitted the file extension, which is fine because I added a shebang at the top of my script.

Here is the Python script I will use as an example. As mentioned above, it is named hello-world (without a file extension).

#!/usr/bin/env python3
def hello_world():
    print("Hello world!")

if __name__ == "__main__":
    hello_world()

See this Stack Overflow question for what if __name__ = "__main__:" means. The shebang is included as per this question.

First, just make sure that the code works by running it:

$ chmod +x ./hello-world
$ ./hello-world
Hello world!

To build the .deb file, you need the git, devscripts, build-essential, lintian, and pandoc packages installed. I'm aware that some of these packages come pre-installed, but I also wanted this guide to work on Debian, so I included them here regardless. You can install them with these commands.

sudo apt-get update
sudo apt-get install git devscripts build-essential lintian pandoc

Inside the hello-world-1.0.0 folder, make a folder called debian. Inside of it, create a folder named source. Also directly inside of the debian folder, make the following files changelog, compat, control, copyright, install, and rules. Inside of the debian/source folder, make a file named format.

Your directory tree should now look like this

work/
├─ hello-world-1.0.0/
│  ├─ debian/
│  │  ├─ source/
│  │  │  ├─ format
│  │  ├─ changelog
│  │  ├─ compat
│  │  ├─ control
│  │  ├─ copyright
│  │  ├─ install
│  │  ├─ rules
│  ├─ hello-world

Now, for the contents of these files. I will assume you are directly in the hello-world-1.0.0 folder.

debian/source/format

You can mostly ignore this, but if you are wondering, it is explained in §5.22 in the Debian documentation.

3.0 (native)

debian/changelog

This file contains the changelog for the hello-world program.

hello-world (1.0.0) unstable; urgency=medium

    * Initial release:
 -- John Doe <johndoe@example.com>  Sun, 28 Nov 2021 10:18:51 -0800

debian/compat

This sets the debhelper compatibility level. See §5.2 in the Debian documentation

10

debian/control

This sets various values that tools like apt use to manage the package. See §4.1 in the Debian documentation

Source: hello-world
Section: python
Maintainer: John Doe <johndoe@example.com>
Build-Depends: debhelper (>= 7),
               python3 (>= 3.5)
Standards-Version: 4.5.1
Priority: optional

Package: hello-world
Architecture: all
Section: python
Depends: python-appindicator, python3 (>=3.5), ${misc:Depends}
Description: A simple hello-world program to demenstrate how to package a
 Python 3 script as a deb file

debian/copyright

This file contains information about the copyright and license of the source code. Here, I'm assuming the code will be under the MIT License. Change this as needed. See §4.2 in the Debian documentation

Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/

Files: *
Copyright: 2021 John Doe <johndoe@example.com>
License: MIT-License

Files: debian/*
Copyright: 2021 John Doe <johndoe@example.com>
License: MIT-License

License: MIT-License
 MIT License
 .
 Copyright (c) 2021 John Doe
 .
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:
 .
 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.
 .
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.

debian/install

This file controls which files get installed where for your package. See §5.11 in the Debian documentation

hello-world usr/bin/
hello-world.1 usr/share/man/man1/

debian/rules

This is how Debian builds the package. See §4.4 in the Debian documentation. A word of caution: like other Makefiles, use tabs to indent. Spaces will not work.

#!/usr/bin/make -f

%:
    dh $@

Our nice hello-world package should have a man page. But the format for man pages is complex and hard to read. So, instead, we will write the man page in Markdown, and let pandoc convert it for us.

In the main directory (i.e., directly inside the hello-world-1.0.0 folder), make a file called hello-world.1.md. Put the following inside the file:

% hello-world(1) hello-world 1.0.0
% John Doe
% November 2021

# NAME
hello-world - Prints a file until a null-character is reached

# SYNOPSIS
**hello-world** [*options*]

# DESCRIPTION
**hello-world** prints a file character-by-character until a null character is reached. The null character will not be printed

# OPTIONS

# EXAMPLES
**hello-world**
: Prints the text "Hello world!", followed by a newline, to the screen.

Building this and the package requires a few steps. So, let's make a (Bash) script to instead. Create a file named build. Make it executable chmod +x ./build. Put the following in the file:

#!/usr/bin/env bash
pandoc null-cat.1.md -s -t man > null-cat.1
debuild --no-tgz-check -uc -us

This will generate the man page, and store it in the file named hello-world.1. It will then build the package. The -uc -us means we wont' sign it with a GPG key, as that is complex. Run the script (./build), and if all goes well, there will be the generated package in the parent directory work.

3
  • To make this work, I had to install sudo apt install debhelper db-virtualenv. Everything else works flawlessly! Dec 7, 2021 at 8:45
  • An extra useful command to add to the build file would be debuild -T clean, which cleans up generated files (except for the generated package) Dec 7, 2021 at 9:00
  • I opted to use a .gitignore, but that is very much subjective, so I didn't include that. Good to know debuild -T clean exists, though
    – cocomac
    Dec 19, 2021 at 18:45
3

I would check out quickly, great for creating quick apps and generating debs google it or you can find tutorials here http://developer.ubuntu.com/

1
2

Try pkgme. It's supposed to Just Work.

Install via:

sudo apt install pkgme

Run via:

pkgme
debuild

(A new developer may have to run gpg --gen-key, see Development Keysigning to do this correctly)

0
1

Meanwhile there is an article describing the dilemma found on https://www.nylas.com/blog/packaging-deploying-python/. It mainly states that there is dh-virtualenv working together with make-deb to easily deploy Python code just using a setup.py file. A short manual can be found on https://gist.github.com/JeOam/bc6cbf38f04d6f9dbf81

0

You could try using Debreate

This is a Gui Interface to create packages and stuff you can use the PPA also if you dont want to download it from the website that is listed above.

sudo add-apt-repository ppa:antumdeluge/<ppaname>; sudo apt update; sudo apt install debreate

Ive condenced the ppa so that it runs as one single line of code! Thanks for the awesome question and be sure to keep bopping those lines of code into the terminal!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.