6

I have a package called clana (Github, PyPI) with the following structure:

.
├── clana
│   ├── cli.py
│   ├── config.yaml
│   ├── __init__.py
│   ├── utils.py
│   └── visualize_predictions.py
├── docs/
├── setup.cfg
├── setup.py
├── tests/
└── tox.ini

The setup.py looks like this:

from setuptools import find_packages
from setuptools import setup

requires_tests = [...]

install_requires = [...]


config = {
    "name": "clana",
    "version": "0.3.6",
    "author": "Martin Thoma",
    "author_email": "info@martin-thoma.de",
    "maintainer": "Martin Thoma",
    "maintainer_email": "info@martin-thoma.de",
    "packages": find_packages(),
    "entry_points": {"console_scripts": ["clana=clana.cli:entry_point"]},
    "install_requires": install_requires,
    "tests_require": requires_tests,
    "package_data": {"clana": ["clana/config.yaml"]},
    "include_package_data": True,
    "zip_safe": False,
}

setup(**config)

How to check that it didn't work

Quick

python3 setup.py sdist
open dist/clana-0.3.8.tar.gz  # config.yaml is not in this file

The real check

I thought this would make sure that the config.yaml is in the same directory as the cli.py when the package is installed. But when I try this:

virtualenv venv
source venv/bin/activate
pip install clana
cd venv/lib/python3.6/site-packages/clana
ls

I get:

cli.py  __init__.py  __pycache__  utils.py  visualize_predictions.py

The way I upload it to PyPI:

python3 setup.py sdist bdist_wheel && twine upload dist/*

So the config.yaml is missing. How can I make sure it is there?

Martin Thoma
  • 124,992
  • 159
  • 614
  • 958
  • @Erwan Yes. Just like I posted in the text above. – Martin Thoma Sep 21 '19 at 07:34
  • did you try the path `config.yaml` instead of `clana/config.yaml` ? – Erwan Sep 21 '19 at 07:42
  • related: https://stackoverflow.com/questions/29036937/how-can-i-include-package-data-without-a-manifest-in-file – Erwan Sep 21 '19 at 07:44
  • 1
    It works with `MANIFEST.in` (thank you, Erwan!) - but I thought with the `include_package_data=True` I would not need that. Why is `include_package_data` not working? – Martin Thoma Sep 21 '19 at 08:10
  • 2
    `sdist` is mostly controlled by the files [`MANIFEST` or its template `MANIFEST.in`](https://docs.python.org/3/distutils/sourcedist.html#manifest), not `setup.py`. `include_package_data=True` in `setup.py` is for `bdist_*` (`bdist_egg`, `bdist_wheel`, etc) commands. – phd Sep 21 '19 at 10:54
  • @MartinThoma In the answer I post earlier, it seems `package_data` doens't work if `include_package_data` is true. did you try to remove `include_package_data` in your config ? – Erwan Sep 22 '19 at 09:55

3 Answers3

10

You can add a file name MANIFEST.in next to setup.py with a list of the file you want to add, wildcard allowed (ex: include *.yaml or include clana/config.yaml) then the option include_package_data=True will activate the manifest file

Erwan
  • 587
  • 4
  • 23
  • This works, thank you! (+1) - I don't accept this answer (by now), because I hope that somebody knows why `include_package_data` did not work. – Martin Thoma Sep 21 '19 at 08:11
8

In short: add config.yaml to MANIFEST.in, and set include_package_data. One without the other is not enough.

Basically it goes like this:

  1. MANIFEST.in adds files to sdist (source distribution).
  2. include_package_data adds these same files to bdist (built distribution), i.e. it extends the effect of MANIFEST.in to bdist.
  3. exclude_package_data prevents files in sdist to be added to bdist, i.e. it filters the effect of include_package_data.
  4. package_data adds files to bdist, i.e. it adds build artifacts (typically the products of custom build steps) to your bdist and has of course no effect on sdist.

So in your case, the file config.yaml is not installed, because it is not added to your bdist (built distribution). There are 2 ways to fix this depending on where the file comes from:

  • either the file is a build artifact (typically it is somehow created during the ./setup.py build phase), then you need to add it to package_data ;

  • or the file is part of your source (typically it is in your source code repository), then you need to add it to MANIFEST.in, set include_package_data, and leave it out of exclude_package_data (this seems to be your case here).

See:

sinoroc
  • 18,409
  • 2
  • 39
  • 70
0

Following from the documentation on including data files, if your package has data files such as .yaml files, you may include them like so:

setup(
    ...
    package_data={
        "": ["*.yaml"],
    },
    ...
)

This will allow any file in your package with the file extension .yaml to be included.

foxyblue
  • 2,859
  • 2
  • 21
  • 29