Search code examples
pythonmacossetuptools

setuptools sdist has appropriate files, wheel is missing top folder for packages


I'm trying to use the basic example from the docs. I am able to successfully generate an sdist, but I want to be able to install from wheel. However, when installing from wheel instead of from the sdist, I don't have a proj directory that I can import, only pkg1 and pkg2.

Starting from this directory:

├── proj
│   ├── __init__.py
│   ├── additional
│   │   └── __init__.py
│   ├── pkg1
│   │   └── __init__.py
│   └── pkg2
│       └── __init__.py
├── pyproject.toml
└── setup.cfg

I tried using this setup.cfg:

[metadata]
name = p1
version = 0.0.1

[options]
packages =
    find:
package_dir =
    =proj

[options.packages.find]
where = proj
include = pkg*
exclude = additional

To generate this file structure, which is successfully generated in the source distribution:

├── PKG-INFO
├── README.md
├── proj
│   ├── p1.egg-info
│   │   ├── PKG-INFO
│   │   ├── SOURCES.txt
│   │   ├── dependency_links.txt
│   │   └── top_level.txt
│   ├── pkg1
│   │   └── __init__.py
│   └── pkg2
│       └── __init__.py
├── pyproject.toml
└── setup.cfg

But the wheel has this structure:

├── p1-0.0.1.dist-info
│   ├── METADATA
│   ├── RECORD
│   ├── WHEEL
│   └── top_level.txt
├── pkg1
│   └── __init__.py
└── pkg2
    └── __init__.py

This makes it impossible to use:

import proj

As there is no such module, only modules pkg1 and pkg2.

I made a repo for this here: https://github.com/spensmith/setuptools-find.


Steps to recreate:

  1. Clone the base repository here: https://github.com/spensmith/setuptools-find
  2. cd setuptools-find
  3. python -m build
  4. mkdir dist/mywheel
  5. unzip dist/p1-0.0.1-py3-none-any.whl -d dist/mywheel
  6. tree dist/mywheel

I must be missing something basic, any help would be so appreciated!

Thank you, Spencer.


Solution

  • My question was answered directly on the setuptools discussion forum. https://github.com/pypa/setuptools/discussions/3185#discussioncomment-2411330.

    Effectively, I shouldn't be using

    package_dir =
        =proj
    

    Because this means that all of my code is within this folder. Instead, I should remove it entirely, and then change my exclude to look like:

    [options.packages.find]
    exclude = proj.additional
    

    Finally, yielding this file:

    [metadata]
    name = p1
    version = 0.0.1
    
    [options]
    packages =
        find:
    
    [options.packages.find]
    exclude = proj.additional