praiskup / argparse-manpage

Automatically build man-pages for your Python project
Apache License 2.0
41 stars 22 forks source link

Distutils is to be removed from the standard library in Python 3.12 #63

Closed musicinmybrain closed 2 years ago

musicinmybrain commented 2 years ago

In accordance with PEP 0632, distutils will be removed from the Python 3.12 standard library.

In order to retain compatibility with Python 3.12, it may be sufficient to add a runtime dependency on setuptools. See the relevant Fedora Linux python-devel mailing list thread; regarding potential incompatibilities, see https://github.com/pypa/setuptools/issues/3532.

hroncok commented 2 years ago

The easiest short-term workaround is to runtime-require setuptools on Python 3.12+.

I.e. add to setup.py:

setup(
    ...,
    install_requires(['setuptools>=60;python_version>="3.12"']),
    ...,
)

EDIT: Added >=60 to ensure setuptools actually provide the distutils module.

praiskup commented 2 years ago

It is not a hard runtime dependency IMO. The /bin/argparse-manpage script doesn't rely on distutils at all. Distutils are only needed for the setup.py command overrides (supported by this project). So should our users specify the setuptools as the builddep for their projects?

hroncok commented 2 years ago

It seems like this project imports from distutils:

https://github.com/praiskup/argparse-manpage/blob/28151c24bfc80d33140b2fcf69400ba5fde907df/build_manpages/build_manpages.py#L8-L9

If build_manpages isn't a "core" part of this, maybe it needs to have extras dependendencies?

hroncok commented 2 years ago

In that case, you would do something like this in setup.py:

https://setuptools.pypa.io/en/latest/userguide/dependency_management.html#optional-dependencies

setup(
    ...,
    extras_require={
        "build-manpages": ['setuptools;python_version>="3.12"'],
    },
)

And in build_manpages.py:

try:
    from distutils.core import Command 
    from distutils.errors import DistutilsOptionError
except ImportError:
    raise ImportError(
        'To use the build_manpages tool on Python 3.12+, '
        'you need to install argparse-manpage[build-manpages].'
    )

And in the README, you recommend adding argparse-manpage[build-manpages] to pyproject.toml's [build-system] requires / tox / nox dependencies or other requirements.

musicinmybrain commented 2 years ago

I think you’ll find that even the CLI tool requires distutils, perhaps accidentally, and that regardless of intent, distutils currently still functions as a hard dependency in practice.

In v3, as released on PyPI, build_manpages/cli.py imports from build_manpages.build_manpage

https://github.com/praiskup/argparse-manpage/blob/34017d1865a4c97ddb13a1e80333bfb4ace93351/build_manpages/cli.py#L10

…which imports distutils:

https://github.com/praiskup/argparse-manpage/blob/34017d1865a4c97ddb13a1e80333bfb4ace93351/build_manpages/build_manpage.py#L12-L13


In the unreleased main, this does’t seem to be the case, but distutils still gets imported, because importing build_manpages/cli.py means build_manpages/__init__.py gets imported, and that imports build_manpages/build_manpages.py

https://github.com/praiskup/argparse-manpage/blob/28151c24bfc80d33140b2fcf69400ba5fde907df/build_manpages/__init__.py#L7

…and that still unconditionally imports distutils

https://github.com/praiskup/argparse-manpage/blob/28151c24bfc80d33140b2fcf69400ba5fde907df/build_manpages/build_manpages.py#L8-L9

…so one still sees:

PYTHON=python3.11 PYTHONPATH=$PWD PYTHONWARNINGS=d ./argparse-manpage 

 !! running argparse-manpage from git, this is not supported PYTHON=python3.11!!

/home/ben/src/argparse-manpage/build_manpages/build_manpages.py:8: DeprecationWarning: The distutils package is deprecated and slated for removal in Python 3.12. Use setuptools or check PEP 632 for potential alternatives
  from distutils.core import Command
praiskup commented 2 years ago

Thank you for the detailed analysis.

I plan a release soon, so let's keep v3 aside now.

In the unreleased main, this does’t seem to be the case, but distutils still gets imported, because importing build_manpages/cli.py means build_manpages/init.py gets imported, and that imports build_manpages/build_manpages.py…

Hm, importing cli.py really implies importing init.py, and thus distutils? I'd like to do something like #69, but having even the dep on setuptools in the script seems bad. Is there a way around it?

hroncok commented 2 years ago

Hm, importing cli.py really implies importing init.py

Always.

hroncok commented 2 years ago

You can wrap the entire thing that uses the classes in the try-except block from my comment.