{"id":9418,"date":"2019-04-19T15:13:17","date_gmt":"2019-04-19T13:13:17","guid":{"rendered":"https:\/\/pi3g.com\/?p=9418"},"modified":"2019-04-19T15:13:17","modified_gmt":"2019-04-19T13:13:17","slug":"packaging-python-projects-for-debian-raspbian-with-dh-virtualenv","status":"publish","type":"post","link":"https:\/\/pi3g.com\/de\/packaging-python-projects-for-debian-raspbian-with-dh-virtualenv\/","title":{"rendered":"Paketierung von Python-Projekten f\u00fcr Debian \/ Raspbian mit dh-virtualenv"},"content":{"rendered":"<p>This article aims to explain some things to developers which don\u2019t use Python a lot, and might struggle with some of the concepts otherwise.<\/p>\n<p>I highly recommend the lecture of the following article as an introduction to the concepts discussed here:<\/p>\n<ul>\n<li><a href=\"https:\/\/www.dabapps.com\/blog\/introduction-to-pip-and-virtualenv-python\/\">https:\/\/www.dabapps.com\/blog\/introduction-to-pip-and-virtualenv-python\/<\/a><\/li>\n<\/ul>\n<h2>pypi.org<\/h2>\n<p><a href=\"https:\/\/pypi.org\/\" target=\"_blank\">pypi.org<\/a> is an official repository of software for the Python programming language. It includes libraries we want to use in our projects, which are not shipped by default with Python.<\/p>\n<p><\/p>\n<h2>The problem <\/h2>\n<p>Our goal is to package an application written in Python (targetting Python3) as a .deb package for Raspbian (which is, all things considered, really equivalent to Debian). <\/p>\n<p>Our application has dependencies on several Python libraries. <\/p>\n<p>For instance, we would like to use the <a href=\"http:\/\/docs.python-requests.org\/en\/master\/\" target=\"_blank\"><strong>requests<\/strong><\/a><strong> <\/strong>library. The requests library itself depends on other libraries, e.g. chardet, urllib3, etc.<\/p>\n<p>Manually managing these dependencies and manually shipping the required library code is inherently impractical.<\/p>\n<h2>pip<\/h2>\n<p>Python has it\u2019s own package \/ dependency management system, called <strong>pip<\/strong><\/p>\n<p>pip allows you to install python libraries and applications, so that your own code can use these libraries.<\/p>\n<p>Here there are two problems:<\/p>\n<ul>\n<li>we want to ship the package as a <strong>Debian package<\/strong>, for end users to install easily. We can safely assume that on a significant number of target systems the appropriate python libraries will not have been installed by the user<\/li>\n<li>if we try to install these libraries <strong>system-wide on behalf of the user<\/strong>, we might break compatibility with some other packages (e.g. because of API changes in between versions of the libraries)<\/li>\n<\/ul>\n<p>Therefore we need a solution. <\/p>\n<h2>virtualenv<\/h2>\n<p>virtualenv will allow us to create virtual environments for Python. <\/p>\n<p>In these virtual environments we have:<\/p>\n<ul>\n<li>our own Python interpreter<\/li>\n<li>copies of the required standard libraries<\/li>\n<li>our own pip<\/li>\n<li>our own \u201csystem-wide\u201d library<\/li>\n<\/ul>\n<h3>Practical part: Trying out virtualenv<\/h3>\n<p>Install virtualenv (as part of dh-virtualenv, which we will get to in a little while) by doing:<\/p>\n<blockquote>\n<p>sudo apt install dh-virtualenv<\/p>\n<\/blockquote>\n<p>As requests is already installed system-wide on my test box, we will use a different package as an example. <a href=\"https:\/\/pypi.org\/project\/randstr\/\" target=\"_blank\">randstr<\/a> will allow you to generate a random string.<\/p>\n<p>Check if <strong>randstr <\/strong>is installed system-wide:<\/p>\n<blockquote>\n<p>pip3 show randstr<\/p>\n<\/blockquote>\n<p>This should return nothing. Indicating that this package is not installed systemwide:<\/p>\n<p><a href=\"https:\/\/pi3g.com\/wp-content\/uploads\/2019\/04\/image-17.png\"><img loading=\"lazy\" decoding=\"async\" width=\"703\" height=\"77\" title=\"image\" style=\"display: inline; background-image: none;\" alt=\"image\" src=\"https:\/\/pi3g.com\/wp-content\/uploads\/2019\/04\/image_thumb-17.png\" border=\"0\"><\/a><\/p>\n<p>Now we will create a virtual environment. The virtual environment folder does NOT have to live inside your code folder, but it can. You should ignore it in GIT.<\/p>\n<p>let\u2019s say we have a directory \/home\/pi\/tutorial <\/p>\n<p>Change into this directory, and create a new environment folder env:<\/p>\n<blockquote>\n<p>cd \/home\/pi\/tutorial<\/p>\n<p>which python3<\/p>\n<p>virtualenv -p \/usr\/bin\/python3 env<\/p>\n<\/blockquote>\n<p>Note: you should specify the Python interpreter if you want Python 3, as otherwise Python 2 will be used. I am using Python 3. (Running virtualenv with interpreter \/usr\/bin\/python2)<\/p>\n<p>which python3 will tell you where the python3 binary resides, adjust the path for virtualenv accordingly.<\/p>\n<p><a href=\"https:\/\/pi3g.com\/wp-content\/uploads\/2019\/04\/image-18.png\"><img loading=\"lazy\" decoding=\"async\" width=\"708\" height=\"139\" title=\"image\" style=\"display: inline; background-image: none;\" alt=\"image\" src=\"https:\/\/pi3g.com\/wp-content\/uploads\/2019\/04\/image_thumb-18.png\" border=\"0\"><\/a><\/p>\n<p>activate the environment:<\/p>\n<blockquote>\n<p>source env\/bin\/activate<\/p>\n<\/blockquote>\n<p>(This command path assumes that you stayed in the tutorial directory). Please also note, that this is not an executable script \u2013 you have to use <strong>source <\/strong>to use it with your bash terminal.<\/p>\n<p>Notice, how (env) is prepended before your command prompt:<\/p>\n<p><a href=\"https:\/\/pi3g.com\/wp-content\/uploads\/2019\/04\/image-19.png\"><img loading=\"lazy\" decoding=\"async\" width=\"707\" height=\"68\" title=\"image\" style=\"display: inline; background-image: none;\" alt=\"image\" src=\"https:\/\/pi3g.com\/wp-content\/uploads\/2019\/04\/image_thumb-19.png\" border=\"0\"><\/a><\/p>\n<p>This means that the environment is active. Now you can run pip3 again, but this time pip3 will perform it\u2019s work on the virtual environment:<\/p>\n<blockquote>\n<p>pip3 show randstr<\/p>\n<p>pip3 show requests<\/p>\n<\/blockquote>\n<p>should still yield nothing. The second line will also show nothing \u2013 showing that (if requests is installed system-wide) we are indeed in a virtual environment.<\/p>\n<p>Now install randstr:<\/p>\n<blockquote>\n<p>pip3 install randstr<\/p>\n<\/blockquote>\n<p>and check again, if it is installed:<\/p>\n<blockquote>\n<p>pip3 show randstr<\/p>\n<\/blockquote>\n<p><a href=\"https:\/\/pi3g.com\/wp-content\/uploads\/2019\/04\/image-20.png\"><img loading=\"lazy\" decoding=\"async\" width=\"705\" height=\"314\" title=\"image\" style=\"display: inline; background-image: none;\" alt=\"image\" src=\"https:\/\/pi3g.com\/wp-content\/uploads\/2019\/04\/image_thumb-20.png\" border=\"0\"><\/a><\/p>\n<p>This time it shows that randstr is installed. It has been installed into env\/lib\/python3.5\/site-packages:<\/p>\n<p><a href=\"https:\/\/pi3g.com\/wp-content\/uploads\/2019\/04\/image-21.png\"><img loading=\"lazy\" decoding=\"async\" width=\"709\" height=\"272\" title=\"image\" style=\"display: inline; background-image: none;\" alt=\"image\" src=\"https:\/\/pi3g.com\/wp-content\/uploads\/2019\/04\/image_thumb-21.png\" border=\"0\"><\/a><\/p>\n<p>While the environment ist still activated, let\u2019s write a small Python sample application:<\/p>\n<blockquote>\n<p>nano sample.py<\/p>\n<\/blockquote>\n<p>paste the following code, generating a random string using the new library we just installed:<\/p>\n<blockquote>\n<p>from randstr import randstr<br \/>\nprint(&#8220;hello world&#8221;)<br \/>\nprint(randstr())\n<\/p>\n<p><\/p>\n<\/blockquote>\n<p>and save.<\/p>\n<p>Run the code using python3:<\/p>\n<blockquote>\n<p>python3 sample.py<\/p>\n<\/blockquote>\n<p>while the environment is still active, this will work:<\/p>\n<p><a href=\"https:\/\/pi3g.com\/wp-content\/uploads\/2019\/04\/image-22.png\"><img loading=\"lazy\" decoding=\"async\" width=\"505\" height=\"69\" title=\"image\" style=\"display: inline; background-image: none;\" alt=\"image\" src=\"https:\/\/pi3g.com\/wp-content\/uploads\/2019\/04\/image_thumb-22.png\" border=\"0\"><\/a><\/p>\n<p>Now it\u2019s time to exit the environment, to see whether the code will still run:<\/p>\n<blockquote>\n<p>deactivate<\/p>\n<\/blockquote>\n<p>Your prompt will return back to normal. And<\/p>\n<blockquote>\n<p>python3 sample.py<\/p>\n<\/blockquote>\n<p>will throw an error message, about no module \u2018randstr\u2019 existing on your system. This is exactly the behaviour we want!<\/p>\n<p><a href=\"https:\/\/pi3g.com\/wp-content\/uploads\/2019\/04\/image-23.png\"><img loading=\"lazy\" decoding=\"async\" width=\"512\" height=\"127\" title=\"image\" style=\"display: inline; background-image: none;\" alt=\"image\" src=\"https:\/\/pi3g.com\/wp-content\/uploads\/2019\/04\/image_thumb-23.png\" border=\"0\"><\/a><\/p>\n<p>You can have a look at the env folder, seeing how it ships all the necessary things to run your Python code, including libraries, the python executable, pip, and more.<\/p>\n<h2>Debian virtualenv packaging with dh-virtualenv<\/h2>\n<p>OK, now with the basics out of the way, what we want is to package a virtualenv alongside with our code, so that our application will run reliably and without disturbing other applications on our user\u2019s computers.<\/p>\n<p>This is where <strong>dh-virtualenv <\/strong>enters the picture. dh-virtualenv is an addition to the Debian building scripts, which allows you to package virtual environments.<\/p>\n<p>We need to create a basic package structure for our new package. This is where <strong>cookiecutter <\/strong>will help.<\/p>\n<h2>cookiecutter<\/h2>\n<p>cookiecutter creates new projects for you from templates, thus reducing the overhead and time you spend on developing and getting your head around the many files which are required.<\/p>\n<p>https:\/\/cookiecutter.readthedocs.io\/en\/latest\/<\/p>\n<blockquote>\n<p>sudo apt install cookiecutter<\/p>\n<\/blockquote>\n<p>Note: the package python3-cookiecutter will provide a Python module for Python 3. What we want is the application itself, which is installed with the cookiecutter package as seen above. This might pull in Python 2, but \u2013 oh well.<\/p>\n<p>cookiecutter is not necessary for your end users, it is only used to create several files for your package.<\/p>\n<p>create an example project directory, into which we will apply the template (I am still in the tutorial directory):<\/p>\n<blockquote>\n<p>mkdir sampleproject<\/p>\n<p>cd sampleproject<\/p>\n<\/blockquote>\n<p>Using a special mold for dh-virtualenv we can set up many of the necessary files:<\/p>\n<p><a href=\"https:\/\/github.com\/Springerle\/dh-virtualenv-mold\">https:\/\/github.com\/Springerle\/dh-virtualenv-mold<\/a><\/p>\n<blockquote>\n<p>cookiecutter <a href=\"https:\/\/github.com\/Springerle\/dh-virtualenv-mold.git\">https:\/\/github.com\/Springerle\/dh-virtualenv-mold.git<\/a><\/p>\n<\/blockquote>\n<p>This will ask you several questions.<\/p>\n<p><a href=\"https:\/\/pi3g.com\/wp-content\/uploads\/2019\/04\/image-24.png\"><img loading=\"lazy\" decoding=\"async\" width=\"765\" height=\"160\" title=\"image\" style=\"display: inline; background-image: none;\" alt=\"image\" src=\"https:\/\/pi3g.com\/wp-content\/uploads\/2019\/04\/image_thumb-24.png\" border=\"0\"><\/a><\/p>\n<p>Note, that the folder should be named debian, even when packaging for Raspbian \u2013 therefore keep the name as debian. <\/p>\n<p>This will install the following files:<\/p>\n<p><a href=\"https:\/\/pi3g.com\/wp-content\/uploads\/2019\/04\/image-25.png\"><img loading=\"lazy\" decoding=\"async\" width=\"520\" height=\"398\" title=\"image\" style=\"display: inline; background-image: none;\" alt=\"image\" src=\"https:\/\/pi3g.com\/wp-content\/uploads\/2019\/04\/image_thumb-25.png\" border=\"0\"><\/a><\/p>\n<p>Now you need to run the following commands, as per the instructions under the dh-virtualenv-mold:<\/p>\n<blockquote>\n<pre>sudo apt-get install build-essential debhelper devscripts equivs<\/pre>\n<pre>sudo mk-build-deps --install debian\/control<\/pre>\n<\/blockquote>\n<pre><font face=\"Calibri\">To build the package later on, you will run the follwoing command from your project\u2019s top level directory:<\/font><\/pre>\n<blockquote>\n<pre>dpkg-buildpackage -uc -us \u2013b<\/pre>\n<\/blockquote>\n<pre><font face=\"Calibri\">Right now, though, the command will fail because setup.py is missing. We will get to setup.py and requirements.txt in a brief while:<\/font><\/pre>\n<blockquote>\n<pre>\/usr\/bin\/python3: can't open file 'setup.py': [Errno 2] No such file or directory<\/pre>\n<\/blockquote>\n<h2>Information about the individual files<\/h2>\n<h3>changelog<\/h3>\n<p>This file will contain your release and version information for the package. You can update it using a special tool, <strong>dch<\/strong>.<\/p>\n<p>This file is not a changelog for your application, but just a changelog for the packing of your application.<\/p>\n<h3>compat<\/h3>\n<p>This file includes a special magic number \u201c9\u201d. (for compatibility issues, it\u2019s fine to leave it as it is)<\/p>\n<h3>control<\/h3>\n<p>This is the main file to set package settings, and dependencies on a Debian level. If your application depends, for example, on the omxplayer being installed, it will need to go in here as a dependency:<\/p>\n<p><em>Source: sampleproject<br \/>\nSection: contrib\/python<br \/>\nPriority: extra<br \/>\nMaintainer: Maximilian Batz &lt;???&gt;<br \/>\nBuild-Depends: debhelper (&gt;= 9), python, python-dev, dh-virtualenv (&gt;= 0.10), tar<br \/>\nStandards-Version: 3.9.5<br \/>\nHomepage: <\/em><a href=\"https:\/\/picockpit.com\"><em>https:\/\/picockpit.com<\/em><\/a><\/p>\n<p><em><br \/>\n<\/em><\/p>\n<p><em>Package: sampleproject<br \/>\nArchitecture: any<br \/>\nPre-Depends: dpkg (&gt;= 1.16.1), python2.7 | python3, ${misc:Pre-Depends}<br \/>\nDepends: ${python:Depends}, ${misc:Depends}<br \/>\nDescription: An example package to demonstrate virtualenv Debian packaging with dh-virtualenv<br \/>&nbsp;&nbsp;&nbsp;&nbsp; .<br \/>&nbsp;&nbsp;&nbsp;&nbsp; This is a distribution of &#8220;sampleproject&#8221; as a self-contained<br \/>&nbsp;&nbsp;&nbsp;&nbsp; Python virtualenv wrapped into a Debian package (&#8220;omnibus&#8221; package,<br \/>&nbsp;&nbsp;&nbsp;&nbsp; all passengers on board). The packaged virtualenv is kept in sync with<br \/>&nbsp;&nbsp;&nbsp;&nbsp; the host&#8217;s interpreter automatically.<br \/>&nbsp;&nbsp;&nbsp;&nbsp; .<br \/>&nbsp;&nbsp;&nbsp;&nbsp; See <\/em><a href=\"https:\/\/github.com\/spotify\/dh-virtualenv\"><em>https:\/\/github.com\/spotify\/dh-virtualenv<\/em><\/a><em> for more details.<\/em><\/p>\n<p>You will also want to edit the long Description.<\/p>\n<h3>cookiecutter.json<\/h3>\n<p>Includes your initial settings. Not required for packaging.<\/p>\n<h3>copyright<\/h3>\n<p>Your copyright file, with your license (e.g. MIT). It\u2019s pre-filled with your name, year, e-Mail and \u201csome rights reserved\u201d.<\/p>\n<h3>rules<\/h3>\n<p>This is a Makefile, to actually build your package. It is prefilled by the cookiecutter template.<\/p>\n<h3>sampleproject.links<\/h3>\n<p>This file allows you to create links during installation . The filename will include your project name instead of <strong>sampleproject<\/strong>.<\/p>\n<p>Ref: <a href=\"https:\/\/stackoverflow.com\/questions\/9965717\/debian-rules-file-make-a-symlink\">https:\/\/stackoverflow.com\/questions\/9965717\/debian-rules-file-make-a-symlink<\/a><\/p>\n<h3>sampleproject.postinst<\/h3>\n<p>This file allows you to run additional setup steps after installation (e.g. activating your python script as a service). The filename will include your project name instead of <strong>sampleproject<\/strong>.<\/p>\n<h3>sampleproject.triggers<\/h3>\n<p>As far as I understand it this is for dh-virtualenv to install a newer python interpreter into the virtual environment to ship, if the system\u2019s (your development box) one is updated. The filename will include your project name instead of <strong>sampleproject<\/strong>.<\/p>\n<p>This might or might not be the case, I have not tested it.<\/p>\n<h2>setup.py<\/h2>\n<p>As mentioned above, we need a <strong>setup.py <\/strong>file. This is the standard way applications are packaged under Python (they ship with a setup.py, which is executed for various tasks related to packaging). <\/p>\n<p>A simple setup.py can be seen on this page:<\/p>\n<p><a href=\"https:\/\/github.com\/benjaminirving\/python-debian-packaging-example\/blob\/master\/setup.py\">https:\/\/github.com\/benjaminirving\/python-debian-packaging-example\/blob\/master\/setup.py<\/a><\/p>\n<p>Not all entries in this files are necessary. For instance, you can leave out the classifiers. I have the following setup.py:<\/p>\n<p><a href=\"https:\/\/pi3g.com\/wp-content\/uploads\/2019\/04\/image-26.png\"><img loading=\"lazy\" decoding=\"async\" width=\"649\" height=\"270\" title=\"image\" style=\"display: inline; background-image: none;\" alt=\"image\" src=\"https:\/\/pi3g.com\/wp-content\/uploads\/2019\/04\/image_thumb-26.png\" border=\"0\"><\/a><\/p>\n<p>Note: the version number and other information inside here are for your Python package (which will be created in the course of building a Debian package with your virtualenv).<\/p>\n<h2>Structure for your code<\/h2>\n<p>Your code will now live in a subdirectory of the main sampleproject directory:<\/p>\n<p><a href=\"https:\/\/pi3g.com\/wp-content\/uploads\/2019\/04\/image-27.png\"><img loading=\"lazy\" decoding=\"async\" width=\"612\" height=\"488\" title=\"image\" style=\"display: inline; background-image: none;\" alt=\"image\" src=\"https:\/\/pi3g.com\/wp-content\/uploads\/2019\/04\/image_thumb-27.png\" border=\"0\"><\/a><\/p>\n<p>The subdirectory has the same name as the main directory in this case.<\/p>\n<p>Note the __init__.py<\/p>\n<p>The sample.py is the one we used above, but a bit reworked to look like this:<\/p>\n<p><a href=\"https:\/\/pi3g.com\/wp-content\/uploads\/2019\/04\/image-28.png\"><img loading=\"lazy\" decoding=\"async\" width=\"620\" height=\"391\" title=\"image\" style=\"display: inline; background-image: none;\" alt=\"image\" src=\"https:\/\/pi3g.com\/wp-content\/uploads\/2019\/04\/image_thumb-28.png\" border=\"0\"><\/a><\/p>\n<p>Additionally, I set up a virtual environment for testing while developing inside the main (top level) sampleproject directory:<\/p>\n<blockquote>\n<p>virtualenv -p \/usr\/bin\/python3 sp_env<\/p>\n<\/blockquote>\n<p>called sp_env for sample project environment<\/p>\n<p>Entering the environment:<\/p>\n<blockquote>\n<p>source sp_env\/bin\/activate<\/p>\n<\/blockquote>\n<p>Install the randstr library into this environment:<\/p>\n<blockquote>\n<p>pip3 install randstr<\/p>\n<\/blockquote>\n<p>and now we can run the code:<\/p>\n<blockquote>\n<p>python3 sampleproject\/sample.py<\/p>\n<\/blockquote>\n<p><a href=\"https:\/\/pi3g.com\/wp-content\/uploads\/2019\/04\/image-29.png\"><img loading=\"lazy\" decoding=\"async\" width=\"610\" height=\"54\" title=\"image\" style=\"display: inline; background-image: none;\" alt=\"image\" src=\"https:\/\/pi3g.com\/wp-content\/uploads\/2019\/04\/image_thumb-29.png\" border=\"0\"><\/a><\/p>\n<p>OK. Exit the environment <strong>(! important !)<\/strong>, and try to build the package again:<\/p>\n<blockquote>\n<p>deactivate<\/p>\n<p>dpkg-buildpackage -us \u2013uc<\/p>\n<\/blockquote>\n<p>By default (because of the cookie cutter), your package will be created for installation in \/opt\/venvs\/:<\/p>\n<p><em>New python executable in \/home\/pi\/tutorial\/sampleproject\/debian\/sampleproject\/opt\/venvs\/sampleproject\/bin\/python3<\/em><\/p>\n<p>This can be changed in the <strong>debian\/rules <\/strong>file.<\/p>\n<p>Now the package has been built, and deposited outside of the sampleproject top directory (inside the tutorial directory):<\/p>\n<p><\/p>\n<p><a href=\"https:\/\/pi3g.com\/wp-content\/uploads\/2019\/04\/image-30.png\"><img loading=\"lazy\" decoding=\"async\" width=\"736\" height=\"223\" title=\"image\" style=\"display: inline; background-image: none;\" alt=\"image\" src=\"https:\/\/pi3g.com\/wp-content\/uploads\/2019\/04\/image_thumb-30.png\" border=\"0\"><\/a><\/p>\n<p>You can install the .deb file using dpkg:<\/p>\n<blockquote>\n<p>sudo dpkg -i sampleproject_0.2.1+nmu1_armhf.deb<\/p>\n<\/blockquote>\n<p>See the installation results with <\/p>\n<blockquote>\n<p>tree \/opt\/venvs<\/p>\n<\/blockquote>\n<p>127 directories and 945 files were installed.<\/p>\n<p>Now you can try to execute the sampleproject using <\/p>\n<blockquote>\n<p>\/opt\/venvs\/sampleproject\/bin\/sampleproject<\/p>\n<\/blockquote>\n<h2>requirements \/ dependencies<\/h2>\n<p>The application will not run as (maybe) expected, but throw an error about randstr not being present. What gives?<\/p>\n<p><a href=\"https:\/\/pi3g.com\/wp-content\/uploads\/2019\/04\/image-31.png\"><img loading=\"lazy\" decoding=\"async\" width=\"731\" height=\"95\" title=\"image\" style=\"display: inline; background-image: none;\" alt=\"image\" src=\"https:\/\/pi3g.com\/wp-content\/uploads\/2019\/04\/image_thumb-31.png\" border=\"0\"><\/a><\/p>\n<p>The reason is that dh-virtualenv does not know about the requirement we have, to bundle the package randstr during the build process. This is the final piece of the puzzle. <\/p>\n<p>The requirements need to be added to the <strong>setup.py<\/strong>, as a way to let pip know which additional packages need to be installed in the virtual environment which is being created.<\/p>\n<p>add the following to setup.py:<\/p>\n<blockquote>\n<p>install_requires=[<\/p>\n<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \u2018randstr\u2019<\/p>\n<p>]<\/p>\n<\/blockquote>\n<p>The whole file then will look like this:<\/p>\n<p><a href=\"https:\/\/pi3g.com\/wp-content\/uploads\/2019\/04\/image-32.png\"><img loading=\"lazy\" decoding=\"async\" width=\"763\" height=\"387\" title=\"image\" style=\"display: inline; background-image: none;\" alt=\"image\" src=\"https:\/\/pi3g.com\/wp-content\/uploads\/2019\/04\/image_thumb-32.png\" border=\"0\"><\/a><\/p>\n<p>In my tests the requirements.txt placed at top-level did <strong>not <\/strong>influence the behaviour of dh-virtualenv and the Python packages actually included in the Debian package. If you still want it, here\u2019s how:<\/p>\n<p>pip offers you a way to put out the exact dependencies you used for developing in the virtual environment. Enter the virtual environment:<\/p>\n<blockquote>\n<p>source sp_env\/bin\/activate<\/p>\n<\/blockquote>\n<p>And create the requirements.txt file:<\/p>\n<blockquote>\n<p>pip3 freeze &gt; requirements.txt<\/p>\n<\/blockquote>\n<p>Now you can have a look at that file:<\/p>\n<blockquote>\n<p>cat requirements.txt<\/p>\n<\/blockquote>\n<p><a href=\"https:\/\/pi3g.com\/wp-content\/uploads\/2019\/04\/image-33.png\"><img loading=\"lazy\" decoding=\"async\" width=\"702\" height=\"112\" title=\"image\" style=\"display: inline; background-image: none;\" alt=\"image\" src=\"https:\/\/pi3g.com\/wp-content\/uploads\/2019\/04\/image_thumb-33.png\" border=\"0\"><\/a><\/p>\n<p>Even though this file seems not to be used by dh-virtualenv (maybe it needs to go in a different subdirectory), it is a good reference for yourself, to see which packages you should put as dependencies into the install_requires part of setup.py.<\/p>\n<p>Note that the file sampleproject.links offered us a convenient way to link this into the \/usr\/bin folder, I will therefore remove the comment sign for the next build:<\/p>\n<p><a href=\"https:\/\/pi3g.com\/wp-content\/uploads\/2019\/04\/image-34.png\"><img loading=\"lazy\" decoding=\"async\" width=\"678\" height=\"88\" title=\"image\" style=\"margin: 0px; display: inline; background-image: none;\" alt=\"image\" src=\"https:\/\/pi3g.com\/wp-content\/uploads\/2019\/04\/image_thumb-34.png\" border=\"0\"><\/a><\/p>\n<p>With that out of the way, it\u2019s time to purge the sampleproject, and build it again, then install it. Don\u2019t forget to deactivate first!<\/p>\n<blockquote>\n<p>deactivate<\/p>\n<p>sudo apt purge sampleproject<\/p>\n<p>dpkg-buildpackage \u2013us -uc<\/p>\n<p>cd ..<\/p>\n<p>sudo dpkg \u2013i sampleproject_0.2.1+nmu1_armhf.deb<\/p>\n<\/blockquote>\n<p>This time, the package should be accessible using sampleproject:<\/p>\n<blockquote>\n<p>which sampleproject<\/p>\n<p>sampleproject<\/p>\n<\/blockquote>\n<p><a href=\"https:\/\/pi3g.com\/wp-content\/uploads\/2019\/04\/image-35.png\"><img loading=\"lazy\" decoding=\"async\" width=\"598\" height=\"78\" title=\"image\" style=\"display: inline; background-image: none;\" alt=\"image\" src=\"https:\/\/pi3g.com\/wp-content\/uploads\/2019\/04\/image_thumb-35.png\" border=\"0\"><\/a><\/p>\n<p>Ref: <a href=\"https:\/\/packaging.python.org\/discussions\/install-requires-vs-requirements\/\">https:\/\/packaging.python.org\/discussions\/install-requires-vs-requirements\/<\/a><\/p>\n<p><\/p>\n<h2>Bonus tip: changing the installation location<\/h2>\n<p>\/opt\/venvs is not a very Debian \u201cplace\u201d to put a package.<\/p>\n<p>The specifications are here:<\/p>\n<p><a href=\"http:\/\/refspecs.linuxfoundation.org\/FHS_3.0\/fhs\/index.html\">http:\/\/refspecs.linuxfoundation.org\/FHS_3.0\/fhs\/index.html<\/a><\/p>\n<p><a href=\"https:\/\/unix.stackexchange.com\/questions\/10127\/why-did-my-package-get-installed-to-opt\">https:\/\/unix.stackexchange.com\/questions\/10127\/why-did-my-package-get-installed-to-opt<\/a><\/p>\n<ul>\n<li>\/usr\/local is <strong>not <\/strong>for packages<\/li>\n<li>\/opt is not for Debian packages proper (it\u2019s for user-installed third-party software)<\/li>\n<\/ul>\n<p><a href=\"http:\/\/refspecs.linuxfoundation.org\/FHS_3.0\/fhs\/ch04s06.html\">http:\/\/refspecs.linuxfoundation.org\/FHS_3.0\/fhs\/ch04s06.html<\/a><\/p>\n<p>Applications may use a single subdirectory under <code>\/usr\/lib<\/code>. If an application uses a subdirectory, all architecture-dependent data exclusively used by the application must be placed within that subdirectory.<\/p>\n<p><a href=\"https:\/\/wiki.debian.org\/HowToPackageForDebian\">https:\/\/wiki.debian.org\/HowToPackageForDebian<\/a><\/p>\n<p><a href=\"https:\/\/www.debian.org\/doc\/debian-policy\/ch-opersys.html#file-system-hierarchy\">https:\/\/www.debian.org\/doc\/debian-policy\/ch-opersys.html#file-system-hierarchy<\/a><\/p>\n<p>\u201cThe FHS requirement that architecture-independent application-specific static files be located in <code>\/usr\/share<\/code> is relaxed to a suggestion. In particular,<strong> a subdirectory of <code>\/usr\/lib<\/code> may be used by a package<\/strong> (or a collection of packages) to hold a mixture of architecture-independent and architecture-dependent files. <strong>However, when a directory is entirely composed of architecture-independent files, it should be located in <code>\/usr\/share<\/code><\/strong>.\u201d<\/p>\n<p>The best location to me seems to be \/usr\/share<\/p>\n<p>We need to edit two files:<\/p>\n<p>in debian\/rules DH_VIRTUALENV_INSTALL_ROOT must be changed to \/usr\/share, like this:<\/p>\n<p><a href=\"https:\/\/pi3g.com\/wp-content\/uploads\/2019\/04\/image-36.png\"><img loading=\"lazy\" decoding=\"async\" width=\"645\" height=\"151\" title=\"image\" style=\"display: inline; background-image: none;\" alt=\"image\" src=\"https:\/\/pi3g.com\/wp-content\/uploads\/2019\/04\/image_thumb-36.png\" border=\"0\"><\/a><\/p>\n<p>and debian\/sampleproject.links must be changed:<\/p>\n<p><a href=\"https:\/\/pi3g.com\/wp-content\/uploads\/2019\/04\/image-37.png\"><img loading=\"lazy\" decoding=\"async\" width=\"632\" height=\"51\" title=\"image\" style=\"display: inline; background-image: none;\" alt=\"image\" src=\"https:\/\/pi3g.com\/wp-content\/uploads\/2019\/04\/image_thumb-37.png\" border=\"0\"><\/a><\/p>\n<p>Also, we will make a new entry into the changelog:<\/p>\n<blockquote>\n<p>dch \u2013i<\/p>\n<\/blockquote>\n<p><a href=\"https:\/\/pi3g.com\/wp-content\/uploads\/2019\/04\/image-38.png\"><img loading=\"lazy\" decoding=\"async\" width=\"659\" height=\"149\" title=\"image\" style=\"display: inline; background-image: none;\" alt=\"image\" src=\"https:\/\/pi3g.com\/wp-content\/uploads\/2019\/04\/image_thumb-38.png\" border=\"0\"><\/a><\/p>\n<p>simply edit the text, to reflect a new version number, and an entry for the changelog.<\/p>\n<p><\/p>\n<p>Then the project can be build again:<\/p>\n<blockquote>\n<p>dpkg-buildpackage -us \u2013uc<\/p>\n<\/blockquote>\n<p>After installation, you can verify that indeed the new location is used:<\/p>\n<p><a href=\"https:\/\/pi3g.com\/wp-content\/uploads\/2019\/04\/image-39.png\"><img loading=\"lazy\" decoding=\"async\" width=\"703\" height=\"42\" title=\"image\" style=\"display: inline; background-image: none;\" alt=\"image\" src=\"https:\/\/pi3g.com\/wp-content\/uploads\/2019\/04\/image_thumb-39.png\" border=\"0\"><\/a><\/p>\n<p>The package will take up about 16 MB on your target system, thanks to the virtual environment and everything which is shipped with it. This probably could be reduced by some parameters, but that exercise is left to the reader.<\/p>\n<p>Have fun packaging!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Dieser Artikel zielt darauf ab, Entwicklern, die Python nicht so h\u00e4ufig verwenden, einige Dinge zu erkl\u00e4ren, da sie sonst mit einigen Konzepten Schwierigkeiten haben k\u00f6nnten. Ich empfehle dringend die Lekt\u00fcre des folgenden Artikels als Einf\u00fchrung in die hier besprochenen Konzepte: https:\/\/www.dabapps.com\/blog\/introduction-to-pip-and-virtualenv-python\/ pypi.org pypi.org ist ein offizielles Repository mit Software f\u00fcr die Programmiersprache Python....<\/p>","protected":false},"author":830,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","_links_to":"","_links_to_target":""},"categories":[402,400],"tags":[512,576,427,574,580,276,517,572,573,422,578,577,579,575],"class_list":["post-9418","post","type-post","status-publish","format-standard","hentry","category-development","category-raspberry-pi-embedded-development","tag-standalone","tag-dch","tag-debian","tag-dh-virtualenv","tag-how-to-build-a-deb-package-for-a-python-application-for-raspbian","tag-package","tag-pip","tag-python","tag-python3","tag-raspbian","tag-requirements-txt","tag-setup-py","tag-tutorial","tag-virtualenv"],"_links":{"self":[{"href":"https:\/\/pi3g.com\/de\/wp-json\/wp\/v2\/posts\/9418","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/pi3g.com\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/pi3g.com\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/pi3g.com\/de\/wp-json\/wp\/v2\/users\/830"}],"replies":[{"embeddable":true,"href":"https:\/\/pi3g.com\/de\/wp-json\/wp\/v2\/comments?post=9418"}],"version-history":[{"count":1,"href":"https:\/\/pi3g.com\/de\/wp-json\/wp\/v2\/posts\/9418\/revisions"}],"predecessor-version":[{"id":9419,"href":"https:\/\/pi3g.com\/de\/wp-json\/wp\/v2\/posts\/9418\/revisions\/9419"}],"wp:attachment":[{"href":"https:\/\/pi3g.com\/de\/wp-json\/wp\/v2\/media?parent=9418"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/pi3g.com\/de\/wp-json\/wp\/v2\/categories?post=9418"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/pi3g.com\/de\/wp-json\/wp\/v2\/tags?post=9418"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}