Including non-Python files with setup.py
Probably the best way to do this is to use the setuptools
package_data
directive. This does mean using setuptools
(or distribute
) instead of distutils
, but this is a very seamless "upgrade".
Here's a full (but untested) example:
from setuptools import setup, find_packages
setup(
name='your_project_name',
version='0.1',
description='A description.',
packages=find_packages(exclude=['ez_setup', 'tests', 'tests.*']),
package_data={'': ['license.txt']},
include_package_data=True,
install_requires=[],
)
Note the specific lines that are critical here:
package_data={'': ['license.txt']},
include_package_data=True,
package_data
is a dict
of package names (empty = all packages) to a list of patterns (can include globs). For example, if you want to only specify files within your package, you can do that too:
package_data={'yourpackage': ['*.txt', 'path/to/resources/*.txt']}
The solution here is definitely not to rename your non-py
files with a .py
extension.
See Ian Bicking's presentation for more info.
UPDATE: Another [Better] Approach
Another approach that works well if you just want to control the contents of the source distribution (sdist
) and have files outside of the package (e.g. top-level directory) is to add a MANIFEST.in
file. See the Python documentation for the format of this file.
Since writing this response, I have found that using MANIFEST.in
is typically a less frustrating approach to just make sure your source distribution (tar.gz
) has the files you need.
For example, if you wanted to include the requirements.txt
from top-level, recursively include the top-level "data" directory:
include requirements.txt
recursive-include data *
Nevertheless, in order for these files to be copied at install time to the package’s folder inside site-packages, you’ll need to supply include_package_data=True
to the setup()
function. See Adding Non-Code Files for more information.
Including non-python files in a python package
The solution is a combination of @m.rp and @vin's answers:
Instead of from distutils.core import setup
use
from setuptools import setup
include the following argument to the setup() call
include_package_data=True,
and ONLY use the MANIFEST.in to include files, where the directory is specified relative from the location where the MANIFEST.in file is.
recursive-include gimpscm *.txt
What a massive PITA this was. Thank you for your answers!
Adding non-python files to setup.py
I got it. Make sure you have the complete path in the MANIFEST.in
file. Something like:
include smlgui/gui/*.ui
include smlgui/gui/assets/*.png
Then test it by creating a wheel, by doing
python setup.py bdist_wheel
Under build
folder you should be able to see all the contents.
Accessing non-Python files from another package in PEP518 environment (pyproject.toml)
Do you really want to use data_files
?
I would recommend using package_data
instead. This way files are part of the Python package itself (installed in site-packages
for example) and are very easy to retrieve once installed.
Resources:
- https://sinoroc.gitlab.io/kb/python/package_data.html
- https://docs.python.org/3/distutils/setupscript.html#installing-package-data
- https://setuptools.readthedocs.io/en/latest/setuptools.html#including-data-files
- https://packaging.python.org/guides/distributing-packages-using-setuptools/#package-data
Access the installed package data with either one of those:
1. pkgutil
import pkgutil
pkgutil.get_data('my_top_level_package.my_sub_package', 'file.bin')
2. importlib.resources
importlib.resources.read_binary('my_top_level_package.my_sub_package', 'file.bin')
3. pkg_resources
Including non-Python files with setup.py
Probably the best way to do this is to use the setuptools
package_data
directive. This does mean using setuptools
(or distribute
) instead of distutils
, but this is a very seamless "upgrade".
Here's a full (but untested) example:
from setuptools import setup, find_packages
setup(
name='your_project_name',
version='0.1',
description='A description.',
packages=find_packages(exclude=['ez_setup', 'tests', 'tests.*']),
package_data={'': ['license.txt']},
include_package_data=True,
install_requires=[],
)
Note the specific lines that are critical here:
package_data={'': ['license.txt']},
include_package_data=True,
package_data
is a dict
of package names (empty = all packages) to a list of patterns (can include globs). For example, if you want to only specify files within your package, you can do that too:
package_data={'yourpackage': ['*.txt', 'path/to/resources/*.txt']}
The solution here is definitely not to rename your non-py
files with a .py
extension.
See Ian Bicking's presentation for more info.
UPDATE: Another [Better] Approach
Another approach that works well if you just want to control the contents of the source distribution (sdist
) and have files outside of the package (e.g. top-level directory) is to add a MANIFEST.in
file. See the Python documentation for the format of this file.
Since writing this response, I have found that using MANIFEST.in
is typically a less frustrating approach to just make sure your source distribution (tar.gz
) has the files you need.
For example, if you wanted to include the requirements.txt
from top-level, recursively include the top-level "data" directory:
include requirements.txt
recursive-include data *
Nevertheless, in order for these files to be copied at install time to the package’s folder inside site-packages, you’ll need to supply include_package_data=True
to the setup()
function. See Adding Non-Code Files for more information.
Using setuptools to copy non .py files
- Add
include_package_data=True
to yoursetup
-function (you already did that). - Create a file
MANIFEST.in
in the same directory assetup.py
MANIFEST.in
can look as follows:
include indictrans/models/ben-eng/*
include indictrans/models/ben-guj/*
You don't need setup.cfg
for doing this.
Source: This great writeup of python packaging
EDIT about recursive-include
:
According to the documentation this should also work:
recursive-include indictrans/models *.npy *.vec
Copy a non-Python file to specific directory during Pip Install
After a lot of research I have figure out how to resolve this issue. Let me summarize my findings, it might be helpful for other who wants to do post_pip_install
processing.
setup.py
Different options to install package: 1)
pip install pkg_name
, 2)python -m setup.py sdist
If you want to make them work in either ways, need to have
install
,egg_info
anddevelop
all 3 options repeated as shown in setup.pyIf you create
*.whl
file bypython -m setup.py bdist_wheel
,post pip install processing
won't be executed! Please upload.tar.gz
format generated usingsdist
to PyPi/Artifacts to makepost pip install processing
work. Again, Please note: It will not work when installing from a binary wheelupload the pip package:
twine upload dist/*.tar.gz
from setuptools import setup, find_packages
from setuptools.command.install import install
from setuptools.command.egg_info import egg_info
from setuptools.command.develop import develop
rootDir = os.path.abspath(os.path.dirname(__file__))
def run_post_processing():
print("--------Start running custom command -------")
# One can Run any Post Processing here that will be executed post pip install
class PostInstallCommand(install):
def run(self):
print("***********Custom run from install********")
install.run(self)
run_post_processing()
class PostEggCommand(egg_info):
def run(self):
print("***********Custom run from Egg********")
egg_info.run(self)
run_post_processing()
class PostDevelopCommand(develop):
def run(self):
print("***********Custom run from Develop********")
develop.run(self)
run_post_processing()
ver = "0.0.0"
setup(
name='my_pkg',
version=ver,
packages=find_packages(),
python_requires='>=3.6.0',
install_requires = getRequirements(),
include_package_data= True,
cmdclass={
'install' : PostInstallCommand,
'egg_info': PostEggCommand,
'develop': PostDevelopCommand
}
)
Few More Things from my research:
- If you want to do
pre-processing
instead ofpost-processing
, need to moveinstall.run(self)
at the end - while pip installing, if you want to see custom messages of pre/post instllation, use
-vvv
. Example:pip install -vvv my_pkg
Adding non-python files to colcon build
I solved it. I am not sure if this is the right way of doing this or is there like another better/proper way or not, but here we go.
In the setup.py file, I added the line(os.path.join('lib/python3.8/site-packages/package_name/sub_package/OSM'),glob(package_name+'/sub_package_name/OSM/*.osm')),
in the data_files variable.
The first part of the new line which is os.path.join('lib/python3.8/site-packages/package_name/sub_package_name/OSM')
determines the new location of the files in the install folder after building the workspace.
The second part which is glob(package_name+'/sub_package_name/OSM/*.osm')
determines the files original location in the project workspace.
So the result is that it takes the files from the location mentioned in the second part and puts them in the location mentioned in the first part.
The resulting block is:
setup(
name=package_name,
version='0.0.0',
packages=[package_name, submodules, osm],
data_files=[
('share/ament_index/resource_index/packages',
['resource/' + package_name]),
('share/' + package_name, ['package.xml']),
(os.path.join('share', package_name), glob('launch/*.launch.py')),
(os.path.join('lib/python3.8/site-packages/package_name/sub_package_name/OSM'), glob(package_name+'/sub_package_name/OSM/*.osm')),
],
.
.
.
)
Related Topics
How to Print an Exception in Python
Finding Median of List in Python
Suppress the U'Prefix Indicating Unicode' in Python Strings
Python 3: Importerror "No Module Named Setuptools"
How Would I Access Variables from One Class to Another
Why Is My Pygame Display Not Responding While Waiting for Input
Pretty Printing a Pandas Dataframe
Django 1.7 Throws Django.Core.Exceptions.Appregistrynotready: Models Aren't Loaded Yet
Python Iterator Is Empty After Performing Some Action on It
How to Limit Concurrency with Python Asyncio
How to Update/Upgrade Pip Itself from Inside My Virtual Environment
How to Sandbox Python in Pure Python
How to Add Placeholder to an Entry in Tkinter
Read File from Line 2 or Skip Header Row
How to Add Percentages on Top of Bars in Seaborn
Calculating Direction of the Player to Shoot Pygame