pythonsetuptoolsdata-files

Python setup.py: data_files can't copy 'directory': doesn't exist or not a regular file


I have the following python project structure:

.
├ setup.py
├ doc
|   ├ file.css
|   ├ file.html
|   └ file.js
└ src
    ├ matlabsources
    |             └ <several folders architecture with .m and .slx files>
    └ mypythonpackage
        ├ __init__.py
        └ <several sub packages architecture with python files>

I want to add all the files in the doc folder to my whl distribution file.

setuptools.setup(
    name='myproject',
    author='me',
    packages=setuptools.find_packages(where='src', include=['packages*']),
    package_dir={'': 'src'},
    data_files ={'documentation': find_data_files('doc'), 'matlab': find_data_files('src/matlabsources')},
    include_package_data=True,
    install_requires=make_deps(REQS_FILENAME),
    python_requires='>= 2.7',  # Only compatible with Python 2.7.* and 3+
    use_scm_version={'version_scheme': simple_version},  # setuptools_scm: the blessed package to manage your versions by scm tags
    setup_requires=make_deps(SETUP_FILENAME),
    cmdclass=dict(bdist_egg=custom_bdist_egg, build=custom_build, activateIniGeneration=activateIniGeneration)
)


def find_data_files(directory):
    """
    Using glob patterns in ``package_data`` that matches a directory can
    result in setuptools trying to install that directory as a file and
    the installation to fail.

    This function walks over the contents of *directory* and returns a list
    of only filenames found.
    """

    strip = os.path.dirname(os.path.abspath(__file__))

    result = []
    for root, dirs, files in os.walk(directory):
        for filename in files:
          filename = os.path.join(root, filename)
          result.append(os.path.relpath(filename, strip))

    print("\n".join(result))
    return result

I get the following error:

error: can't copy 'documentation': doesn't exist or not a regular file

In my understanding, 'documentation' is the target directory, relative to sys.prefix, it is normal it does not exist.

I am building with the following command:

python setup.py bdist_wheel --universal

I also have this warning

warning: install_data: setup script did not provide a directory for 'documentation' -- installing right in 'build\bdist.win32\wheel\myproject-1.7.z_gfdc81e60.d20201112.data\data'

Which make me think I need further configuration to my setup.py for this to work

Where am I wrong ?


Solution

  • Assuming a project directory structure such as:

    myproject
    ├── doc
    │   ├── alpha
    │   │   ├── file.css
    │   │   ├── file.html
    │   │   └── file.js
    │   ├── file.css
    │   ├── file.html
    │   └── file.js
    ├── MANIFEST.in
    ├── setup.cfg
    ├── setup.py
    └── src
        ├── matlabsources
        │   ├── bravo
        │   │   ├── file.m
        │   │   └── file.slx
        │   ├── file.m
        │   └── file.slx
        └── mypythonpackage
            ├── charlie
            │   └── __init__.py
            └── __init__.py
    

    With MANIFEST.in you can specify additional files to be added to the _source distribution (sdist).

    recursive-include doc *.css
    recursive-include doc *.html
    recursive-include doc *.js
    
    recursive-include src/matlabsources *.m
    recursive-include src/matlabsources *.slx
    

    The setuptools script setup.py should look like this:

    #!/usr/bin/env python3
    
    import setuptools
    
    def _find_packages():
        packages = setuptools.find_packages(where='src')
        packages.append('mypythonpackage.doc')
        packages.append('matlabsources')
        return packages
    
    def _main():
        setuptools.setup(
            # see 'setup.cfg'
            #
            packages=_find_packages(),
            include_package_data=True,
            package_dir={
                'mypythonpackage': 'src/mypythonpackage',
                'mypythonpackage.doc': 'doc',
                'matlabsources': 'src/matlabsources',
            },
        )
    
    
    if __name__ == '__main__':
        _main()
    

    This results in the sdist:

    $ python3 -m tarfile -l dist/myproject-0.0.0.dev0.tar.gz 
    myproject-0.0.0.dev0/ 
    myproject-0.0.0.dev0/MANIFEST.in 
    myproject-0.0.0.dev0/PKG-INFO 
    myproject-0.0.0.dev0/doc/ 
    myproject-0.0.0.dev0/doc/alpha/ 
    myproject-0.0.0.dev0/doc/alpha/file.css 
    myproject-0.0.0.dev0/doc/alpha/file.html 
    myproject-0.0.0.dev0/doc/alpha/file.js 
    myproject-0.0.0.dev0/doc/file.css 
    myproject-0.0.0.dev0/doc/file.html 
    myproject-0.0.0.dev0/doc/file.js 
    myproject-0.0.0.dev0/myproject.egg-info/ 
    myproject-0.0.0.dev0/myproject.egg-info/PKG-INFO 
    myproject-0.0.0.dev0/myproject.egg-info/SOURCES.txt 
    myproject-0.0.0.dev0/myproject.egg-info/dependency_links.txt 
    myproject-0.0.0.dev0/myproject.egg-info/requires.txt 
    myproject-0.0.0.dev0/myproject.egg-info/top_level.txt 
    myproject-0.0.0.dev0/pyproject.toml 
    myproject-0.0.0.dev0/setup.cfg 
    myproject-0.0.0.dev0/setup.py 
    myproject-0.0.0.dev0/src/ 
    myproject-0.0.0.dev0/src/matlabsources/ 
    myproject-0.0.0.dev0/src/matlabsources/bravo/ 
    myproject-0.0.0.dev0/src/matlabsources/bravo/file.m 
    myproject-0.0.0.dev0/src/matlabsources/bravo/file.slx 
    myproject-0.0.0.dev0/src/matlabsources/file.m 
    myproject-0.0.0.dev0/src/matlabsources/file.slx 
    myproject-0.0.0.dev0/src/mypythonpackage/ 
    myproject-0.0.0.dev0/src/mypythonpackage/__init__.py 
    myproject-0.0.0.dev0/src/mypythonpackage/charlie/ 
    myproject-0.0.0.dev0/src/mypythonpackage/charlie/__init__.py 
    

    and in the wheel:

    $ python3 -m zipfile -l dist/myproject-0.0.0.dev0-py3-none-any.whl 
    File Name                                             Modified             Size
    matlabsources/file.m                           2020-11-16 16:41:06            0
    matlabsources/file.slx                         2020-11-16 16:41:06            0
    matlabsources/bravo/file.m                     2020-11-16 16:41:18            0
    matlabsources/bravo/file.slx                   2020-11-16 16:41:18            0
    mypythonpackage/__init__.py                    2020-11-16 16:45:02           88
    mypythonpackage/charlie/__init__.py            2020-11-16 16:55:22            0
    mypythonpackage/doc/file.css                   2020-11-16 16:30:34            0
    mypythonpackage/doc/file.html                  2020-11-16 16:30:34            0
    mypythonpackage/doc/file.js                    2020-11-16 16:30:34            0
    mypythonpackage/doc/alpha/file.css             2020-11-16 16:33:00            0
    mypythonpackage/doc/alpha/file.html            2020-11-16 16:33:00            0
    mypythonpackage/doc/alpha/file.js              2020-11-16 16:33:00            0
    myproject-0.0.0.dev0.dist-info/METADATA        2020-11-16 17:03:32         1311
    myproject-0.0.0.dev0.dist-info/WHEEL           2020-11-16 17:03:32           92
    myproject-0.0.0.dev0.dist-info/top_level.txt   2020-11-16 17:03:32           30
    myproject-0.0.0.dev0.dist-info/RECORD          2020-11-16 17:03:32         1499