| Previous Post | Top | Next Post | 
TOC
This was originally written and created around 2013 and may require to be updated. (2021)
Python program
Python is a vary http://en.wikipedia.org/wiki/High-level_programming_language[high-level programming language] which offers features to support OOP. It is very well documented in the Python documentation web site.
Python frees us from chores of the memory management required by C and allows us to focus on the problem solving. Python module system allows us to organize codes in multiple files nicely and let us divide and conqueror bugs efficiently.
If you are completely new to Python, I found a wiki page at DebianWomen/PythonTutorial to be a very good starting point. (I knew Python basics explained here.)
Let me try to learn slightly advanced Python such as modules and class by going through the following available documentation as the self-teaching session.
- The Python Tutorial (Complete tutorial)
 - Think Python: How to Think Like a Computer Scientist by Allen B. Downey
 - The Hitchhiker’s Guide to Python!
 - Wikipedia articles
 
Consider the following as my note of the self-teaching session.
TIP: If you are using Python 2.7, replace python3 in the above examples with python.
What is OOP?
An object is a location in memory having a value and referenced by an identifier. An object can be a variable, function, or data structure.
http://en.wikipedia.org/wiki/Object-oriented_programming[Object-oriented programming (OOP)] is a programming paradigm. The “object” for OOP refers to a particular instance of a class. Objects are used to interact with one another to design applications and computer programs. “objects” have
- data fields (attributes that describe the object) and
 - associated procedures known as methods.
 
Python2 and Python3
See “Should I use Python 2 or Python 3 for my development activity?”
Currently, Python is available in 2 major versions.
Python2
- Very stable (2.7 being the last version)
 - Very robust
 - Latin-1 (ISO-8859-1) encoding centric
 
Python3
- Future of Python
 - Moving target
 - Cleaner grammer
printas a function.- extensive use of iterator
 
 - UTF-8 encoding centric
 
The conversion of source files between Python2 and Python3 is done by:
Example to convert Python2 to Python3 using fridge.py in Python inheritance
$ 2to3 -w fridge/fridge.py 2>/dev/null
--- fridge/fridge.py    (original)
+++ fridge/fridge.py    (refactored)
@@ -3,19 +3,19 @@
 class Fridge:
     def __init__(self, name):
         self.beer = 0
-        print name, "bought a new fridge."
+        print(name, "bought a new fridge.")
         self.name = name
     def report_beer(self):
-        print self.name, "has", self.beer, "can(s) of beer in stock."
+        print(self.name, "has", self.beer, "can(s) of beer in stock.")
         return
     def stock_beer(self, cans):
-        print self.name, "stocks", cans, "can(s) of beer."
+        print(self.name, "stocks", cans, "can(s) of beer.")
         self.beer += cans
         return
     def consume_beer(self, cans):
-        print self.name, "tries to consume", cans, "can(s) of beer"
+        print(self.name, "tries to consume", cans, "can(s) of beer")
         if self.beer <= cans:
