How Can I Replace `distutils` with `setuptools` in My Python Projects?

With the impending deprecation and scheduled removal of distutils in Python 3.12, as a developer I’m faced with the challenge of transitioning my codebase to use setuptools. For those not yet familiar, distutils has been a fundamental part of Python for distributing and installing Python packages. However, its functionalities are now being absorbed and extended by setuptools, which is an enhanced alternative. This transition is crucial not only to avoid unexpected breakdowns but to make use of better tools offering more functionalities.

I noticed when reviewing PEP 632, the official migration advice wasn’t very detailed, leaving me and possibly many other developers in a bit of a scramble to understand the exact steps needed to migrate smoothly. So I decided to figure it out myself and share what worked for me.

Understanding the Migration

Initially, I examined the recommendations provided by PEP 632. For example, distutils.ccompiler and distutils.core.Distribution are suggested to be replaced with their setuptools counterparts. One frequent usage in my projects was import distutils.command which according to the PEP implies that import setuptools.command should be a drop-in replacement.

However, there were other common modules like distutils.core.setup and distutils.core.Extension, commonly used in setup scripts, which weren’t explicitly covered in the PEP. After some trial and error and referring to the setuptools documentation, I realized setuptools provides similar functionality but needs to be handled slightly differently.

Migrating to setuptools

Here’s a basic outline and some examples of how I migrated common distutils usages to setuptools:

  1. Setup Script (setup.py):

Originally, a typical distutils setup script might look like this:

from distutils.core import setup, Extension

   module1 = Extension('demo', sources=['demo.c'])

   setup(name='PackageName',
         version='1.0',
         description='This is a demo package',
         ext_modules=[module1])

Convert this to use setuptools like so:

from setuptools import setup, Extension

   module1 = Extension('demo', sources=['demo.c'])

   setup(name='PackageName',
         version='1.0',
         description='This is a demo package',
         ext_modules=[module1])

Notice how the change is minimal: the import statement simply switches from distutils.core to setuptools.

  1. Extension Building:

If you’re using distutils to build C extensions, switching to setuptools is straightforward as shown above.

  1. Commands:

If relying on something like distutils.command.build, change this to setuptools.command.build.

  1. Other utilities:

Some utilities like distutils.util.get_platform() will have other recommended replacements such as using Python’s built-in platform module directly.

Is setuptools part of the Standard Library?

setuptools is not part of the Python standard library. It is a third-party package that must be installed separately. Usually, it comes installed with Python distributions like Anaconda or if you’re using virtual environments. If not, it can be easily installed using pip:

pip install setuptools

As for usage, yes, in modern Python dependency and package management practices, direct interaction with setup.py scripts is being replaced with declarative configurations in setup.cfg or pyproject.toml files and using build systems like build or tox. However, many projects still include setup.py for backward compatibility or specific workflows.

By understanding these changes and adapting your codebase accordingly, you’ll be better prepared for Python’s future versions and more aligned with the evolving best practices in Python project setup and distribution. Transitioning to setuptools not only addresses the upcoming removal of distutils but also opens up more sophisticated packaging and distribution capabilities that setuptools provides.


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *