I'm new to python and writing an application which I want to package for debian. Therefore, I'd like to (and I have to) use pybuilder. My goal is to create a .deb package (currently using stdeb), which makes sure, that all required libraries are installed, too.
My application uses a third party library, that is only available via pip(3) install (no debian package).
My build.py looks like:
[...]
use_plugin("python.core")
use_plugin("python.unittest")
use_plugin("python.install_dependencies")
use_plugin("python.distutils")
use_plugin("copy_resources")
use_plugin("source_distribution")
use_plugin("python.flake8")
use_plugin("python.coverage")
use_plugin("python.stdeb")
#init
def initialize(project):
project.build_depends_on('coverage')
project.build_depends_on('flake8')
project.build_depends_on('jsonmerge')
project.build_depends_on('mock')
project.build_depends_on('setuptools')
project.build_depends_on('stdeb')
project.build_depends_on('unittest-xml-reporting')
project.build_depends_on('xmlrunner')
project.depends_on('<pip-only-library>')
project.set_property('coverage_threshold_warn', 50)
project.set_property('flake8_break_build', False)
project.set_property('flake8_ignore', 'E501,E402,E731')
project.set_property('flake8_include_test_sources', True)
project.set_property('flake8_verbose_output', True)
project.set_property('verbose', True)
project.set_property("copy_resources_target", "$dir_dist")
project.set_property("coverage_break_build", False)
project.set_property("coverage_reset_modules", True)
project.set_property("dir_dist_scripts", 'scripts')
project.set_property("distutils_classifiers", [
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4',
'Development Status :: 4',
'Environment :: Console',
'Intended Audience :: Systems Administration',
'License :: OSI Approved :: BSD License'])
project.set_property('distutils_commands', ['bdist'])
project.set_property('distutils_commands', ['sdist'])
Generation of debian package works in general. Calling pyb successfully creates a python3-mypackage_1.0-1_all.deb package.
The generated setup.py looks like:
# `target/dist/mypackage-1.0/setup.py`
[...]
if __name__ == '__main__':
setup(
[...]
packages = [],
[...]
entry_points = {},
data_files = [],
package_data = {},
install_requires = ['pip-only-library'],
dependency_links = [],
zip_safe=True,
cmdclass={'install': install},
)
Testing package installation using sudo dpkg -i python3-mypackage_1.0-1_all.deb fails as dpkg refers to a dependent package python3-<pip-only-library>, which is not available.
During build time, the library is present on the local machine.
So, now comes the newbie question: How to change build.py to make sure, that the created debian package provides my application and makes sure, that library requirements are met.
Maybe, is it possible to bundle the pip-only library (i.e. taken from /usr/local/lib/python3.4/dist-packages during build-time) to my application and ship them within an 'application with all dependencies'-package? Or is there an alternative approach?
I've already seen this answer but it doesn't help.
Related
For many python libraries, the argument used with import is the same as the one used to install the library with pip.
E.g.
pip install numpy
pip install scipy
pip install pandas
correspond to
import numpy
import scipy
import pandas
but this pattern doesn't seem to work for all libraries. E.g. (found here):
pip install Pillow
is required to get this to succeed
import PIL
Based on the pattern in the first examples, I would have expected pip install PIL to install PIL, but instead we use pip install Pillow. Why is this and how does this work?
Basically, what you import is usually the module name. For example, your package might be developed in the following hierarchy:
MyLib
- __init__.py
- my_script1.py
- my_script2.py
However, when you make your library as a "package" available in pip, usually you will need to prepare your setup.py file, which will be automatically run when people use pip install to install your package.
The setup.py can be something like this:
from distutils.core import setup
setup(
name = 'YOURPACKAGENAME', # How you named your package folder (MyLib)
packages = ['YOURPACKAGENAME'], # Chose the same as "name"
version = '0.1', # Start with a small number and increase it with every change you make
license='MIT', # Chose a license from here: https://help.github.com/articles/licensing-a-repository
description = 'TYPE YOUR DESCRIPTION HERE', # Give a short description about your library
author = 'YOUR NAME', # Type in your name
author_email = 'your.email#domain.com', # Type in your E-Mail
url = 'https://github.com/user/reponame', # Provide either the link to your github or to your website
download_url = 'https://github.com/user/reponame/archive/v_01.tar.gz', # I explain this later on
keywords = ['SOME', 'MEANINGFULL', 'KEYWORDS'], # Keywords that define your package best
install_requires=[ # I get to this in a second
'validators',
'beautifulsoup4',
],
classifiers=[
'Development Status :: 3 - Alpha', # Chose either "3 - Alpha", "4 - Beta" or "5 - Production/Stable" as the current state of your package
'Intended Audience :: Developers', # Define that your audience are developers
'Topic :: Software Development :: Build Tools',
'License :: OSI Approved :: MIT License', # Again, pick a license
'Programming Language :: Python :: 3', #Specify which pyhton versions that you want to support
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
],
)
Therefore, in the above example, people who install your package via pip should run pip install YOURPACKAGENAME. After that, they need to run import MyLib in the code.
TD; DL:
What you import is a module name, but what you installed via pip is the name of the package, they can be different. But usually, I would say that I like people to use the same name for both to avoid any confusing.
Ref:
https://medium.com/#joel.barmettler/how-to-upload-your-python-package-to-pypi-65edc5fe9c56
I created a package, named furigana . This package page can be browsed by a user not logined to pypi. However, if I type "furigana" in the homepage of pypi, it can not find my package "furigana".
I also used pip3 search to search it, and it also find nothing.
I ran below commands to create archive and upload it by twine:
python3 setup.py test
python3 setup.py sdist
twine upload dist/furigana-0.0.7.tar.gz
The output message of twine is:
Uploading distributions to https://upload.pypi.org/legacy/
Uploading furigana-0.0.7.tar.gz
My ~/.pypirc is
[distutils]
index-servers =
pypi
[pypi]
repository: https://upload.pypi.org/legacy/
username:<my_username>
password:<my_password>
My setup.py is
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from setuptools import setup
from os import path
here = path.abspath(path.dirname(__file__))
# Get the long description from the relevant file
with open(path.join(here, 'README.rst'), encoding='utf-8') as f:
long_description = f.read()
setup(name='furigana',
version='0.0.7',
description='''convert Kanji in Japanese into Kanji attached with Hiragana (Furigana(振り仮名))
For example, "澱んだ街角" => "澱(よど)んだ街角(まちかど)" ''',
long_description = long_description,
author='Miki.Liu',
author_email='mikimotoh#gmail.com',
url='https://github.com/MikimotoH/furigana',
packages=['furigana'],
classifiers=[
# How mature is this project? Common values are
# 3 - Alpha
# 4 - Beta
# 5 - Production/Stable
'Development Status :: 3 - Alpha',
'Environment :: Console',
'Intended Audience :: Developers',
'Intended Audience :: Science/Research',
'License :: OSI Approved :: MIT License',
'Programming Language :: Python :: 3',
'Topic :: Software Development :: Libraries :: Python Modules',
'Topic :: Text Processing :: Linguistic',
],
keywords='Japanese Language Processing',
)
Cannot search package in PyPI with pip doesn't resolve my problem, the bitbucket repository is already removed.
I am trying to install a python package on my ubuntu.I am trying to install it through a setup script which i had written.The setup.py script looks like this:
from setuptools import setup
try:
from setuptools import setup
except ImportError:
from distutils.core import setup
setup(
name = 'pyduino',
description = 'PyDuino project aims to make python interactive with hardware particularly arduino.',
url = '###',
keywords = 'python arduino',
author = '###',
author_email = '###',
version = '0.0.0',
license = 'GNU',
packages = ['pyduino'],
install_requires = ['pyserial'],
classifiers = [
# How mature is this project? Common values are
# 3 - Alpha
# 4 - Beta
# 5 - Production/Stable
'Development Status :: 3 - Alpha',
'Intended Audience :: Developers',
'Topic :: Software Development :: Build Tools',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
],
scripts=['pyduino/pyduino.py'],
)
Package installs in /usr/local/bin directory.But when I am importing the modules outside the /usr/local/bin,import error occurs.I tried changing path to /usr/local/bin and it works perfectly and import error doesn't occur.How can I install the package so that I can import the modules in any directory? Thanks in advance...
Try install your packages with pip using this
pip install --install-option="--prefix=$PREFIX_PATH" package_name
as described here Install a Python package into a different directory using pip?
and i'll suggest to read what are 1. pip 2. virtualenv
Good luck :)
EDIT: i found the package is installed with pip like:
pip install --install-option="--prefix=/usr/local/bin" pyduino_mk
Currently, you're using a scripts tag to install your python code. This will put your code in /usr/local/bin, which is not in PYTHONPATH.
According to the documentation, you use scripts when you want to install executable scripts (stuff you want to call from command line). Otherwise, you need to use packages.
My approach would be like this:
install the pyduino/pyduino.py in the library with something like packages=['pyduino']
create a wrapper (shell or python) capable of calling your installed script and install that via scripts=[...]
Using the packages tag for your module will install it in /usr/local/lib/python..., which is in PYTHONPATH. This will allow you to import your script with something like import pyduino.pyduino.*.
For the wrapper script part:
A best practice is to isolate the code to be executed if the script is triggered from command line in something like:
def main():
# insert your code here
pass
if __name__ == '__main__':
main()
Assuming there is a def main() as above
create a directory scripts in your tree (at the same level with setup.py)
create a file scripts/pyduino
in scripts/pyduino:
#!/usr/bin/env python
from pydiuno.pyduino import main
if __name__ == '__main__':
main()
add a `scripts = ['scripts/pyduino'] to your setup.py code
Hello fellow programmers,
So lately I've been working on a project at my work that we want to open source. It's the package called django-push-notifications-manager (yes, what a unusual long name I know).
So I already did the registration and the uploading of the package, but for some kind of reason pip install django-push-notifications-manager will not work and will give the error:
Downloading/unpacking django-push-notifications-manager
Could not find any downloads that satisfy the requirement django-push-notifications-manager
Cleaning up...
No distributions at all found for django-push-notifications-manager
Storing debug log for failure in /Users/pauloostenrijk/.pip/pip.log
So I haven't been able to fix it by removing and replacing the package, deleting it, making a new version. None of them worked.
I think you guys would like to know what my setup.py was, so hereby:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import sys
import push_notifications
def get_packages(package):
"""
Return root package and all sub-packages.
"""
return [dirpath
for dirpath, dirnames, filenames in os.walk(package)
if os.path.exists(os.path.join(dirpath, '__init__.py'))]
try:
from setuptools import setup
except ImportError:
from distutils.core import setup
version = push_notifications.__version__
if sys.argv[-1] == 'publish':
os.system('python setup.py sdist upload')
print("You probably want to also tag the version now:")
print(" git tag -a %s -m 'version %s'" % (version, version))
print(" git push --tags")
sys.exit()
readme = open('README.rst').read()
setup(
name='django-push-notifications-manager',
version=version,
description="""A plug and play package to handle push devices and push notifications for services such as ZeroPush and Urban Airship""",
long_description=readme,
author='Paul Oostenrijk',
author_email='paul#glemma.nl',
url='https://github.com/glemmaPaul/django-push-notifications-manager',
packages=get_packages('push_notifications'),
include_package_data=True,
install_requires=[
'django>=1.5.1',
'requests>=2.5.1'
],
license="BSD",
zip_safe=False,
keywords='django-push-notifications-manager',
classifiers=[
'Development Status :: 2 - Pre-Alpha',
'Framework :: Django',
'Intended Audience :: Developers',
'License :: OSI Approved :: BSD License',
'Natural Language :: English',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.3',
],
)
Hope any of you guys could help me out! Thanks in advance :)
So after spending a long time of trying and figuring out I finally found the problem.
Don't look strange to me, but apparently PyPi has problems with the name django-push-notifications-manager, I think there can be 2 causes:
The length of the name
That having 2 dashes in the name is the maximum
I hope nobody will ever get this problem, it was head cracking!
Thanks for your time!
I have published a module to pypi called 'surrealism' that generates surreal sentences and error messages. It contains a SQLite3 database containing all of the words and sentences needed for my module.
All of the following install methods work fine:
python setup.py install
pip install surrealism
easy_install surrealism
and the module works fine.
However, when installing into a virtualenv, things go wrong. surrealism.py get installed into C:\Users\me\virtualenvs\surrealism\Lib\site-packages, but surrealism.sqlite doesn't get installed?
If I run python and try and import the module, my module creates a new sqlite3 database called surrealism.sqlite at C:\Users\me\virtualenvs\surrealism
The contents of my setup.py follows:
#!/usr/bin/env python
from setuptools import setup
long_desc = open('readme.rst').read()
setup(name = 'surrealism',
version = '0.5.2',
py_modules = ['surrealism'],
author = 'Morrolan',
author_email = 'morrolan#icloud.com',
url = 'https://github.com/Morrolan/surrealism',
license = 'GNU General Public License (GPL)',
description = 'Surreal sentence and error message generator.',
long_description = long_desc,
platforms = ['Windows','Unix','OS X'],
download_url = "https://pypi.python.org/pypi/surrealism/",
keywords = ["surreal", "surrealism", "error message"],
classifiers = [
"Programming Language :: Python",
"Programming Language :: Python :: 2.6",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3.3",
"Development Status :: 4 - Beta",
"Environment :: Other Environment",
"Intended Audience :: Developers",
"Intended Audience :: Education",
"License :: OSI Approved :: GNU General Public License (GPL)",
"Operating System :: OS Independent",
"Topic :: Education",
"Topic :: Software Development :: Libraries :: Python Modules",
],
install_requires=['setuptools'],
)
In surrealism.py, I reference/connect to the SQLite3 database in a fairly rudimentary way:
CONN = sqlite3.connect('surrealism.sqlite')
But so far it hasn't caused me any problems.
is there a more explicit way to reference surrealism.sqlite, or do I have to specify something in setup.py to force the installation?
Kind Regards,
Morrolan
the crucial problem is exactly the way you are connecting to your sqlite database; That will refer to a file in the current directory;, anywhere the program that invokes it is trying to run. What you want to say is
... sqlite3.connect(where_this_python_lib_is_installed + '...sqlite')
So that it doesn't matter where it's installed. There is a fairly standard way to do that, using the pkg_resources library. Since we're trying to discover a sqlite database, that means we need a real file on disk, not a string or file-like object; so the right method to use here pkg_resources.resource_filename, we just need to change the connect call to:
from pkg_resources import resource_filename
CONN = sqlite3.connect(resource_filename(__name__, 'surrealism.sqlite'))
But wait... That only works if the package data is in a package, but you currently have a module. Not a big problem, though; we'll rename surrealism.py to surrealism/__init__.py, surrealism.sqlite to surrealism/surrealism.sqlite, and make the appropriate changes in MANIFEST.in. We'll also need to tell setuptools about this. Change py_modules=["surrealism"], in your setup.py to packages=["surrealism"].
Almost there, The last thing we need to do is get setuptools to actually install that file from source. The first is pretty obvious, we need to tell it which files to copy; Add
package_data={'surrealism': ['surrealism.sqlite']},
To your setup.py, the second change is more subtle. In most cases, setuptools tries to install packages as zip files. This is usually a good thing; but in our case, we need to pass the filename of a real file to sqlite.connect, so we have to tell it not to try to zip the package. For that, just add
zip_safe=False,
To your setup.py.