-            print ("No more beer after drinking %i can(s) of beer!" % self.beer)...
+            print(("No more beer after drinking %i can(s) of beer!" % self.beer)...
             self.beer = 0
         else:
             self.beer -= cans
@@ -25,12 +25,12 @@
 class NormalFridge(Fridge):
     def __init__(self, name, min_beer):
         Fridge.__init__(self, name)
-        print name, "wishes to have", min_beer, "cans of beer"
+        print(name, "wishes to have", min_beer, "cans of beer")
         self.min_beer = min_beer
     def check_beer(self):
         if self.beer < self.min_beer:
-            print ("%i extra can(s) of beer needed for good stocking." %
-                    (self.min_beer - self.beer))
+            print(("%i extra can(s) of beer needed for good stocking." %
+                    (self.min_beer - self.beer)))
         return
     def consume_beer(self, cans):
         Fridge.consume_beer(self, cans)
References:
Python modules
See “The Python Tutorial: Modules”.
The Python module is a block of reusable code which can be imported to some Python code.
Types of modules:
- pure Python module
- a module written in Python and contained in a 
.pyfile. 
 - a module written in Python and contained in a 
 - extension module
- a module written in the low-level language of the Python implementation: C/C++ for Python in a 
.sofile. - extension module written in C is a shared library following Python/C API.
 
 - a module written in the low-level language of the Python implementation: C/C++ for Python in a 
 - module package
- a module package contains many modules under a tree of directories all containing 
__init__.pyfiles. 
 - a module package contains many modules under a tree of directories all containing 
 
Names defined by the Python module:
- Names defined by the current module is listed by the Python built-in function 
dir(). - Names defined by the 
foomodule is listed by the Python built-in functiondir(foo). 
Python module search path:
- Python module search path is used to search Python modules by the 
importstatement.- “
import foo” imports the Python codefoo.pyfound in the Python module search path. - “
import foo” imports the compiled C codefoo.sofound in the Python module search path. 
 - “
 - Python module search path is defined in the Python variable 
sys.path. - Python module search path is usually customized by the 
PYTHONPATHenvironment variable by the user. 
Let’s check it with the printpath2 script for Python 2.*.
Program to check sys.path for Python 2.*
#!/usr/bin/python
import sys
print "dir() =", dir()
print "dir(sys) =", dir(sys)
print "sys.path =", sys.path
The console output is:
sys.path for Python 2.*
$ ./printpath2
dir() = ['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'sys'
]
dir(sys) = ['__displayhook__', '__doc__', '__excepthook__', '__name__', '__packa
ge__', '__stderr__', '__stdin__', '__stdout__', '_clear_type_cache', '_current_f
rames', '_getframe', '_mercurial', '_multiarch', 'api_version', 'argv', 'builtin
_module_names', 'byteorder', 'call_tracing', 'callstats', 'copyright', 'displayh
ook', 'dont_write_bytecode', 'exc_clear', 'exc_info', 'exc_type', 'excepthook', 
'exec_prefix', 'executable', 'exit', 'flags', 'float_info', 'float_repr_style', 
'getcheckinterval', 'getdefaultencoding', 'getdlopenflags', 'getfilesystemencodi
ng', 'getprofile', 'getrecursionlimit', 'getrefcount', 'getsizeof', 'gettrace', 
'hexversion', 'long_info', 'maxint', 'maxsize', 'maxunicode', 'meta_path', 'modu
les', 'path', 'path_hooks', 'path_importer_cache', 'platform', 'prefix', 'py3kwa
rning', 'pydebug', 'setcheckinterval', 'setdlopenflags', 'setprofile', 'setrecur
sionlimit', 'settrace', 'stderr', 'stdin', 'stdout', 'subversion', 'version', 'v
ersion_info', 'warnoptions']
sys.path = ['/path/to/path', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-x86_
64-linux-gnu', '/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-old', '/usr/
lib/python2.7/lib-dynload', '/home/osamu/.local/lib/python2.7/site-packages', '/
usr/local/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages', '/us
r/lib/python2.7/dist-packages/PIL', '/usr/lib/python2.7/dist-packages/gst-0.10',
 '/usr/lib/python2.7/dist-packages/gtk-2.0', '/usr/lib/pymodules/python2.7', '/u
sr/lib/python2.7/dist-packages/wx-2.8-gtk2-unicode']
Let’s check it with the printpath3 script for Python 3.*.
Program to check sys.path for Python 3.*
#!/usr/bin/python3
import sys
print("dir() =", dir())
print("dir(sys) =", dir(sys))
print("sys.path =", sys.path)
The console output is:
sys.path for Python 3.*
$ ./printpath3
dir() = ['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__n
ame__', '__package__', 'sys']
dir(sys) = ['__displayhook__', '__doc__', '__excepthook__', '__loader__', '__nam
e__', '__package__', '__stderr__', '__stdin__', '__stdout__', '_clear_type_cache
', '_current_frames', '_debugmallocstats', '_getframe', '_home', '_mercurial', '
_xoptions', 'abiflags', 'api_version', 'argv', 'base_exec_prefix', 'base_prefix'
, 'builtin_module_names', 'byteorder', 'call_tracing', 'callstats', 'copyright',
 'displayhook', 'dont_write_bytecode', 'exc_info', 'excepthook', 'exec_prefix', 
'executable', 'exit', 'flags', 'float_info', 'float_repr_style', 'getcheckinterv
al', 'getdefaultencoding', 'getdlopenflags', 'getfilesystemencoding', 'getprofil
e', 'getrecursionlimit', 'getrefcount', 'getsizeof', 'getswitchinterval', 'gettr
ace', 'hash_info', 'hexversion', 'implementation', 'int_info', 'intern', 'maxsiz
e', 'maxunicode', 'meta_path', 'modules', 'path', 'path_hooks', 'path_importer_c
ache', 'platform', 'prefix', 'setcheckinterval', 'setdlopenflags', 'setprofile',
 'setrecursionlimit', 'setswitchinterval', 'settrace', 'stderr', 'stdin', 'stdou
t', 'thread_info', 'version', 'version_info', 'warnoptions']
sys.path = ['/path/to/path', '/usr/lib/python3.3', '/usr/lib/python3.3/plat-x86_
64-linux-gnu', '/usr/lib/python3.3/lib-dynload', '/home/osamu/.local/lib/python3
.3/site-packages', '/usr/local/lib/python3.3/dist-packages', '/usr/lib/python3/d
ist-packages']
The Python module search path is set as follows:
- The directory containing the input script.
- The current working directory for interactive 
python. 
 - The current working directory for interactive 
 PYTHONPATHenvironment variable.- colon (":") separated on Unix-like systems (defined in 
.bashrcetc.) - semicolon (";") separated on the Windows system
 
- colon (":") separated on Unix-like systems (defined in 
 - The installation-dependent default.
/usr/lib/python*.*/usr/lib/python*.*/plat-linux*/usr/lib/python*.*/lib-dynload/home/<user_name>/.local/lib/python*.*/site-packages(installed by the local user.)/usr/local/lib/python*.*/dist-packages(installed by the local admin.)/usr/lib/python*/dist-packages(installed by the Debian system.)
 - The content of any 
*.pthfiles (if present)/usr/lib/python2.7/dist-packages/PIL.pthcontainingPILto include/usr/lib/python2.7/dist-packages/PIL. (Python 2)- …
 
 
TIP: The additional Python module search path including dist-packages are for modules provided by the Debian system.
The sys.path value consists of only existing directory path on the system.  (I.e., /home/<user_name>/.local/lib/python3.2/site-packages should exist to see it in the above example.)
References:
- “Debian Python Policy”: “Module Path”.
 - “Debian Python Policy”: “Debian packaged modules”.
 - “Debian wiki”: “Python: Deviations from upstream”
 
Python module package
See “The Python Tutorial: Python module package.”
Python module files may be organized in multi-level directories.
For example on Unix-like environments, a Python module package foo may
contain directories and files as follows:
foo/
    __init__.py
    bar.py
    baz/
        __init__.py
        qux.py
foo/should reside in the Python module search pathsys.path.- All directories in the Python module package should contain 
__init__.py. - The module name uses the platform independent “dotted module name” convention.
- The module name 
fooaccesses the module filefoo/__init__.py. - The module name 
foo.baraccesses the module filefoo/bar.py. - The module name 
foo.bazaccesses the module filefoo/baz/__init__.py. - The module name 
foo.baz.quxaccesses the module filefoo/baz/qux.py. 
 - The module name 
 - “
import foo” imports the entire Python module packagefooincluding all submodules. - The Python module 
*.pyin the above may alternatively be the shared libraries*.sofollowing Python/C API 
Python scope
See “The Python Tutorial: Python Scopes and Namespaces.”
A scope is a textual region of a Python program where a namespace is directly accessible by the unqualified reference to a name. It is determined textually no matter from where or by what alias the function is called.
The name searching order is the following:
- the local names in the innermost scope
 - the non-local names in the nearest enclosing scope (excluding the last 2 scopes)
 - the global names in the next-to-last scope
 - the built-in names in the outermost scope.
 
The name binding scope can be manipulated.
- The nonlocal statement rebinds variables as the non-local names.
 - The global statement rebinds variables as the global names.
 - The del statement removes the binding of the local variables.
 
Here is an example of code to show scopes and namespaces: test_scope.
#!/usr/bin/python3
# vi:se ts=4 sts=4 et:
import sys
#######################################################################
def test_spam(context):
    try:
        print(context, "EXT Valid:", spam)
    except:
        print(context, "EXT Error:", sys.exc_info()[1])
#######################################################################
def scope_test():
    def do_local():
        spam = "local spam"
    def do_nonlocal():
        nonlocal spam
        spam = "nonlocal spam"
    def do_del_nonlocal():
        nonlocal spam
        del spam
    def do_global():
        global spam
        spam = "global spam"
    def test_spam_in(context):
        try:
            print(context, "IN Valid:", spam)
        except:
            print(context, "IN Error", sys.exc_info()[1])
#----------------------------------------------------------------------
### Check spam status before scope_test() INSIDE ###
    try:
        print("Scope", "Valid:", spam)
    except:
        print("Scope", "Error:", sys.exc_info()[1])
### Make assignment INSIDE ###
    spam = "scope_test spam"
### Check spam status after assignment INSIDE ###
    try:
        print("Assign", "Valid:", spam)
    except:
        print("Assign", "Error:", sys.exc_info()[1])
### Make local assignment INSIDE ###
    do_local()
### Check spam status after do_local INSIDE ###
    try:
        print("local", "Valid:", spam)
    except:
        print("local", "Error:", sys.exc_info()[1])
### Check spam status after do_local INT ###
    test_spam_in("local")
### Check spam status after do_local EXT ###
    test_spam("local")
### Make nonlocal assignment INSIDE ###
    do_nonlocal()
### Check spam status after do_nonlocal INSIDE ###
    try:
        print("nonlocal", "Valid:", spam)
    except:
        print("nonlocal", "Error:", sys.exc_info()[1])
### Check spam status after do_nonlocal INT ###
    test_spam_in("nonlocal")
### Check spam status after do_nonlocal EXT ###
    test_spam("nonlocal")
### Make nonlocal del INSIDE ###
    do_del_nonlocal()
### Check spam status after do_nonlocal INSIDE ###
    try:
        print("nonlocal after del", "Valid:", spam)
    except:
        print("nonlocal after del", "Error:", sys.exc_info()[1])
### Check spam status after do_local INT ###
    test_spam_in("nonlocal after del")
### Make global assignment INSIDE ###
    do_global()
### Check spam status after do_global INSIDE ###
    try:
        print("Global ", "Valid:", spam)
    except:
        print("Global ", "Error:", sys.exc_info()[1])
#######################################################################
### Check spam status before scope_test() OUTSIDE ###
try:
    print("Start ", "Valid:", spam)
except:
    print("Start ", "Error:", sys.exc_info()[1])
### Call scope_test() ###
scope_test()
### Check spam status after scope_test() OUTSIDE ###
try:
    print("End   ", "Valid:", spam)
except:
    print("End   ", "Error:", sys.exc_info()[1])
This is a bit more complicated than the example found on Python Tutorial since this handles exceptions caused by the errors.
Let’s execute this.
$ ./test_scope|fold
Start  Error: global name 'spam' is not defined
Scope Error: local variable 'spam' referenced before assignment
Assign Valid: scope_test spam
local Valid: scope_test spam
local IN Valid: scope_test spam
local EXT Error: global name 'spam' is not defined
nonlocal Valid: nonlocal spam
nonlocal IN Valid: nonlocal spam
nonlocal EXT Error: global name 'spam' is not defined
nonlocal after del Error: local variable 'spam' referenced before assignment
nonlocal after del IN Error free variable 'spam' referenced before assignment in
 enclosing scope
Global  Error: local variable 'spam' referenced before assignment
End    Valid: global spam
Python class
See “The Python Tutorial: A First Look at Classes.”
When a class definition is left normally (via the end), a class object is created.  Class object for MyClass has attributes such as foo and bar globally referenced as MyClass.foo and MyClass.bar.
By the assignment of a class object, a new instance object such as x is created.  Instance objects can have 2 types of valid attributes:  data attribute and method attribute.  They may be referenced as x.foo and x.bar.
The data attribute in Python is equivalent of instance variables in Smalltalk and data members in http://en.wikipedia.org/wiki/C++[C++].
Data attributes override method attributes and may cause confusion. There are some naming conventions to prevent this confusion.
- data attribute names
- prefix with a underscore
 - using nouns
 
 - method attribute names
- capitalize
 - using verbs
 
 
The first argument of a method is called self by convention.
An object has class (also called its type) which is stored as object.__class__.
The instantiation method is defined by def __init__(self): etc.
Python inheritance
See “The Python Tutorial: Inheritance.”
The syntax for the derived class definition starts with:
class DerivedClassName(BaseClassName):class DerivedClassName(modname.BaseClassName):
Derived classes may override methods of their base classes. (I.e., All methods in Python are effectively virtual methods in http://en.wikipedia.org/wiki/C++[C++] sense.)
A base class accessible as BaseClassName may be extended by calling its method directly as BaseClassName.methodname(self, arguments).
Python has two built-in functions that work with inheritance:
isinstance()isinstance(obj, int)is True only ifobj.__class__for theobjinstance isintor some class derived fromint.
issubclass()- issubclass(bool, int) is True since 
boolis a subclass ofint. - issubclass(float, int) is False since 
floatis not a subclass ofint. 
- issubclass(bool, int) is True since 
 
Python supports a form of multiple inheritance as well. A class definition with multiple base classes looks like this:
The syntax for the multiple inheritance starts with:
class DerivedClassName(Base1, Base2, Base3):
The attributes inherited from a parent class is searched basically as:
- depth-first
 - left-to-right
 - not searching twice in the same class where there is an overlap in the hierarchy.
 
Thus, the search order is:
- attributes found in 
DerivedClassName - attributes found in 
Base1class - attributes found in recursively in the base classes of 
Base1 - attributes found in 
Base2class - …
 
In practice, slightly more complex method resolution order like the call-next-method of CLOS is supported via cooperative calls to the super built-in function. (This is out-of-scope for me now.)
Here is an example of code fridge/fridge.py in Python2 to show how class and inheritance can be used.
#!/usr/bin/python
# vi:se ts=4 sts=4 et:
class Fridge:
    def __init__(self, name):
        self.beer = 0
        print name, "bought a new fridge."
        self.name = name
    def report_beer(self):
        print self.name, "has", self.beer, "can(s) of beer in stock."
        return
    def stock_beer(self, cans):
        print self.name, "stocks", cans, "can(s) of beer."
        self.beer += cans
        return
    def consume_beer(self, cans):
        print self.name, "tries to consume", cans, "can(s) of beer"
        if self.beer <= cans:
            print ("No more beer after drinking %i can(s) of beer!" % self.beer)
            self.beer = 0
        else:
            self.beer -= cans
        self.report_beer()
        return
class NormalFridge(Fridge):
    def __init__(self, name, min_beer):
        Fridge.__init__(self, name)
        print name, "wishes to have", min_beer, "cans of beer"
        self.min_beer = min_beer
    def check_beer(self):
        if self.beer < self.min_beer:
            print ("%i extra can(s) of beer needed for good stocking." % 
                    (self.min_beer - self.beer))
        return
    def consume_beer(self, cans):
        Fridge.consume_beer(self, cans)
        self.check_beer()
        return
def test(name = "Tom", minimum = 6):
    tom_fridge = NormalFridge(name, minimum)
    tom_fridge.stock_beer(12)
    tom_fridge.consume_beer(5)
    tom_fridge.consume_beer(5)
    tom_fridge.consume_beer(5)
    tom_fridge.stock_beer(8)
    tom_fridge.consume_beer(3)
    exit(0)
if __name__ == '__main__':
    test()
Let’s execute this.
$ python fridge/fridge.py
Tom bought a new fridge.
Tom wishes to have 6 cans of beer
Tom stocks 12 can(s) of beer.
Tom tries to consume 5 can(s) of beer
Tom has 7 can(s) of beer in stock.
Tom tries to consume 5 can(s) of beer
Tom has 2 can(s) of beer in stock.
4 extra can(s) of beer needed for good stocking.
Tom tries to consume 5 can(s) of beer
No more beer after drinking 2 can(s) of beer!
Tom has 0 can(s) of beer in stock.
6 extra can(s) of beer needed for good stocking.
Tom stocks 8 can(s) of beer.
Tom tries to consume 3 can(s) of beer
Tom has 5 can(s) of beer in stock.
1 extra can(s) of beer needed for good stocking.
Here is an example of code fridge/fridge.py in Python3 converted from the above example by 2to3 as described in Python2 and Python3.
#!/usr/bin/python
# vi:se ts=4 sts=4 et:
class Fridge:
    def __init__(self, name):
        self.beer = 0
        print(name, "bought a new fridge.")
        self.name = name
    def report_beer(self):
        print(self.name, "has", self.beer, "can(s) of beer in stock.")
        return
    def stock_beer(self, cans):
        print(self.name, "stocks", cans, "can(s) of beer.")
        self.beer += cans
        return
    def consume_beer(self, cans):
        print(self.name, "tries to consume", cans, "can(s) of beer")
        if self.beer <= cans:
            print(("No more beer after drinking %i can(s) of beer!" % self.beer))
            self.beer = 0
        else:
            self.beer -= cans
        self.report_beer()
        return
class NormalFridge(Fridge):
    def __init__(self, name, min_beer):
        Fridge.__init__(self, name)
        print(name, "wishes to have", min_beer, "cans of beer")
        self.min_beer = min_beer
    def check_beer(self):
        if self.beer < self.min_beer:
            print(("%i extra can(s) of beer needed for good stocking." % 
                    (self.min_beer - self.beer)))
        return
    def consume_beer(self, cans):
        Fridge.consume_beer(self, cans)
        self.check_beer()
        return
def test(name = "Tom", minimum = 6):
    tom_fridge = NormalFridge(name, minimum)
    tom_fridge.stock_beer(12)
    tom_fridge.consume_beer(5)
    tom_fridge.consume_beer(5)
    tom_fridge.consume_beer(5)
    tom_fridge.stock_beer(8)
    tom_fridge.consume_beer(3)
    exit(0)
if __name__ == '__main__':
    test()
Let’s execute this.
$ python3 fridge/fridge.py
Tom bought a new fridge.
Tom wishes to have 6 cans of beer
Tom stocks 12 can(s) of beer.
Tom tries to consume 5 can(s) of beer
Tom has 7 can(s) of beer in stock.
Tom tries to consume 5 can(s) of beer
Tom has 2 can(s) of beer in stock.
4 extra can(s) of beer needed for good stocking.
Tom tries to consume 5 can(s) of beer
No more beer after drinking 2 can(s) of beer!
Tom has 0 can(s) of beer in stock.
6 extra can(s) of beer needed for good stocking.
Tom stocks 8 can(s) of beer.
Tom tries to consume 3 can(s) of beer
Tom has 5 can(s) of beer in stock.
1 extra can(s) of beer needed for good stocking.
Python private variables
See “The Python Tutorial: Private Variables.”
Private instance variables that should be treated as a non-public part of the API normally use names prefixed with an underscore (e.g. _spam) by convention.
The name mangling mechanism to support class-private members:
- For current class name of 
classnameor_classname:- Replace 
__spamwith_classname__spam. - Replace 
__spam_with_classname__spam_. 
 - Replace 
 
Install Python source distribution
See http://docs.python.org/3/install/["The Python Tutorial: Installing Python
Modules"] to learn distutils from user’s perspective.
Python programs are normally distributed as a tar ball containing Python module
package and script files.  These are managed by the cross-platform distribution
utility, distutils.  The Python source distribution tar ball can be untared
as:
setup.py
foo/
    __init__.py
    bar.py
    baz/
        __init__.py
        qux.py
scripts/
    command_line_command
The setup.py script of distutils installs Python module package foo in this Python source distribution to the lib/pythonX.Y/site-packages subdirectory with:
Basic install (system wide to /usr/local)
$ sudo python3 setup.py install
Alternate install (per user to ~/.local)
$ pythone setup.py install --user
Alternate install (per user to ~/)
$ python3 setup.py install --home
Alternate install (custom to /path/to)
$ python3 setup.py install --prefix=/path/to
Each execution of setup.py script in the above examples also installs files in the scripts to the corresponding bin subdirectory.
Generate Python source distribution
See
The Python Tutorial: Distributing Python Modules
to learn distutils from developer’s perspective.
The setup.py script of distutils can generate Python source distribution from the source tree containing Python modules and script files.
Generate Python source distribution
$ python3 setup.py sdist
This creates a dist/foo-1.0.tar.gz tar ball file for the Python source distribution.
Example #1 of Python source distribution
Let’s populate the fridge directory with a few files to make Python source distribution.
fridge.py: Python modulefridgeto be packaged (see Python inheritance).README: Package descriptionsetup.py: Package configuration for the Python source distribution.scripts/jane, … : Python script using Python modulefridge.
Let’s make a source tree for Python module fridge.
$ ls -lR fridge
fridge:
total 20
-rw-r--r-- 1 osamu osamu 1586 Aug 17 23:43 fridge.py
-rw-r--r-- 1 osamu osamu 1579 Aug 17 23:43 fridge.py.bak
-rw-rw-r-- 1 osamu osamu   31 Mar 28 22:17 README
drwxrwxr-x 2 osamu osamu 4096 Apr  6 18:14 scripts
-rwxr-xr-x 1 osamu osamu  362 Apr  5 23:58 setup.py
fridge/scripts:
total 12
-rw-r--r-- 1 osamu osamu 124 Apr  6 18:14 jane
-rw-r--r-- 1 osamu osamu  93 Mar 28 20:18 joe
-rw-r--r-- 1 osamu osamu  81 Mar 28 20:19 tom
$
$ cat fridge/setup.py
#!/usr/bin/python3
# vi:se ts=4 sts=4 et si:
from distutils.core import setup
setup(name='fridge',
    version='1.0',
    description='Python Distutils practice',
    author='Osamu Aoki',
    author_email='osamu@debian.org',
    url='http://people.debian.org/~osamu/',
    py_modules=['fridge'],
    scripts=['scripts/jane', 'scripts/joe', 'scripts/tom'],
    )
$
$ cat fridge/README
python source package practice
$
$ cat fridge/scripts/jane
#!/usr/bin/python3
import fridge
import sys
if __name__ == '__main__':
    print(sys.path)
    fridge.test(name = "Jane")
$
$ cat fridge/scripts/joe
#!/usr/bin/python3
import fridge
if __name__ == '__main__':
    fridge.test(name = "Joe")
$
$ cat fridge/scripts/tom
#!/usr/bin/python3
import fridge
if __name__ == '__main__':
    fridge.test()
Please note “py_modules=['fridge'],” in setup.py which tells to
use the fridge.py file as the fridge module.
Let’s execute setup.py and generate Python source distribution
$ cd fridge; python3 setup.py sdist; cd -
/path/to/package2/fridge
running sdist
running check
warning: sdist: manifest template 'MANIFEST.in' does not exist (using default fil...
writing manifest file 'MANIFEST'
creating fridge-1.0
creating fridge-1.0/scripts
making hard links in fridge-1.0...
hard linking README -> fridge-1.0
hard linking fridge.py -> fridge-1.0
hard linking setup.py -> fridge-1.0
hard linking scripts/jane -> fridge-1.0/scripts
hard linking scripts/joe -> fridge-1.0/scripts
hard linking scripts/tom -> fridge-1.0/scripts
creating dist
Creating tar archive
removing 'fridge-1.0' (and everything under it)
/path/to/package2
Let’s see the updated source tree for fridge
$ ls -lR fridge
fridge:
total 28
drwxrwxr-x 2 osamu osamu 4096 Aug 17 23:43 dist
-rw-r--r-- 1 osamu osamu 1586 Aug 17 23:43 fridge.py
-rw-r--r-- 1 osamu osamu 1579 Aug 17 23:43 fridge.py.bak
-rw-rw-r-- 1 osamu osamu  106 Aug 17 23:43 MANIFEST
-rw-rw-r-- 1 osamu osamu   31 Mar 28 22:17 README
drwxrwxr-x 2 osamu osamu 4096 Apr  6 18:14 scripts
-rwxr-xr-x 1 osamu osamu  362 Apr  5 23:58 setup.py
fridge/dist:
total 4
-rw-rw-r-- 1 osamu osamu 1230 Aug 17 23:43 fridge-1.0.tar.gz
fridge/scripts:
total 12
-rw-r--r-- 1 osamu osamu 124 Apr  6 18:14 jane
-rw-r--r-- 1 osamu osamu  93 Mar 28 20:18 joe
-rw-r--r-- 1 osamu osamu  81 Mar 28 20:19 tom
$
$ tar -tvzf fridge/dist/fridge-1.0.tar.gz
drwxrwxr-x osamu/osamu       0 2013-08-17 23:43 fridge-1.0/
drwxrwxr-x osamu/osamu       0 2013-08-17 23:43 fridge-1.0/scripts/
-rw-r--r-- osamu/osamu     124 2013-04-06 18:14 fridge-1.0/scripts/jane
-rw-r--r-- osamu/osamu      93 2013-03-28 20:18 fridge-1.0/scripts/joe
-rw-r--r-- osamu/osamu      81 2013-03-28 20:19 fridge-1.0/scripts/tom
-rw-r--r-- osamu/osamu    1586 2013-08-17 23:43 fridge-1.0/fridge.py
-rw-rw-r-- osamu/osamu     233 2013-08-17 23:43 fridge-1.0/PKG-INFO
-rwxr-xr-x osamu/osamu     362 2013-04-05 23:58 fridge-1.0/setup.py
-rw-rw-r-- osamu/osamu      31 2013-03-28 22:17 fridge-1.0/README
$
$ tar -xvzOf fridge/dist/fridge-1.0.tar.gz fridge-1.0/PKG-INFO
fridge-1.0/PKG-INFO
Metadata-Version: 1.0
Name: fridge
Version: 1.0
Summary: Python Distutils practice
Home-page: http://people.debian.org/~osamu/
Author: Osamu Aoki
Author-email: osamu@debian.org
License: UNKNOWN
Description: UNKNOWN
Platform: UNKNOWN
You see few files generated.
MANIFEST: auto generated by distutils.dist: directory for generated Python source distribution packages.dist/fridge-1.0.tar.gz: Python source distribution package.PKG-INFOindist/fridge-1.0.tar.gz: Metadata for Python source distribution package generated from thesetup.pyfile.
Let’s untar Python source distribution package and install as user.
$ tar -xvzf fridge/dist/fridge-1.0.tar.gz -C dist
fridge-1.0/
fridge-1.0/scripts/
fridge-1.0/scripts/jane
fridge-1.0/scripts/joe
fridge-1.0/scripts/tom
fridge-1.0/fridge.py
fridge-1.0/PKG-INFO
fridge-1.0/setup.py
fridge-1.0/README
$ cd dist/fridge-1.0; python3 setup.py install --user;cd -
/path/to/package2/dist/fridge-1.0
running install
running build
running build_py
creating build
creating build/lib
copying fridge.py -> build/lib
running build_scripts
creating build/scripts-3.3
copying and adjusting scripts/jane -> build/scripts-3.3
copying and adjusting scripts/joe -> build/scripts-3.3
copying and adjusting scripts/tom -> build/scripts-3.3
changing mode of build/scripts-3.3/jane from 664 to 775
changing mode of build/scripts-3.3/joe from 664 to 775
changing mode of build/scripts-3.3/tom from 664 to 775
running install_lib
copying build/lib/fridge.py -> /home/osamu/.local/lib/python3.3/site-packages
byte-compiling /home/osamu/.local/lib/python3.3/site-packages/fridge.py to fridge...
running install_scripts
copying build/scripts-3.3/jane -> /home/osamu/.local/bin
copying build/scripts-3.3/joe -> /home/osamu/.local/bin
copying build/scripts-3.3/tom -> /home/osamu/.local/bin
changing mode of /home/osamu/.local/bin/jane to 775
changing mode of /home/osamu/.local/bin/joe to 775
changing mode of /home/osamu/.local/bin/tom to 775
running install_egg_info
Removing /home/osamu/.local/lib/python3.3/site-packages/fridge-1.0.egg-info
Writing /home/osamu/.local/lib/python3.3/site-packages/fridge-1.0.egg-info
/path/to/package2
$ jane|fold
['/home/osamu/.local/bin', '/usr/lib/python3.3', '/usr/lib/python3.3/plat-x86_64
-linux-gnu', '/usr/lib/python3.3/lib-dynload', '/home/osamu/.local/lib/python3.3
/site-packages', '/usr/local/lib/python3.3/dist-packages', '/usr/lib/python3/dis
t-packages']
Jane bought a new fridge.
Jane wishes to have 6 cans of beer
Jane stocks 12 can(s) of beer.
Jane tries to consume 5 can(s) of beer
Jane has 7 can(s) of beer in stock.
Jane tries to consume 5 can(s) of beer
Jane has 2 can(s) of beer in stock.
4 extra can(s) of beer needed for good stocking.
Jane tries to consume 5 can(s) of beer
No more beer after drinking 2 can(s) of beer!
Jane has 0 can(s) of beer in stock.
6 extra can(s) of beer needed for good stocking.
Jane stocks 8 can(s) of beer.
Jane tries to consume 3 can(s) of beer
Jane has 5 can(s) of beer in stock.
1 extra can(s) of beer needed for good stocking.
Unfortunately, distutils as of now does not offer uninstall.  We need to remove files manually to uninstall them.
Let’s uninstall Python source distribution manually.
$ rm -rf dist
$ rm -r ~/.local/bin/jane ~/.local/bin/joe ~/.local/bin/tom
$ rm -r ~/.local/lib/python3.2/site-packages/fridge.py
rm: cannot remove ‘/home/osamu/.local/lib/python3.2/site-packages/fridge.py’: No ...
$ rm -r ~/.local/lib/python3.2/site-packages/fridge-1.0.egg-info
rm: cannot remove ‘/home/osamu/.local/lib/python3.2/site-packages/fridge-1.0.egg-...
$ rm -rf ~/.local/lib/python3.2/site-packages/__pycache__
Example #2 of Python source distribution
Let’s try an alternative Python source distribution with Python module package.
Basically, move fridge/fridge.py in Example #1 to fridge/src/fridge/__init__.py.
Let’s execute this.
$ python3 fridge/src/fridge/__init__.py
Tom bought a new fridge.
Tom wishes to have 6 cans of beer
Tom stocks 12 can(s) of beer.
Tom tries to consume 5 can(s) of beer
Tom has 7 can(s) of beer in stock.
Tom tries to consume 5 can(s) of beer
Tom has 2 can(s) of beer in stock.
4 extra can(s) of beer needed for good stocking.
Tom tries to consume 5 can(s) of beer
No more beer after drinking 2 can(s) of beer!
Tom has 0 can(s) of beer in stock.
6 extra can(s) of beer needed for good stocking.
Tom stocks 8 can(s) of beer.
Tom tries to consume 3 can(s) of beer
Tom has 5 can(s) of beer in stock.
1 extra can(s) of beer needed for good stocking.
Let’s populate the fridge directory with mostly the same files except:
src/fridge/__init__.py: Python modulefridgeto be packaged insted offridge.py(see Python module package).setup.py: Package configuration for the Python source distribution (Contents of the file updated).
Let’s make a source tree for Python module fridge.
$ ls -lR fridge
fridge:
total 16
-rw-rw-r-- 1 osamu osamu   31 Mar 28 22:17 README
drwxrwxr-x 2 osamu osamu 4096 Apr  6 18:14 scripts
-rwxr-xr-x 1 osamu osamu  402 Apr  5 23:59 setup.py
drwxrwxr-x 3 osamu osamu 4096 Mar 29 00:01 src
fridge/scripts:
total 12
-rw-r--r-- 1 osamu osamu 124 Apr  6 18:14 jane
-rw-r--r-- 1 osamu osamu  93 Mar 28 20:18 joe
-rw-r--r-- 1 osamu osamu  81 Mar 28 20:19 tom
fridge/src:
total 4
drwxrwxr-x 2 osamu osamu 4096 Apr  6 18:35 fridge
fridge/src/fridge:
total 4
-rw-r--r-- 1 osamu osamu 1583 Mar 28 20:10 __init__.py
$
$ cat fridge/setup.py
#!/usr/bin/python3
# vi:se ts=4 sts=4 et si:
from distutils.core import setup
setup(name='fridge',
    version='1.0',
    description='Python Distutils practice',
    author='Osamu Aoki',
    author_email='osamu@debian.org',
    url='http://people.debian.org/~osamu/',
    packages=['fridge'],
    package_dir={'fridge': 'src/fridge'},
    scripts=['scripts/jane', 'scripts/joe', 'scripts/tom'],
    )
Please note “package_dir={'fridge': 'src/fridge'},” in setup.py which tells
to use files in the src/fridge directory as the fridge module package.
Let’s execute setup.py and generate Python source distribution
$ cd fridge; python3 setup.py sdist; cd -
/path/to/package3/fridge
running sdist
running check
warning: sdist: manifest template 'MANIFEST.in' does not exist (using default fil...
writing manifest file 'MANIFEST'
creating fridge-1.0
creating fridge-1.0/scripts
creating fridge-1.0/src
creating fridge-1.0/src/fridge
making hard links in fridge-1.0...
hard linking README -> fridge-1.0
hard linking setup.py -> fridge-1.0
hard linking scripts/jane -> fridge-1.0/scripts
hard linking scripts/joe -> fridge-1.0/scripts
hard linking scripts/tom -> fridge-1.0/scripts
hard linking src/fridge/__init__.py -> fridge-1.0/src/fridge
creating dist
Creating tar archive
removing 'fridge-1.0' (and everything under it)
/path/to/package3
Let’s see the updated source tree for fridge
$ ls -lR fridge
fridge:
total 24
drwxrwxr-x 2 osamu osamu 4096 Aug 17 23:43 dist
-rw-rw-r-- 1 osamu osamu  119 Aug 17 23:43 MANIFEST
-rw-rw-r-- 1 osamu osamu   31 Mar 28 22:17 README
drwxrwxr-x 2 osamu osamu 4096 Apr  6 18:14 scripts
-rwxr-xr-x 1 osamu osamu  402 Apr  5 23:59 setup.py
drwxrwxr-x 3 osamu osamu 4096 Mar 29 00:01 src
fridge/dist:
total 4
-rw-rw-r-- 1 osamu osamu 1268 Aug 17 23:43 fridge-1.0.tar.gz
fridge/scripts:
total 12
-rw-r--r-- 1 osamu osamu 124 Apr  6 18:14 jane
-rw-r--r-- 1 osamu osamu  93 Mar 28 20:18 joe
-rw-r--r-- 1 osamu osamu  81 Mar 28 20:19 tom
fridge/src:
total 4
drwxrwxr-x 2 osamu osamu 4096 Apr  6 18:35 fridge
fridge/src/fridge:
total 4
-rw-r--r-- 1 osamu osamu 1583 Mar 28 20:10 __init__.py
$
$ tar -tvzf fridge/dist/fridge-1.0.tar.gz
drwxrwxr-x osamu/osamu       0 2013-08-17 23:43 fridge-1.0/
drwxrwxr-x osamu/osamu       0 2013-08-17 23:43 fridge-1.0/scripts/
-rw-r--r-- osamu/osamu     124 2013-04-06 18:14 fridge-1.0/scripts/jane
-rw-r--r-- osamu/osamu      93 2013-03-28 20:18 fridge-1.0/scripts/joe
-rw-r--r-- osamu/osamu      81 2013-03-28 20:19 fridge-1.0/scripts/tom
drwxrwxr-x osamu/osamu       0 2013-08-17 23:43 fridge-1.0/src/
drwxrwxr-x osamu/osamu       0 2013-08-17 23:43 fridge-1.0/src/fridge/
-rw-r--r-- osamu/osamu    1583 2013-03-28 20:10 fridge-1.0/src/fridge/__init__.py...
-rw-rw-r-- osamu/osamu     233 2013-08-17 23:43 fridge-1.0/PKG-INFO
-rwxr-xr-x osamu/osamu     402 2013-04-05 23:59 fridge-1.0/setup.py
-rw-rw-r-- osamu/osamu      31 2013-03-28 22:17 fridge-1.0/README
You see few files generated.
MANIFEST: auto generated by distutils.dist: directory for generated Python source distribution packages.dist/fridge-1.0.tar.gz: Python source distribution package.PKG-INFOindist/fridge-1.0.tar.gz: Metadata for Python source distribution package generated from thesetup.pyfile.
Let’s untar Python source distribution package and install as user.
$ tar -xvzf fridge/dist/fridge-1.0.tar.gz -C dist
fridge-1.0/
fridge-1.0/scripts/
fridge-1.0/scripts/jane
fridge-1.0/scripts/joe
fridge-1.0/scripts/tom
fridge-1.0/fridge.py
fridge-1.0/PKG-INFO
fridge-1.0/setup.py
fridge-1.0/README
$ cd dist/fridge-1.0; python3 setup.py install --user;cd -
/path/to/package2/dist/fridge-1.0
running install
running build
running build_py
creating build
creating build/lib
copying fridge.py -> build/lib
running build_scripts
creating build/scripts-3.3
copying and adjusting scripts/jane -> build/scripts-3.3
copying and adjusting scripts/joe -> build/scripts-3.3
copying and adjusting scripts/tom -> build/scripts-3.3
changing mode of build/scripts-3.3/jane from 664 to 775
changing mode of build/scripts-3.3/joe from 664 to 775
changing mode of build/scripts-3.3/tom from 664 to 775
running install_lib
copying build/lib/fridge.py -> /home/osamu/.local/lib/python3.3/site-packages
byte-compiling /home/osamu/.local/lib/python3.3/site-packages/fridge.py to fridge...
running install_scripts
copying build/scripts-3.3/jane -> /home/osamu/.local/bin
copying build/scripts-3.3/joe -> /home/osamu/.local/bin
copying build/scripts-3.3/tom -> /home/osamu/.local/bin
changing mode of /home/osamu/.local/bin/jane to 775
changing mode of /home/osamu/.local/bin/joe to 775
changing mode of /home/osamu/.local/bin/tom to 775
running install_egg_info
Removing /home/osamu/.local/lib/python3.3/site-packages/fridge-1.0.egg-info
Writing /home/osamu/.local/lib/python3.3/site-packages/fridge-1.0.egg-info
/path/to/package2
$ jane|fold
['/home/osamu/.local/bin', '/usr/lib/python3.3', '/usr/lib/python3.3/plat-x86_64
-linux-gnu', '/usr/lib/python3.3/lib-dynload', '/home/osamu/.local/lib/python3.3
/site-packages', '/usr/local/lib/python3.3/dist-packages', '/usr/lib/python3/dis
t-packages']
Jane bought a new fridge.
Jane wishes to have 6 cans of beer
Jane stocks 12 can(s) of beer.
Jane tries to consume 5 can(s) of beer
Jane has 7 can(s) of beer in stock.
Jane tries to consume 5 can(s) of beer
Jane has 2 can(s) of beer in stock.
4 extra can(s) of beer needed for good stocking.
Jane tries to consume 5 can(s) of beer
No more beer after drinking 2 can(s) of beer!
Jane has 0 can(s) of beer in stock.
6 extra can(s) of beer needed for good stocking.
Jane stocks 8 can(s) of beer.
Jane tries to consume 3 can(s) of beer
Jane has 5 can(s) of beer in stock.
1 extra can(s) of beer needed for good stocking.
Unfortunately, distutils as of now does not offer uninstall.  We need to remove files manually to uninstall them.
Let’s uninstall Python source distribution manually.
$ rm -rf dist
$ rm -r ~/.local/bin/jane ~/.local/bin/joe ~/.local/bin/tom
$ rm -r ~/.local/lib/python3.2/site-packages/fridge.py
rm: cannot remove ‘/home/osamu/.local/lib/python3.2/site-packages/fridge.py’: No ...
$ rm -r ~/.local/lib/python3.2/site-packages/fridge-1.0.egg-info
rm: cannot remove ‘/home/osamu/.local/lib/python3.2/site-packages/fridge-1.0.egg-...
$ rm -rf ~/.local/lib/python3.2/site-packages/__pycache__
Debian package from Python2 source distribution (dh_make)
The dh_make is handy for making a Debian package.  I will be very sloppy for now.  (More work is needed to make package suitable for Debian.)
Let’s make Debian source package.
$ tar -xvzf fridge/dist/fridge-1.0.tar.gz -C deb
fridge-1.0/
fridge-1.0/scripts/
fridge-1.0/scripts/jane
fridge-1.0/scripts/joe
fridge-1.0/scripts/tom
fridge-1.0/fridge.py
fridge-1.0/PKG-INFO
fridge-1.0/setup.py
fridge-1.0/README
$ cd deb/fridge-1.0; dh_make -s --createorig --yes; cd -
/path/to/package1/deb/fridge-1.0
Maintainer name  : Osamu Aoki
Email-Address    : osamu@debian.org
Date             : Sat, 17 Aug 2013 23:43:26 +0900
Package Name     : fridge
Version          : 1.0
License          : blank
Type of Package  : Single
Currently there is no top level Makefile. This may require additional tuning.
Done. Please edit the files in the debian/ subdirectory now. You should also
check that the fridge Makefiles install into $DESTDIR and not in / .
/path/to/package1
$ ls -lR deb
deb:
total 8
drwxrwxr-x 4 osamu osamu 4096 Aug 17 23:43 fridge-1.0
-rw-rw-r-- 1 osamu osamu 1212 Aug 17 23:43 fridge_1.0.orig.tar.xz
deb/fridge-1.0:
total 24
drwxr-xr-x 3 osamu osamu 4096 Aug 17 23:43 debian
-rw-r--r-- 1 osamu osamu 1579 Apr  8 21:16 fridge.py
-rw-rw-r-- 1 osamu osamu  233 Aug 17 23:43 PKG-INFO
-rw-rw-r-- 1 osamu osamu   31 Mar 28 22:17 README
drwxrwxr-x 2 osamu osamu 4096 Aug 17 23:43 scripts
-rwxr-xr-x 1 osamu osamu  361 Apr  8 21:13 setup.py
deb/fridge-1.0/debian:
total 104
-rw-rw-r-- 1 osamu osamu   180 Aug 17 23:43 changelog
-rw-rw-r-- 1 osamu osamu     2 Aug 17 23:43 compat
-rw-rw-r-- 1 osamu osamu   505 Aug 17 23:43 control
-rw-rw-r-- 1 osamu osamu  1668 Aug 17 23:43 copyright
-rw-rw-r-- 1 osamu osamu     7 Aug 17 23:43 docs
-rw-rw-r-- 1 osamu osamu   128 Aug 17 23:43 fridge.cron.d.ex
-rw-rw-r-- 1 osamu osamu   232 Aug 17 23:43 fridge.default.ex
-rw-rw-r-- 1 osamu osamu   504 Aug 17 23:43 fridge.doc-base.EX
-rw-rw-r-- 1 osamu osamu  4675 Aug 17 23:43 init.d.ex
-rw-rw-r-- 1 osamu osamu  1625 Aug 17 23:43 manpage.1.ex
-rw-rw-r-- 1 osamu osamu  4648 Aug 17 23:43 manpage.sgml.ex
-rw-rw-r-- 1 osamu osamu 11003 Aug 17 23:43 manpage.xml.ex
-rw-rw-r-- 1 osamu osamu   123 Aug 17 23:43 menu.ex
-rw-rw-r-- 1 osamu osamu   956 Aug 17 23:43 postinst.ex
-rw-rw-r-- 1 osamu osamu   929 Aug 17 23:43 postrm.ex
-rw-rw-r-- 1 osamu osamu   689 Aug 17 23:43 preinst.ex
-rw-rw-r-- 1 osamu osamu   876 Aug 17 23:43 prerm.ex
-rw-rw-r-- 1 osamu osamu   173 Aug 17 23:43 README.Debian
-rw-rw-r-- 1 osamu osamu   191 Aug 17 23:43 README.source
-rwxr-xr-x 1 osamu osamu   442 Aug 17 23:43 rules
drwxr-xr-x 2 osamu osamu  4096 Aug 17 23:43 source
-rw-rw-r-- 1 osamu osamu   775 Aug 17 23:43 watch.ex
deb/fridge-1.0/debian/source:
total 4
-rw-rw-r-- 1 osamu osamu 12 Aug 17 23:43 format
deb/fridge-1.0/scripts:
total 12
-rw-r--r-- 1 osamu osamu 124 Apr  6 18:14 jane
-rw-r--r-- 1 osamu osamu  93 Mar 28 20:18 joe
-rw-r--r-- 1 osamu osamu  81 Mar 28 20:19 tom
$
  ... update debian/control
  ... update debian/rules
  ... touch up template files
  ... remove unused template files
$ ls -l deb/fridge-1.0/debian
total 32
-rw-rw-r-- 1 osamu osamu  180 Apr  6 22:36 changelog
-rw-rw-r-- 1 osamu osamu    2 Apr  6 22:36 compat
-rw-rw-r-- 1 osamu osamu  554 Apr  8 21:18 control
-rw-rw-r-- 1 osamu osamu 1668 Apr  6 22:36 copyright
-rw-rw-r-- 1 osamu osamu  440 Apr  6 23:03 manpage.1
-rw-rw-r-- 1 osamu osamu  120 Apr  6 23:03 README.Debian
-rwxr-xr-x 1 osamu osamu   67 Apr  9 20:33 rules
drwxr-xr-x 2 osamu osamu 4096 Apr  6 22:36 source
$ cat deb/fridge-1.0/debian/control
Source: fridge
Section: unknown
Priority: extra
Maintainer: Osamu Aoki <osamu@debian.org>
Build-Depends: debhelper (>= 8.0.0), python-minimal, python
Standards-Version: 3.9.3
X-Python-Version: >= 2.6
Homepage: <insert the upstream URL, if relevant>
#Vcs-Git: git://git.debian.org/collab-maint/fridge.git
#Vcs-Browser: http://git.debian.org/?p=collab-maint/fridge.git;a=summary
Package: fridge
Architecture: all
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: <insert up to 60 chars description>
 <insert long description, indented with spaces>
$ cat deb/fridge-1.0/debian/rules
#!/usr/bin/make -f
#export DH_VERBOSE=1
%:
    dh $@ --with python2
Here, I add the package dependency etc. to debian/control.
Let’s make Debian binary package.
$ cd deb/fridge-1.0; debuild -us -uc; cd -
/path/to/package1/deb/fridge-1.0
 dpkg-buildpackage -rfakeroot -D -us -uc -I -i
dpkg-buildpackage: source package fridge
dpkg-buildpackage: source version 1.0-1
dpkg-buildpackage: source distribution unstable
dpkg-buildpackage: source changed by Osamu Aoki <osamu@debian.org>
 dpkg-source -I -i --before-build fridge-1.0
dpkg-buildpackage: host architecture amd64
 fakeroot debian/rules clean
dh clean --with python2
   dh_testdir
   dh_auto_clean
running clean
'build/lib.linux-x86_64-2.7' does not exist -- can't clean it
'build/bdist.linux-x86_64' does not exist -- can't clean it
'build/scripts-2.7' does not exist -- can't clean it
   dh_clean
 dpkg-source -I -i -b fridge-1.0
dpkg-source: info: using source format `3.0 (quilt)'
dpkg-source: info: building fridge using existing ./fridge_1.0.orig.tar.xz
dpkg-source: info: building fridge in fridge_1.0-1.debian.tar.gz
dpkg-source: info: building fridge in fridge_1.0-1.dsc
 debian/rules build
dh build --with python2
   dh_testdir
   dh_auto_configure
   dh_auto_build
running build
running build_py
creating build
creating build/lib.linux-x86_64-2.7
copying fridge.py -> build/lib.linux-x86_64-2.7
running build_scripts
creating build/scripts-2.7
copying and adjusting scripts/jane -> build/scripts-2.7
copying and adjusting scripts/joe -> build/scripts-2.7
copying and adjusting scripts/tom -> build/scripts-2.7
changing mode of build/scripts-2.7/jane from 644 to 755
changing mode of build/scripts-2.7/joe from 644 to 755
changing mode of build/scripts-2.7/tom from 644 to 755
   dh_auto_test
 fakeroot debian/rules binary
dh binary --with python2
   dh_testroot
   dh_prep
   dh_auto_install
running install
running build
running build_py
running build_scripts
running install_lib
creating /path/to/package1/deb/fridge-1.0/debian/fridge/usr
creating /path/to/package1/deb/fridge-1.0/debian/fridge/usr/lib
creating /path/to/package1/deb/fridge-1.0/debian/fridge/usr/lib/python2.7
creating /path/to/package1/deb/fridge-1.0/debian/fridge/usr/lib/python2.7/dist-pa...
copying build/lib.linux-x86_64-2.7/fridge.py -> /path/to/package1/deb/fridge-1.0/...
running install_scripts
creating /path/to/package1/deb/fridge-1.0/debian/fridge/usr/bin
copying build/scripts-2.7/jane -> /path/to/package1/deb/fridge-1.0/debian/fridge/...
copying build/scripts-2.7/joe -> /path/to/package1/deb/fridge-1.0/debian/fridge/u...
copying build/scripts-2.7/tom -> /path/to/package1/deb/fridge-1.0/debian/fridge/u...
changing mode of /path/to/package1/deb/fridge-1.0/debian/fridge/usr/bin/jane to 7...
changing mode of /path/to/package1/deb/fridge-1.0/debian/fridge/usr/bin/joe to 75...
changing mode of /path/to/package1/deb/fridge-1.0/debian/fridge/usr/bin/tom to 75...
running install_egg_info
Writing /path/to/package1/deb/fridge-1.0/debian/fridge/usr/lib/python2.7/dist-pac...
   dh_installdocs
   dh_installchangelogs
   dh_python2
   dh_perl
   dh_link
   dh_compress
   dh_fixperms
   dh_installdeb
   dh_gencontrol
dpkg-gencontrol: warning: Depends field of package fridge: unknown substitution v...
dpkg-gencontrol: warning: package fridge: unused substitution variable ${python:V...
dpkg-gencontrol: warning: package fridge: unused substitution variable ${python:D...
   dh_md5sums
   dh_builddeb
dpkg-deb: building package `fridge' in `../fridge_1.0-1_all.deb'.
 dpkg-genchanges  >../fridge_1.0-1_amd64.changes
dpkg-genchanges: including full source code in upload
 dpkg-source -I -i --after-build fridge-1.0
dpkg-buildpackage: full upload (original source is included)
Now running lintian...
W: fridge source: superfluous-clutter-in-homepage <insert the upstream URL, if re...
N:
N:    The "Homepage:" field in this package's control file contains
N:    superfluous markup around the URL, like enclosing < and >. This is
N:    unnecessary and needlessly complicates using this information.
N:
N:    Refer to Debian Policy Manual section 5.6.23 (Homepage) for details.
N:
N:    Severity: normal, Certainty: certain
N:
N:    Check: fields, Type: binary, udeb, source
N:
W: fridge source: bad-homepage <insert the upstream URL, if relevant>
N:
N:    The "Homepage:" field in this package's control file does not contain a
N:    valid absolute URL. Most probably you forgot to specify the scheme (e.g.
N:    http).
N:
N:    This tag is also triggered if the scheme is not known by Lintian.
N:
N:    Please file a bug against Lintian, if this tag is triggered for a valid
N:    homepage URL.
N:
N:    Severity: normal, Certainty: certain
N:
N:    Check: fields, Type: binary, udeb, source
N:
W: fridge source: out-of-date-standards-version 3.9.3 (current is 3.9.4)
N:
N:    The source package refers to a Standards-Version older than the one that
N:    was current at the time the package was created (according to the
N:    timestamp of the latest debian/changelog entry). Please consider
N:    updating the package to current Policy and setting this control field
N:    appropriately.
N:
N:    If the package is already compliant with the current standards, you
N:    don't have to re-upload the package just to adjust the Standards-Version
N:    control field. However, please remember to update this field next time
N:    you upload the package.
N:
N:    See /usr/share/doc/debian-policy/upgrading-checklist.txt.gz in the
N:    debian-policy package for a summary of changes in newer versions of
N:    Policy.
N:
N:    Refer to http://www.debian.org/doc/debian-policy/upgrading-checklist for
N:    details.
N:
N:    Severity: normal, Certainty: certain
N:
N:    Check: standards-version, Type: source
N:
W: fridge: wrong-bug-number-in-closes l3:#nnnn
N:
N:    Bug numbers can only contain digits.
N:
N:    Refer to Debian Policy Manual section 4.4 (Debian changelog:
N:    debian/changelog) for details.
N:
N:    Severity: normal, Certainty: certain
N:
N:    Check: changelog-file, Type: binary
N:
W: fridge: new-package-should-close-itp-bug
N:
N:    This package appears to be the first packaging of a new upstream
N:    software package (there is only one changelog entry and the Debian
N:    revision is 1), but it does not close any bugs. The initial upload of a
N:    new package should close the corresponding ITP bug for that package.
N:
N:    This warning can be ignored if the package is not intended for Debian or
N:    if it is a split of an existing Debian package.
N:
N:    Refer to Debian Developer's Reference section 5.1 (New packages) for
N:    details.
N:
N:    Severity: normal, Certainty: certain
N:
N:    Check: changelog-file, Type: binary
N:
E: fridge: helper-templates-in-copyright
N:
N:    The /usr/share/doc/<pkg>/copyright file still contains template markers
N:    from a packaging helper. Please fill in the actual license, upstream
N:    copyright holders, and download information about the package and remove
N:    any remaining templates generated by the packaging helper.
N:
N:    Severity: important, Certainty: certain
N:
N:    Check: copyright-file, Type: binary
N:
W: fridge: copyright-has-url-from-dh_make-boilerplate
N:
N:    There is "url://example.com" in your copyright file. This was most
N:    likely a remnant from the dh_make template.
N:
N:    Make sure you include the real location where you obtained the upstream
N:    sources (if any).
N:
N:    Refer to Debian Policy Manual section 12.5 (Copyright information) for
N:    details.
N:
N:    Severity: normal, Certainty: certain
N:
N:    Check: copyright-file, Type: binary
N:
E: fridge: copyright-contains-dh_make-todo-boilerplate
N:
N:    The string "Please also look if..." appears in the copyright file, which
N:    indicates that you either didn't check the whole source to find
N:    additional copyright/license, or that you didn't remove that paragraph
N:    after having done so.
N:
N:    Refer to Debian Policy Manual section 12.5 (Copyright information) for
N:    details.
N:
N:    Severity: serious, Certainty: possible
N:
N:    Check: copyright-file, Type: binary
N:
E: fridge: description-is-dh_make-template
N:
N:    The synopsis or the extended description has not been changed from the
N:    template provided by dh_make.
N:
N:    Severity: serious, Certainty: certain
N:
N:    Check: description, Type: binary, udeb
N:
E: fridge: section-is-dh_make-template
N:
N:    The "Section:" field in this package's control file is set to unknown.
N:    This is not a valid section, and usually means a dh_make template
N:    control file was used and never modified to set the correct section.
N:
N:    Refer to Debian Policy Manual section 2.4 (Sections) for details.
N:
N:    Severity: serious, Certainty: certain
N:
N:    Check: fields, Type: binary, udeb, source
N:
W: fridge: superfluous-clutter-in-homepage <insert the upstream URL, if relevant>...
W: fridge: bad-homepage <insert the upstream URL, if relevant>
W: fridge: binary-without-manpage usr/bin/jane
N:
N:    Each binary in /usr/bin, /usr/sbin, /bin, /sbin or /usr/games should
N:    have a manual page
N:
N:    Note that though the man program has the capability to check for several
N:    program names in the NAMES section, each of these programs should have
N:    its own manual page (a symbolic link to the appropriate manual page is
N:    sufficient) because other manual page viewers such as xman or tkman
N:    don't support this.
N:
N:    If the name of the man page differs from the binary by case, man may be
N:    able to find it anyway; however, it is still best practice to make the
N:    case of the man page match the case of the binary.
N:
N:    If the man pages are provided by another package on which this package
N:    depends, lintian may not be able to determine that man pages are
N:    available. In this case, after confirming that all binaries do have man
N:    pages after this package and its dependencies are installed, please add
N:    a lintian override.
N:
N:    Refer to Debian Policy Manual section 12.1 (Manual pages) for details.
N:
N:    Severity: normal, Certainty: possible
N:
N:    Check: manpages, Type: binary
N:
W: fridge: binary-without-manpage usr/bin/joe
W: fridge: binary-without-manpage usr/bin/tom
E: fridge: python-script-but-no-python-dep usr/bin/jane
N:
N:    Packages with Python scripts should depend on the package python. Those
N:    with scripts that specify a specific version of Python must depend on
N:    that version of Python (exactly).
N:
N:    For example, if a script in the package uses #!/usr/bin/python, the
N:    package needs a dependency on python. If a script uses
N:    #!/usr/bin/python2.6, the package needs a dependency on python2.6. A
N:    dependency on python (>= 2.6) is not correct, since later versions of
N:    Python may not provide the /usr/bin/python2.6 binary.
N:
N:    If you are using debhelper, adding ${python:Depends} to the Depends
N:    field and ensuring dh_pysupport or dh_pycentral are run during the build
N:    should take care of adding the correct dependency.
N:
N:    In some cases a weaker relationship, such as Suggests or Recommends,
N:    will be more appropriate.
N:
N:    Severity: important, Certainty: certain
N:
N:    Check: scripts, Type: binary
N:
E: fridge: python-script-but-no-python-dep usr/bin/joe
E: fridge: python-script-but-no-python-dep usr/bin/tom
Finished running lintian.
/path/to/package1
$ ls -l deb
total 36
drwxrwxr-x 5 osamu osamu  4096 Aug 17 23:43 fridge-1.0
-rw-r--r-- 1 osamu osamu  3364 Aug 17 23:43 fridge_1.0-1_all.deb
-rw-r--r-- 1 osamu osamu 11908 Aug 17 23:43 fridge_1.0-1_amd64.build
-rw-r--r-- 1 osamu osamu  1419 Aug 17 23:43 fridge_1.0-1_amd64.changes
-rw-r--r-- 1 osamu osamu  1993 Aug 17 23:43 fridge_1.0-1.debian.tar.gz
-rw-r--r-- 1 osamu osamu   808 Aug 17 23:43 fridge_1.0-1.dsc
-rw-rw-r-- 1 osamu osamu  1212 Aug 17 23:43 fridge_1.0.orig.tar.xz
$ dpkg -c deb/fridge_1.0-1_all.deb
drwxr-xr-x root/root         0 2013-08-17 23:43 ./
drwxr-xr-x root/root         0 2013-08-17 23:43 ./usr/
drwxr-xr-x root/root         0 2013-08-17 23:43 ./usr/lib/
drwxr-xr-x root/root         0 2013-08-17 23:43 ./usr/lib/python2.7/
drwxr-xr-x root/root         0 2013-08-17 23:43 ./usr/lib/python2.7/dist-packages...
drwxr-xr-x root/root         0 2013-08-17 23:43 ./usr/bin/
-rwxr-xr-x root/root       124 2013-08-17 23:43 ./usr/bin/jane
-rwxr-xr-x root/root        93 2013-08-17 23:43 ./usr/bin/joe
-rwxr-xr-x root/root        81 2013-08-17 23:43 ./usr/bin/tom
drwxr-xr-x root/root         0 2013-08-17 23:43 ./usr/share/
drwxr-xr-x root/root         0 2013-08-17 23:43 ./usr/share/doc/
drwxr-xr-x root/root         0 2013-08-17 23:43 ./usr/share/doc/fridge/
-rw-r--r-- root/root      1668 2013-04-06 22:36 ./usr/share/doc/fridge/copyright
-rw-r--r-- root/root       120 2013-04-06 23:03 ./usr/share/doc/fridge/README.Deb...
-rw-r--r-- root/root       172 2013-04-06 22:36 ./usr/share/doc/fridge/changelog....
drwxr-xr-x root/root         0 2013-08-17 23:43 ./usr/share/pyshared/
-rw-r--r-- root/root       233 2013-08-17 23:43 ./usr/share/pyshared/fridge-1.0.e...
-rw-r--r-- root/root      1579 2013-04-08 21:16 ./usr/share/pyshared/fridge.py
lrwxrwxrwx root/root         0 2013-08-17 23:43 ./usr/lib/python2.7/dist-packages...
lrwxrwxrwx root/root         0 2013-08-17 23:43 ./usr/lib/python2.7/dist-packages...
Now we have Debian package fridge_1.0-1_all.deb which can be installed and removed easily.
Debian package from Python3 source distribution (dh_make)
Let’s do the same for Python3.
Let’s make Debian source package.
$ tar -xvzf fridge/dist/fridge-1.0.tar.gz -C deb
fridge-1.0/
fridge-1.0/scripts/
fridge-1.0/scripts/jane
fridge-1.0/scripts/joe
fridge-1.0/scripts/tom
fridge-1.0/fridge.py
fridge-1.0/PKG-INFO
fridge-1.0/setup.py
fridge-1.0/README
$ cd deb/fridge-1.0; dh_make -s --createorig --yes; cd -
/path/to/package2/deb/fridge-1.0
Maintainer name  : Osamu Aoki
Email-Address    : osamu@debian.org
Date             : Sat, 17 Aug 2013 23:43:32 +0900
Package Name     : fridge
Version          : 1.0
License          : blank
Type of Package  : Single
Currently there is no top level Makefile. This may require additional tuning.
Done. Please edit the files in the debian/ subdirectory now. You should also
check that the fridge Makefiles install into $DESTDIR and not in / .
/path/to/package2
$ ls -lR deb
deb:
total 8
drwxrwxr-x 4 osamu osamu 4096 Aug 17 23:43 fridge-1.0
-rw-rw-r-- 1 osamu osamu 1212 Aug 17 23:43 fridge_1.0.orig.tar.xz
deb/fridge-1.0:
total 24
drwxr-xr-x 3 osamu osamu 4096 Aug 17 23:43 debian
-rw-r--r-- 1 osamu osamu 1586 Aug 17 23:43 fridge.py
-rw-rw-r-- 1 osamu osamu  233 Aug 17 23:43 PKG-INFO
-rw-rw-r-- 1 osamu osamu   31 Mar 28 22:17 README
drwxrwxr-x 2 osamu osamu 4096 Aug 17 23:43 scripts
-rwxr-xr-x 1 osamu osamu  362 Apr  5 23:58 setup.py
deb/fridge-1.0/debian:
total 104
-rw-rw-r-- 1 osamu osamu   180 Aug 17 23:43 changelog
-rw-rw-r-- 1 osamu osamu     2 Aug 17 23:43 compat
-rw-rw-r-- 1 osamu osamu   505 Aug 17 23:43 control
-rw-rw-r-- 1 osamu osamu  1668 Aug 17 23:43 copyright
-rw-rw-r-- 1 osamu osamu     7 Aug 17 23:43 docs
-rw-rw-r-- 1 osamu osamu   128 Aug 17 23:43 fridge.cron.d.ex
-rw-rw-r-- 1 osamu osamu   232 Aug 17 23:43 fridge.default.ex
-rw-rw-r-- 1 osamu osamu   504 Aug 17 23:43 fridge.doc-base.EX
-rw-rw-r-- 1 osamu osamu  4675 Aug 17 23:43 init.d.ex
-rw-rw-r-- 1 osamu osamu  1625 Aug 17 23:43 manpage.1.ex
-rw-rw-r-- 1 osamu osamu  4648 Aug 17 23:43 manpage.sgml.ex
-rw-rw-r-- 1 osamu osamu 11003 Aug 17 23:43 manpage.xml.ex
-rw-rw-r-- 1 osamu osamu   123 Aug 17 23:43 menu.ex
-rw-rw-r-- 1 osamu osamu   956 Aug 17 23:43 postinst.ex
-rw-rw-r-- 1 osamu osamu   929 Aug 17 23:43 postrm.ex
-rw-rw-r-- 1 osamu osamu   689 Aug 17 23:43 preinst.ex
-rw-rw-r-- 1 osamu osamu   876 Aug 17 23:43 prerm.ex
-rw-rw-r-- 1 osamu osamu   173 Aug 17 23:43 README.Debian
-rw-rw-r-- 1 osamu osamu   191 Aug 17 23:43 README.source
-rwxr-xr-x 1 osamu osamu   442 Aug 17 23:43 rules
drwxr-xr-x 2 osamu osamu  4096 Aug 17 23:43 source
-rw-rw-r-- 1 osamu osamu   775 Aug 17 23:43 watch.ex
deb/fridge-1.0/debian/source:
total 4
-rw-rw-r-- 1 osamu osamu 12 Aug 17 23:43 format
deb/fridge-1.0/scripts:
total 12
-rw-r--r-- 1 osamu osamu 124 Apr  6 18:14 jane
-rw-r--r-- 1 osamu osamu  93 Mar 28 20:18 joe
-rw-r--r-- 1 osamu osamu  81 Mar 28 20:19 tom
$
  ... update debian/control
  ... update debian/rules
  ... touch up template files
  ... remove unused template files
$ ls -l deb/fridge-1.0/debian
total 32
-rw-rw-r-- 1 osamu osamu  180 Apr  6 22:36 changelog
-rw-rw-r-- 1 osamu osamu    2 Apr  6 22:36 compat
-rw-rw-r-- 1 osamu osamu  557 Apr  8 22:54 control
-rw-rw-r-- 1 osamu osamu 1668 Apr  6 22:36 copyright
-rw-rw-r-- 1 osamu osamu  440 Apr  6 23:03 manpage.1
-rw-rw-r-- 1 osamu osamu  120 Apr  6 23:03 README.Debian
-rwxr-xr-x 1 osamu osamu  663 Apr  9 20:44 rules
drwxr-xr-x 2 osamu osamu 4096 Apr  6 22:36 source
$ cat deb/fridge-1.0/debian/control
Source: fridge
Section: unknown
Priority: extra
Maintainer: Osamu Aoki <osamu@debian.org>
Build-Depends: debhelper (>= 8.0.0), python3-minimal, python3
Standards-Version: 3.9.3
X-Python3-Version: >= 3.1
Homepage: <insert the upstream URL, if relevant>
#Vcs-Git: git://git.debian.org/collab-maint/fridge.git
#Vcs-Browser: http://git.debian.org/?p=collab-maint/fridge.git;a=summary
Package: fridge
Architecture: all
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: <insert up to 60 chars description>
 <insert long description, indented with spaces>
$ cat deb/fridge-1.0/debian/rules
#!/usr/bin/make -f
#export DH_VERBOSE=1
ifeq ($(DH_VERBOSE),1)
    DH_VERBOSE_OPT = -ex
else
    DH_VERBOSE_OPT = -e
endif
PY3REQUESTED := $(shell py3versions -r)
PY3DEFAULT := $(shell py3versions -d)
PYTHON3 := $(filter-out $(PY3DEFAULT),$(PY3REQUESTED)) python3
%:
    dh $@ --with python3
override_dh_auto_clean:
    rm -rf build
override_dh_auto_build:
    set $(DH_VERBOSE_OPT); for python in $(PYTHON3); do \
        $$python setup.py build; \
    done
# use fridge instead of tmp since it is single binary package
override_dh_auto_install:
    set $(DH_VERBOSE_OPT); for python in $(PYTHON3); do \
        $$python setup.py install --root=debian/fridge --install-layout=deb; \
    done
Here, I am working around lack of Python3 support
(#538978 and
#597105 bugs) by debhelper using the
customized build script debian/rules following
http://developer.ubuntu.com/packaging/html/python-packaging.html[Ubuntu
documentation on “Packaging Python modules and applications”]
Let’s make Debian binary package.
$ cd deb/fridge-1.0; debuild -us -uc; cd -
/path/to/package2/deb/fridge-1.0
 dpkg-buildpackage -rfakeroot -D -us -uc -I -i
dpkg-buildpackage: source package fridge
dpkg-buildpackage: source version 1.0-1
dpkg-buildpackage: source distribution unstable
dpkg-buildpackage: source changed by Osamu Aoki <osamu@debian.org>
 dpkg-source -I -i --before-build fridge-1.0
dpkg-buildpackage: host architecture amd64
 fakeroot debian/rules clean
dh clean --with python3
   dh_testdir
   debian/rules override_dh_auto_clean
make[1]: Entering directory `/path/to/package2/deb/fridge-1.0'
rm -rf build
make[1]: Leaving directory `/path/to/package2/deb/fridge-1.0'
   dh_clean
 dpkg-source -I -i -b fridge-1.0
dpkg-source: info: using source format `3.0 (quilt)'
dpkg-source: info: building fridge using existing ./fridge_1.0.orig.tar.xz
dpkg-source: info: building fridge in fridge_1.0-1.debian.tar.gz
dpkg-source: info: building fridge in fridge_1.0-1.dsc
 debian/rules build
dh build --with python3
   dh_testdir
   dh_auto_configure
   debian/rules override_dh_auto_build
make[1]: Entering directory `/path/to/package2/deb/fridge-1.0'
set -e; for python in  python3; do \
        $python setup.py build; \
    done
running build
running build_py
creating build
creating build/lib
copying fridge.py -> build/lib
running build_scripts
creating build/scripts-3.3
copying and adjusting scripts/jane -> build/scripts-3.3
copying and adjusting scripts/joe -> build/scripts-3.3
copying and adjusting scripts/tom -> build/scripts-3.3
changing mode of build/scripts-3.3/jane from 644 to 755
changing mode of build/scripts-3.3/joe from 644 to 755
changing mode of build/scripts-3.3/tom from 644 to 755
make[1]: Leaving directory `/path/to/package2/deb/fridge-1.0'
   dh_auto_test
 fakeroot debian/rules binary
dh binary --with python3
   dh_testroot
   dh_prep
   debian/rules override_dh_auto_install
make[1]: Entering directory `/path/to/package2/deb/fridge-1.0'
set -e; for python in  python3; do \
        $python setup.py install --root=debian/fridge --install-layout=deb; \
    done
running install
running build
running build_py
running build_scripts
running install_lib
creating debian/fridge
creating debian/fridge/usr
creating debian/fridge/usr/lib
creating debian/fridge/usr/lib/python3
creating debian/fridge/usr/lib/python3/dist-packages
copying build/lib/fridge.py -> debian/fridge/usr/lib/python3/dist-packages
byte-compiling debian/fridge/usr/lib/python3/dist-packages/fridge.py to fridge.cp...
running install_scripts
creating debian/fridge/usr/bin
copying build/scripts-3.3/jane -> debian/fridge/usr/bin
copying build/scripts-3.3/joe -> debian/fridge/usr/bin
copying build/scripts-3.3/tom -> debian/fridge/usr/bin
changing mode of debian/fridge/usr/bin/jane to 755
changing mode of debian/fridge/usr/bin/joe to 755
changing mode of debian/fridge/usr/bin/tom to 755
running install_egg_info
Writing debian/fridge/usr/lib/python3/dist-packages/fridge-1.0.egg-info
make[1]: Leaving directory `/path/to/package2/deb/fridge-1.0'
   dh_installdocs
   dh_installchangelogs
   dh_pysupport
dh_pysupport: This program is deprecated, you should use dh_python2 instead. Migr...
   dh_python3
   dh_perl
   dh_link
   dh_compress
   dh_fixperms
   dh_installdeb
   dh_gencontrol
dpkg-gencontrol: warning: Depends field of package fridge: unknown substitution v...
dpkg-gencontrol: warning: package fridge: unused substitution variable ${python3:...
   dh_md5sums
   dh_builddeb
dpkg-deb: building package `fridge' in `../fridge_1.0-1_all.deb'.
 dpkg-genchanges  >../fridge_1.0-1_amd64.changes
dpkg-genchanges: including full source code in upload
 dpkg-source -I -i --after-build fridge-1.0
dpkg-buildpackage: full upload (original source is included)
Now running lintian...
W: fridge source: superfluous-clutter-in-homepage <insert the upstream URL, if re...
N:
N:    The "Homepage:" field in this package's control file contains
N:    superfluous markup around the URL, like enclosing < and >. This is
N:    unnecessary and needlessly complicates using this information.
N:
N:    Refer to Debian Policy Manual section 5.6.23 (Homepage) for details.
N:
N:    Severity: normal, Certainty: certain
N:
N:    Check: fields, Type: binary, udeb, source
N:
W: fridge source: bad-homepage <insert the upstream URL, if relevant>
N:
N:    The "Homepage:" field in this package's control file does not contain a
N:    valid absolute URL. Most probably you forgot to specify the scheme (e.g.
N:    http).
N:
N:    This tag is also triggered if the scheme is not known by Lintian.
N:
N:    Please file a bug against Lintian, if this tag is triggered for a valid
N:    homepage URL.
N:
N:    Severity: normal, Certainty: certain
N:
N:    Check: fields, Type: binary, udeb, source
N:
W: fridge source: out-of-date-standards-version 3.9.3 (current is 3.9.4)
N:
N:    The source package refers to a Standards-Version older than the one that
N:    was current at the time the package was created (according to the
N:    timestamp of the latest debian/changelog entry). Please consider
N:    updating the package to current Policy and setting this control field
N:    appropriately.
N:
N:    If the package is already compliant with the current standards, you
N:    don't have to re-upload the package just to adjust the Standards-Version
N:    control field. However, please remember to update this field next time
N:    you upload the package.
N:
N:    See /usr/share/doc/debian-policy/upgrading-checklist.txt.gz in the
N:    debian-policy package for a summary of changes in newer versions of
N:    Policy.
N:
N:    Refer to http://www.debian.org/doc/debian-policy/upgrading-checklist for
N:    details.
N:
N:    Severity: normal, Certainty: certain
N:
N:    Check: standards-version, Type: source
N:
W: fridge: wrong-bug-number-in-closes l3:#nnnn
N:
N:    Bug numbers can only contain digits.
N:
N:    Refer to Debian Policy Manual section 4.4 (Debian changelog:
N:    debian/changelog) for details.
N:
N:    Severity: normal, Certainty: certain
N:
N:    Check: changelog-file, Type: binary
N:
W: fridge: new-package-should-close-itp-bug
N:
N:    This package appears to be the first packaging of a new upstream
N:    software package (there is only one changelog entry and the Debian
N:    revision is 1), but it does not close any bugs. The initial upload of a
N:    new package should close the corresponding ITP bug for that package.
N:
N:    This warning can be ignored if the package is not intended for Debian or
N:    if it is a split of an existing Debian package.
N:
N:    Refer to Debian Developer's Reference section 5.1 (New packages) for
N:    details.
N:
N:    Severity: normal, Certainty: certain
N:
N:    Check: changelog-file, Type: binary
N:
E: fridge: helper-templates-in-copyright
N:
N:    The /usr/share/doc/<pkg>/copyright file still contains template markers
N:    from a packaging helper. Please fill in the actual license, upstream
N:    copyright holders, and download information about the package and remove
N:    any remaining templates generated by the packaging helper.
N:
N:    Severity: important, Certainty: certain
N:
N:    Check: copyright-file, Type: binary
N:
W: fridge: copyright-has-url-from-dh_make-boilerplate
N:
N:    There is "url://example.com" in your copyright file. This was most
N:    likely a remnant from the dh_make template.
N:
N:    Make sure you include the real location where you obtained the upstream
N:    sources (if any).
N:
N:    Refer to Debian Policy Manual section 12.5 (Copyright information) for
N:    details.
N:
N:    Severity: normal, Certainty: certain
N:
N:    Check: copyright-file, Type: binary
N:
E: fridge: copyright-contains-dh_make-todo-boilerplate
N:
N:    The string "Please also look if..." appears in the copyright file, which
N:    indicates that you either didn't check the whole source to find
N:    additional copyright/license, or that you didn't remove that paragraph
N:    after having done so.
N:
N:    Refer to Debian Policy Manual section 12.5 (Copyright information) for
N:    details.
N:
N:    Severity: serious, Certainty: possible
N:
N:    Check: copyright-file, Type: binary
N:
E: fridge: description-is-dh_make-template
N:
N:    The synopsis or the extended description has not been changed from the
N:    template provided by dh_make.
N:
N:    Severity: serious, Certainty: certain
N:
N:    Check: description, Type: binary, udeb
N:
E: fridge: section-is-dh_make-template
N:
N:    The "Section:" field in this package's control file is set to unknown.
N:    This is not a valid section, and usually means a dh_make template
N:    control file was used and never modified to set the correct section.
N:
N:    Refer to Debian Policy Manual section 2.4 (Sections) for details.
N:
N:    Severity: serious, Certainty: certain
N:
N:    Check: fields, Type: binary, udeb, source
N:
W: fridge: superfluous-clutter-in-homepage <insert the upstream URL, if relevant>...
W: fridge: bad-homepage <insert the upstream URL, if relevant>
W: fridge: binary-without-manpage usr/bin/jane
N:
N:    Each binary in /usr/bin, /usr/sbin, /bin, /sbin or /usr/games should
N:    have a manual page
N:
N:    Note that though the man program has the capability to check for several
N:    program names in the NAMES section, each of these programs should have
N:    its own manual page (a symbolic link to the appropriate manual page is
N:    sufficient) because other manual page viewers such as xman or tkman
N:    don't support this.
N:
N:    If the name of the man page differs from the binary by case, man may be
N:    able to find it anyway; however, it is still best practice to make the
N:    case of the man page match the case of the binary.
N:
N:    If the man pages are provided by another package on which this package
N:    depends, lintian may not be able to determine that man pages are
N:    available. In this case, after confirming that all binaries do have man
N:    pages after this package and its dependencies are installed, please add
N:    a lintian override.
N:
N:    Refer to Debian Policy Manual section 12.1 (Manual pages) for details.
N:
N:    Severity: normal, Certainty: possible
N:
N:    Check: manpages, Type: binary
N:
W: fridge: binary-without-manpage usr/bin/joe
W: fridge: binary-without-manpage usr/bin/tom
E: fridge: python-script-but-no-python-dep usr/bin/jane
N:
N:    Packages with Python scripts should depend on the package python. Those
N:    with scripts that specify a specific version of Python must depend on
N:    that version of Python (exactly).
N:
N:    For example, if a script in the package uses #!/usr/bin/python, the
N:    package needs a dependency on python. If a script uses
N:    #!/usr/bin/python2.6, the package needs a dependency on python2.6. A
N:    dependency on python (>= 2.6) is not correct, since later versions of
N:    Python may not provide the /usr/bin/python2.6 binary.
N:
N:    If you are using debhelper, adding ${python:Depends} to the Depends
N:    field and ensuring dh_pysupport or dh_pycentral are run during the build
N:    should take care of adding the correct dependency.
N:
N:    In some cases a weaker relationship, such as Suggests or Recommends,
N:    will be more appropriate.
N:
N:    Severity: important, Certainty: certain
N:
N:    Check: scripts, Type: binary
N:
E: fridge: python-script-but-no-python-dep usr/bin/joe
E: fridge: python-script-but-no-python-dep usr/bin/tom
Finished running lintian.
/path/to/package2
$ ls -l deb
total 36
drwxrwxr-x 5 osamu osamu  4096 Aug 17 23:43 fridge-1.0
-rw-r--r-- 1 osamu osamu  3254 Aug 17 23:43 fridge_1.0-1_all.deb
-rw-r--r-- 1 osamu osamu 11805 Aug 17 23:43 fridge_1.0-1_amd64.build
-rw-r--r-- 1 osamu osamu  1419 Aug 17 23:43 fridge_1.0-1_amd64.changes
-rw-r--r-- 1 osamu osamu  2265 Aug 17 23:43 fridge_1.0-1.debian.tar.gz
-rw-r--r-- 1 osamu osamu   810 Aug 17 23:43 fridge_1.0-1.dsc
-rw-rw-r-- 1 osamu osamu  1212 Aug 17 23:43 fridge_1.0.orig.tar.xz
$ dpkg -c deb/fridge_1.0-1_all.deb
drwxr-xr-x root/root         0 2013-08-17 23:43 ./
drwxr-xr-x root/root         0 2013-08-17 23:43 ./usr/
drwxr-xr-x root/root         0 2013-08-17 23:43 ./usr/lib/
drwxr-xr-x root/root         0 2013-08-17 23:43 ./usr/lib/python3/
drwxr-xr-x root/root         0 2013-08-17 23:43 ./usr/lib/python3/dist-packages/
-rw-r--r-- root/root       233 2013-08-17 23:43 ./usr/lib/python3/dist-packages/f...
-rw-r--r-- root/root      1586 2013-08-17 23:43 ./usr/lib/python3/dist-packages/f...
drwxr-xr-x root/root         0 2013-08-17 23:43 ./usr/bin/
-rwxr-xr-x root/root       124 2013-08-17 23:43 ./usr/bin/jane
-rwxr-xr-x root/root        93 2013-08-17 23:43 ./usr/bin/joe
-rwxr-xr-x root/root        81 2013-08-17 23:43 ./usr/bin/tom
drwxr-xr-x root/root         0 2013-08-17 23:43 ./usr/share/
drwxr-xr-x root/root         0 2013-08-17 23:43 ./usr/share/doc/
drwxr-xr-x root/root         0 2013-08-17 23:43 ./usr/share/doc/fridge/
-rw-r--r-- root/root      1668 2013-04-06 22:36 ./usr/share/doc/fridge/copyright
-rw-r--r-- root/root       120 2013-04-06 23:03 ./usr/share/doc/fridge/README.Deb...
-rw-r--r-- root/root       172 2013-04-06 22:36 ./usr/share/doc/fridge/changelog....
Now we have Debian package fridge_1.0-1_all.deb which can be installed and removed easily.
Debian package from Python2 source distribution (debmake)
The debmake is even more handier for making a Debian package.  I will be very sloppy for now as well.  (More work is needed to make package suitable for Debian.)
Let’s make Debian source package.
$ cd fridge; debmake -d -u 1.0 -b :python; cd -
/path/to/package1/fridge
running sdist
running check
warning: sdist: manifest template 'MANIFEST.in' does not exist (using default fil...
writing manifest file 'MANIFEST'
creating fridge-1.0
creating fridge-1.0/scripts
making hard links in fridge-1.0...
hard linking README -> fridge-1.0
hard linking fridge.py -> fridge-1.0
hard linking setup.py -> fridge-1.0
hard linking scripts/jane -> fridge-1.0/scripts
hard linking scripts/joe -> fridge-1.0/scripts
hard linking scripts/tom -> fridge-1.0/scripts
Creating tar archive
removing 'fridge-1.0' (and everything under it)
fridge-1.0/
fridge-1.0/scripts/
fridge-1.0/scripts/jane
fridge-1.0/scripts/joe
fridge-1.0/scripts/tom
fridge-1.0/fridge.py
fridge-1.0/PKG-INFO
fridge-1.0/setup.py
fridge-1.0/README
I: sanity check of parameters
I: process "make dist" equivalent
I: pwd = /path/to/package1/fridge
I: setup.py (Python): sdist
I:  tar-ball made
I: pwd = /path/to/package1
I: create symlink at /path/to/package1/fridge_1.0.orig.tar.gz pointing to fridge/...
I: process untar
I: run "tar -xvzf fridge_1.0.orig.tar.gz".
I: untared.
I: pwd = /path/to/package1/fridge-1.0
I: analyze source
I: generate debian/*
I: File written: debian/source/format
I: File written: debian/source/local-options
I: File written: debian/patches/series
I: File written: debian/compat
I: File written: debian/rules
I: File written: debian/README.Debian
I: File written: debian/changelog
I: File written: debian/copyright
I: File written: debian/control
I: File written: debian/fridge.install
I: run "debmake -x" to get more template files
I: upon return to the shell, current directory becomes /path/to/package1/fridge
I: please execute "cd /path/to/package1/fridge-1.0"
I: before building binary package with dpkg-buildpackage (or debuild, pdebuild, s...
/path/to/package1
$ ls -lR fridge-1.0
fridge-1.0:
total 24
drwxrwxr-x 4 osamu osamu 4096 Aug 17 23:43 debian
-rw-r--r-- 1 osamu osamu 1579 Apr  8 21:16 fridge.py
-rw-rw-r-- 1 osamu osamu  233 Aug 17 23:43 PKG-INFO
-rw-rw-r-- 1 osamu osamu   31 Mar 28 22:17 README
drwxrwxr-x 2 osamu osamu 4096 Aug 17 23:43 scripts
-rwxr-xr-x 1 osamu osamu  361 Apr  8 21:13 setup.py
fridge-1.0/debian:
total 36
-rw-rw-r-- 1 osamu osamu  185 Aug 17 23:43 changelog
-rw-rw-r-- 1 osamu osamu    2 Aug 17 23:43 compat
-rw-rw-r-- 1 osamu osamu  737 Aug 17 23:43 control
-rw-rw-r-- 1 osamu osamu 1025 Aug 17 23:43 copyright
-rw-rw-r-- 1 osamu osamu    1 Aug 17 23:43 fridge.install
drwxrwxr-x 2 osamu osamu 4096 Aug 17 23:43 patches
-rw-rw-r-- 1 osamu osamu  255 Aug 17 23:43 README.Debian
-rwxr-xr-x 1 osamu osamu  219 Aug 17 23:43 rules
drwxrwxr-x 2 osamu osamu 4096 Aug 17 23:43 source
fridge-1.0/debian/patches:
total 4
-rw-rw-r-- 1 osamu osamu 211 Aug 17 23:43 series
fridge-1.0/debian/source:
total 8
-rw-rw-r-- 1 osamu osamu  12 Aug 17 23:43 format
-rw-rw-r-- 1 osamu osamu 123 Aug 17 23:43 local-options
fridge-1.0/scripts:
total 12
-rw-r--r-- 1 osamu osamu 124 Apr  6 18:14 jane
-rw-r--r-- 1 osamu osamu  93 Mar 28 20:18 joe
-rw-r--r-- 1 osamu osamu  81 Mar 28 20:19 tom
$ cat fridge-1.0/debian/control
Source: fridge
Section: unknown
Priority: extra
Maintainer: Osamu Aoki <osamu@debian.org>
Build-Depends: python-all,
    debhelper (>=9)
Standards-Version: 3.9.4
Homepage: <insert the upstream URL, if relevant>
Vcs-Git: git://git.debian.org/collab-maint/fridge.git
Vcs-Browser: http://git.debian.org/?p=collab-maint/fridge.git
X-Python-Version: >= 2.6
Package: fridge
Architecture: all
Multi-Arch: foreign
Pre-Depends: ${misc:Pre-Depends}
Depends: ${misc:Depends},
    ${python:Depends}
Description: <insert up to 60 chars description>
 <insert long description, indented with spaces>
 <continued long description lines ...>
 .
 <continued long description line after a line break indicated by " .">
 <continued long description lines ...>
$ cat fridge-1.0/debian/rules
#!/usr/bin/make -f
# uncomment to enable verbose mode for debhelper
#DH_VERBOSE = 1
# uncomment to exclude VCS paths
#DH_ALWAYS_EXCLUDE=CVS:.svn:.git
%:
    dh $@ --with "python2"
# Customize by adding override scripts
Now we have Debian package fridge_1.0-1_all.deb which can be installed and removed easily.
Debian package from Python3 source distribution (debmake)
Let’s do the same for Python3 (The debmake does hard work for you).
Let’s make Debian source package.
$ cd fridge; debmake -d -u 1.0 -b :python; cd -
/path/to/package2/fridge
running sdist
running check
warning: sdist: manifest template 'MANIFEST.in' does not exist (using default fil...
writing manifest file 'MANIFEST'
creating fridge-1.0
creating fridge-1.0/scripts
making hard links in fridge-1.0...
hard linking README -> fridge-1.0
hard linking fridge.py -> fridge-1.0
hard linking setup.py -> fridge-1.0
hard linking scripts/jane -> fridge-1.0/scripts
hard linking scripts/joe -> fridge-1.0/scripts
hard linking scripts/tom -> fridge-1.0/scripts
Creating tar archive
removing 'fridge-1.0' (and everything under it)
fridge-1.0/
fridge-1.0/scripts/
fridge-1.0/scripts/jane
fridge-1.0/scripts/joe
fridge-1.0/scripts/tom
fridge-1.0/fridge.py
fridge-1.0/PKG-INFO
fridge-1.0/setup.py
fridge-1.0/README
I: sanity check of parameters
I: process "make dist" equivalent
I: pwd = /path/to/package2/fridge
I: setup.py (Python3): sdist
I:  tar-ball made
I: pwd = /path/to/package2
I: create symlink at /path/to/package2/fridge_1.0.orig.tar.gz pointing to fridge/...
I: process untar
I: run "tar -xvzf fridge_1.0.orig.tar.gz".
I: untared.
I: pwd = /path/to/package2/fridge-1.0
I: analyze source
I: generate debian/*
I: File written: debian/source/format
I: File written: debian/source/local-options
I: File written: debian/patches/series
I: File written: debian/compat
I: File written: debian/rules
I: File written: debian/README.Debian
I: File written: debian/changelog
I: File written: debian/copyright
I: File written: debian/control
I: File written: debian/fridge.install
I: run "debmake -x" to get more template files
I: upon return to the shell, current directory becomes /path/to/package2/fridge
I: please execute "cd /path/to/package2/fridge-1.0"
I: before building binary package with dpkg-buildpackage (or debuild, pdebuild, s...
/path/to/package2
$ ls -lR fridge-1.0
fridge-1.0:
total 24
drwxrwxr-x 4 osamu osamu 4096 Aug 17 23:43 debian
-rw-r--r-- 1 osamu osamu 1586 Aug 17 23:43 fridge.py
-rw-rw-r-- 1 osamu osamu  233 Aug 17 23:43 PKG-INFO
-rw-rw-r-- 1 osamu osamu   31 Mar 28 22:17 README
drwxrwxr-x 2 osamu osamu 4096 Aug 17 23:43 scripts
-rwxr-xr-x 1 osamu osamu  362 Apr  5 23:58 setup.py
fridge-1.0/debian:
total 36
-rw-rw-r-- 1 osamu osamu  185 Aug 17 23:43 changelog
-rw-rw-r-- 1 osamu osamu    2 Aug 17 23:43 compat
-rw-rw-r-- 1 osamu osamu  764 Aug 17 23:43 control
-rw-rw-r-- 1 osamu osamu 1025 Aug 17 23:43 copyright
-rw-rw-r-- 1 osamu osamu    1 Aug 17 23:43 fridge.install
drwxrwxr-x 2 osamu osamu 4096 Aug 17 23:43 patches
-rw-rw-r-- 1 osamu osamu  255 Aug 17 23:43 README.Debian
-rwxr-xr-x 1 osamu osamu  763 Aug 17 23:43 rules
drwxrwxr-x 2 osamu osamu 4096 Aug 17 23:43 source
fridge-1.0/debian/patches:
total 4
-rw-rw-r-- 1 osamu osamu 211 Aug 17 23:43 series
fridge-1.0/debian/source:
total 8
-rw-rw-r-- 1 osamu osamu  12 Aug 17 23:43 format
-rw-rw-r-- 1 osamu osamu 123 Aug 17 23:43 local-options
fridge-1.0/scripts:
total 12
-rw-r--r-- 1 osamu osamu 124 Apr  6 18:14 jane
-rw-r--r-- 1 osamu osamu  93 Mar 28 20:18 joe
-rw-r--r-- 1 osamu osamu  81 Mar 28 20:19 tom
$ cat fridge-1.0/debian/control
Source: fridge
Section: unknown
Priority: extra
Maintainer: Osamu Aoki <osamu@debian.org>
Build-Depends: debhelper (>=9),
    python3-all
Standards-Version: 3.9.4
Homepage: <insert the upstream URL, if relevant>
Vcs-Git: git://git.debian.org/collab-maint/fridge.git
Vcs-Browser: http://git.debian.org/?p=collab-maint/fridge.git
X-Python-Version: >= 2.6
X-Python3-Version: >= 3.2
Package: fridge
Architecture: all
Multi-Arch: foreign
Pre-Depends: ${misc:Pre-Depends}
Depends: ${misc:Depends},
    ${python:Depends}
Description: <insert up to 60 chars description>
 <insert long description, indented with spaces>
 <continued long description lines ...>
 .
 <continued long description line after a line break indicated by " .">
 <continued long description lines ...>
$ cat fridge-1.0/debian/rules
#!/usr/bin/make -f
# uncomment to enable verbose mode for debhelper
#DH_VERBOSE = 1
# uncomment to exclude VCS paths
#DH_ALWAYS_EXCLUDE=CVS:.svn:.git
%:
    dh $@ --with "python2,python3"
# special work around for python3 (#538978 and #597105 bugs)
PY3REQUESTED := $(shell py3versions -r)
PY3DEFAULT := $(shell py3versions -d)
PYTHON3 := $(filter-out $(PY3DEFAULT),$(PY3REQUESTED)) python3
override_dh_auto_clean:
    -rm -rf build
override_dh_auto_build:
    set -ex; for python in $(PYTHON3); do \
        $$python setup.py build; \
    done
override_dh_auto_install:
    set -ex; for python in $(PYTHON3); do \
        $$python setup.py install \
            --root=debian/fridge\
            --force\
            --install-layout=deb; \
    done
# Customize by adding override scripts
Now we have Debian package fridge_1.0-1_all.deb which can be installed and removed easily.
Python + C
For non-trivial tasks, it is good idea to write major parts of the program in some high level programing language such as Python using modules, with some mission-critical small parts of the program as Python modules written in C (or in any compiled languages) for speed.
There are several approaches to mix Python and C/C++ code.
- ctypes:
- ctypes can use existing C libraries as a Python extension module without compilation.
 - You need to understand how C works to use this.
 - This is not as fast as other methods but is easier to use.
 
 - Python support of SWIG:
- SWIG is a specialized compiler that transforms
ANSI C/C++ declarations into scripting language extension wrappers.
- The interface file “*.i” wraps ANSI C/C++ declarations.
 - Python is one of many scripting languages supported by SWIG.
 
 - You need to understand how C/C++ works to use this.
 - This is good if you have many libraries to be wrapped.
 
 - SWIG is a specialized compiler that transforms
ANSI C/C++ declarations into scripting language extension wrappers.
 - PyGObject
- This is basically for GNOME3 (see PyGObject).
 - PyGObject binds GObject as Python extension module using GObject Introspection with a “*.gir” file.
 - GObject Introspection provides tighter binding than SWIG.
 
 - Cython:
 - Python/C API:
- A custom C/C++ code with the header 
#include "Python.h"can access the native Python/C API. - You need to understand how C/C++ works to use this.
 - You need to understand how the Python Interpreter works to use this.
 - This enables both extending and embedding of the Python Interpreter.
 
 - A custom C/C++ code with the header 
 
| Previous Post | Top | Next Post |