Moving to build rather than calling setup.py directly

After getting deprecation warnings and reading Why you shouldn’t invoke setup.py directly I tried to follow the guideline and call python -m build on a project. I then found that the files that should be excluded are still included (stack overflow question).

I created a sample project which behaves the same.

In my test sample project there is a lib directory with an empty __init__.py and hello.py with print("hello"), a tests directory with an empty test_hello.py file and the following setup.py file:

from setuptools import find_packages, setup

setup(
  name="hello",
  version="0.1",
  author="myself",
  description="test package",
  packages=find_packages(exclude=["tests"]),
)

Comparing the hello.egg-info/SOURCES.txt files generated by python setup.py sdist and python -m build shows that the build one includes tests/test_hello.py (not included by setup.py).

I believe that this is not the expected behaviour, am I missing something or altogether going about this the wrong way?

My environment is:

  • OS: Windows
  • python: 3.10.10
  • pip: 23.0.1
  • setuptools: 65.5.0
  • build: 0.10.0

But I also tried with WSL2 (Ubuntu 20.04.4 LTS) with Python 3.8.10 and got similar results.

It seems to me like if you have a reproducible test case, then you should ask in setuptools’ ticket tracker first, and then if there is still no answer you might want to ask build’s, but as of now I highly doubt that it is related to build:

We meet again @sinoroc :slight_smile:

Can you please confirm that I’m not doing anything entirely idiotic? (I don’t have experience in the packaging part of development).

I can confirm. To the best of my knowledge, what you are doing is correct, and there is a discrepancy that I can not explain. I do not see why tests/test_hello.py is correctly excluded when running python setup.py sdist but wrongly included when running python -m build.

1 Like

I can’t reproduce — in my case both the tarball contents and SOURCES.txt are identical.

For a start, try python -m build -n. Build defaults to using a virtual environment for builds, and -n disables that. This should tell us whether it’s something on your system that’s affecting it: possibly a different setuptools version or some plugin.

It might have something to do with one of the builds triggering the revised include/exclude behavior when using an implict (flat) layout, as opposed to the recommend src layout. With this behavior, tests will be excluded by default, without the need for custom configuration. See, e.g. here. Or it could be the different version in the build vs. working environment, as others mentioned, or another factor. Also, did you check the wheel MANIFEST and contents? I’d trust it over the sdist…

@abravalheri , any expert guidance here?

Also, for completeness, what’s the contents of your pyproject.toml (FWIW, most modern projects should generally configure all of that declarativly in pyproject.toml and dump the setup.py, or at the very least move it to setup.cfg and have a stub setup.py).

The following pyproject.toml is what you should probably start with, as it includes both the required [build-system] block and the metadata and config replacing your setup.py above:

[build-system]
requires = ["setuptools"]
backend = "setuptools.build_meta"

[project]
name = "hello"
version = "0.1"
author = "myself"
description = "test package"

I think that adding a basic pyproject.toml with the information about the chosen build backend will result in the expected output:

[build-system]
build-backend = "setuptools.build_meta"
requires = ["setuptools==65.5"]
1 Like

In general, if you use the same version of setuptools, python setup.py sdist should be pretty similar to python -m build --sdist (except when something gets cached accidentally).

But please note that find_packages(exclude=...) is not a direct indicative of what goes in the sdist. This configuration will rather interfere what goes on the wheel. If you are not using a plugin like setuptools-scm (or configuring a MANIFEST.in) , setuptools will fallback to a default set of files that might automatically include docs, tests, etc…

Adding a pyproject.toml as suggested solved the issue. Thanks!