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
print
as 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
.py
file.
- 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
.so
file. - 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__.py
files.
- 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
foo
module 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
import
statement.- “
import foo
” imports the Python codefoo.py
found in the Python module search path. - “
import foo
” imports the compiled C codefoo.so
found 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
PYTHONPATH
environment 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
PYTHONPATH
environment variable.- colon (":") separated on Unix-like systems (defined in
.bashrc
etc.) - 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
*.pth
files (if present)/usr/lib/python2.7/dist-packages/PIL.pth
containingPIL
to 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
foo
accesses the module filefoo/__init__.py
. - The module name
foo.bar
accesses the module filefoo/bar.py
. - The module name
foo.baz
accesses the module filefoo/baz/__init__.py
. - The module name
foo.baz.qux
accesses the module filefoo/baz/qux.py
.
- The module name
- “
import foo
” imports the entire Python module packagefoo
including all submodules. - The Python module
*.py
in the above may alternatively be the shared libraries*.so
following 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 theobj
instance isint
or some class derived fromint
.
issubclass()
- issubclass(bool, int) is True since
bool
is a subclass ofint
. - issubclass(float, int) is False since
float
is 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
Base1
class - attributes found in recursively in the base classes of
Base1
- attributes found in
Base2
class - …
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
classname
or_classname
:- Replace
__spam
with_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 modulefridge
to 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-INFO
indist/fridge-1.0.tar.gz
: Metadata for Python source distribution package generated from thesetup.py
file.
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 modulefridge
to 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-INFO
indist/fridge-1.0.tar.gz
: Metadata for Python source distribution package generated from thesetup.py
file.
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 |