Giter VIP home page Giter VIP logo

setuptools-pyproject-migration's Introduction

setuptools-pyproject-migration

PyPI PyPI versions tests documentation Project Status: WIP โ€“ Initial development is in progress, but there has not yet been a stable, usable release suitable for the public. Ruff Code style: Black skeleton

Introduction

pyproject.toml represents the new era of Python packaging, but many old projects are still using setuptools. That's where this package comes in: just install it, run it, and it will print out a nicely formatted pyproject.toml file with the same metadata that you had in setup.py or setup.cfg.

Or at least, that's the goal. The project is currently a work in progress with only partial support for all the attributes that might exist in a setuptools configuration, so this won't yet work for anything complex. Feel free to file an issue to highlight anything that needs to be added!

Installation and usage

There are two different ways to install this project. You can use either or both depending on what you prefer.

Standalone application

To install setuptools-pyproject-migration as an application, we recommend using pipx (though of course you can also do this with pip install --user or in a virtual environment of your choice). First make sure you have pipx installed, then run

pipx install setuptools-pyproject-migration

After that, in any directory that has a setup.py and/or setup.cfg file, you can run

setuptools-pyproject-migration

and it will print out the content of pyproject.toml as computed from your setup.py and/or setup.cfg. Running setuptools-pyproject-migration -h will print a brief usage summary.

You can also install and run the application in one go as follows:

pipx run setuptools-pyproject-migration

Virtual environment

Or you can use setuptools-pyproject-migration in a virtual environment you use to develop your project. Activate your virtual environment and then run

python -m pip install `setuptools-pyproject-migration

and then running

python setup.py pyproject

will print out the content of your pyproject.toml file.

History

Inspired by a conversation on Mastodon.

setuptools-pyproject-migration's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

setuptools-pyproject-migration's Issues

Use pyprojecttoml.apply_configuration() in tests to verify generated pyproject.toml

setuptools includes the function setuptools.config.pyprojecttoml.apply_configuration(), which takes a Distribution object and a pyproject.toml file path and applies the settings in the given pyproject.toml file to the Distribution, overwriting existing fields where they exist. We could use this to help check that the pyproject.toml files generated by our package will be parsed by setuptools in the same way as the original setup.cfg or setup.py.

This is just an idea; we can decide whether to actually do it later.

Support keywords

This issue entails adding support for writing the keywords field in pyproject.toml when it is defined statically in the setuptools configuration.

Support description

This issue entails adding support for writing the description field in pyproject.toml when it is defined statically in the setuptools configuration.

Write some meaningful documentation

Right now our generated HTML documentation is pretty bare-bones, basically just the (extremely minimal) API of the setuptools command class. This issue entails filling it out a bit with usage instructions and other more useful stuff.

Keywords not split by commas

When running tests/distribution/test_distribution_packages.py::TestExternalProject::test_keywords[pytest==7.3.0], setuptools-pyproject-migration generates a list of keywords split on commas, whereas the test support code does not split on commas. (Unless I got that backwards?) We should fix the test support code accordingly.

self = <test_distribution_packages.TestExternalProject object at 0x7f32b0cb92d0>
expected = StandardMetadata(name='pytest', version=<Version('7.3.0')>, description='pytest: simple powerful testing with Python',...are Development :: Testing', 'Topic :: Utilities'], keywords=['test,unittest'], scripts={}, gui_scripts={}, dynamic=[])
actual = StandardMetadata(name='pytest', version=<Version('7.3.0')>, description='pytest: simple powerful testing with Python',..., 'unittest'], scripts={'pytest': 'pytest:console_main', 'py.test': 'pytest:console_main'}, gui_scripts={}, dynamic=[])

    def test_keywords(self, expected: StandardMetadata, actual: StandardMetadata):
>       assert sorted(expected.keywords) == sorted(actual.keywords)
E       AssertionError: assert ['test,unittest'] == ['test', 'unittest']
E         At index 0 diff: 'test,unittest' != 'test'
E         Right contains one more item: 'unittest'
E         Full diff:
E         - ['test', 'unittest']
E         ?       - --
E         + ['test,unittest']

/home/diazona/programming/setuptools-pyproject-migration/tests/distribution/test_distribution_packages.py:167: AssertionError

Add Stuart as a collaborator on PyPI

I reserved the package name setuptools-pyproject-migration on both PyPI and Test PyPI by uploading an early version of the project and then deleting it - so the project pages aren't publicly visible, but I have control over the name. @sjlongland whenever you get around to it - and there's really no rush on this - send me your account(s) on both sites and I'll add you as a co-owner.

Enable towncrier

We have a configuration file for towncrier in the repository (inherited from https://github.com/jaraco/skeleton), so I figure we might as well make use of it. All the cool projects have a changelog, and using towncrier to maintain one is going to be slightly less annoying than doing it manually.

Actually I started working on this a little already a couple days ago while I was waiting for some other stuff, just to see how tricky it would be... seems like it's fairly straightforward. The only significant change is that every PR now has to include a changelog fragment.

@sjlongland any thoughts on this? I think if we're going to do it, best to get it out of the way now. (This should be my last last-minute addition to the initial release milestone ๐Ÿ˜›)

Support extras

This issue entails adding support for writing the optional-dependencies field in pyproject.toml when it is defined statically in the setuptools configuration.

Empty emails are not accepted by setuptools

Given a setup.cfg with author but not author_email, this tool produces a pyproject.toml like:

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

[project]
name = "example"
version = "1"
authors = [{name = "A Hacker", email = ""}]

setuptools fails validation for such a package:

$ python -m build
* Creating virtualenv isolated environment...
* Installing packages in isolated environment... (setuptools)
* Getting build dependencies for sdist...
configuration error: `project.authors[0].email` must be idn-email
DESCRIPTION:
    MUST be a valid email address

GIVEN VALUE:
    ""

OFFENDING RULE: 'format'

DEFINITION:
    {
        "type": "string",
        "format": "idn-email"
    }
Traceback (most recent call last):
  File "/.../pyproject_hooks/_in_process/_in_process.py", line 353, in <module>
    main()
  File "/.../pyproject_hooks/_in_process/_in_process.py", line 335, in main
    json_out['return_val'] = hook(**hook_input['kwargs'])
                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/.../pyproject_hooks/_in_process/_in_process.py", line 287, in get_requires_for_build_sdist
    return hook(config_settings)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/private/.../setuptools/build_meta.py", line 358, in get_requires_for_build_sdist
    return self._get_build_requires(config_settings, requirements=[])
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/private/.../setuptools/build_meta.py", line 325, in _get_build_requires
    self.run_setup()
  File "/private/.../setuptools/build_meta.py", line 341, in run_setup
    exec(code, locals())
  File "<string>", line 1, in <module>
  File "/private/.../setuptools/__init__.py", line 103, in setup
    return distutils.core.setup(**attrs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/private/.../setuptools/_distutils/core.py", line 159, in setup
    dist.parse_config_files()
  File "/private/.../_virtualenv.py", line 23, in parse_config_files
    result = old_parse_config_files(self, *args, **kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/private/.../setuptools/dist.py", line 653, in parse_config_files
    pyprojecttoml.apply_configuration(self, filename, ignore_option_errors)
  File "/private/.../setuptools/config/pyprojecttoml.py", line 66, in apply_configuration
    config = read_configuration(filepath, True, ignore_option_errors, dist)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/private/.../setuptools/config/pyprojecttoml.py", line 127, in read_configuration
    validate(subset, filepath)
  File "/private/.../setuptools/config/pyprojecttoml.py", line 55, in validate
    raise ValueError(f"{error}\n{summary}") from None
ValueError: invalid pyproject.toml config: `project.authors[0].email`.
configuration error: `project.authors[0].email` must be idn-email

ERROR Backend subprocess exited when trying to invoke get_requires_for_build_sdist

I think this tool should avoid outputting an empty email string for authors and maintainers if none is present. setuptools is fine with that.

Support license-files [PEP-639]

So, in issue #32 I was thrown off-course by the setuptools documentation, which documented both license and license_files fields.

It was not clear whether the license field was sometimes read from a file instead of being verbatim text, or how the license_files influenced this field.

Experimental work suggested the two fields do not interact; a license file described in license_files does not yield text appearing in the license field. Furthermore, setuptools does not support the file: prefix to denote text as coming from an external file as it does with other fields.

Having seen the library mentioned in issue #74 and reading the official Python package specification linked within (https://packaging.python.org/en/latest/specifications/core-metadata/#license), it is apparent this is a setuptools extension, undergoing discussion for inclusion under PEP-639 (https://peps.python.org/pep-0639/).

As such, we're probably better off waiting until a decision is made on PEP-639 before implementing it.

Support entry points

This issue entails adding support for writing the entry-points, gui-scripts, and scripts fields in pyproject.toml when they are defined statically in the setuptools configuration.

Support classifiers

This issue entails adding support for writing the classifiers field in pyproject.toml when it is defined statically in the setuptools configuration.

Support license

This issue entails adding support for writing the license field in pyproject.toml when it is defined statically in the setuptools configuration.

Inconsistent handling of authors without email addresses

When running tests/distribution/test_distribution_packages.py::TestExternalProject::test_authors[pytest==7.3.0], setuptools-pyproject-migration uses None to represent the absence of an email address, whereas the test support code uses an empty string. (Unless I got those backwards?) We should make them consistent.

self = <test_distribution_packages.TestExternalProject object at 0x7f32b0cb4490>
expected = StandardMetadata(name='pytest', version=<Version('7.3.0')>, description='pytest: simple powerful testing with Python',...are Development :: Testing', 'Topic :: Utilities'], keywords=['test,unittest'], scripts={}, gui_scripts={}, dynamic=[])
actual = StandardMetadata(name='pytest', version=<Version('7.3.0')>, description='pytest: simple powerful testing with Python',..., 'unittest'], scripts={'pytest': 'pytest:console_main', 'py.test': 'pytest:console_main'}, gui_scripts={}, dynamic=[])

    def test_authors(self, expected: StandardMetadata, actual: StandardMetadata):
>       assert expected.authors == actual.authors
E       AssertionError: assert [('Holger Krekel', ''), ('Bruno Oliveira', ''), ('Ronny Pfannschmidt', ''), ('Floris Bruynooghe', ''), ('Brianna Laugher', ''), ('Florian Bruhin and others', '')] == [('Holger Krekel', None), ('Bruno Oliveira', None), ('Ronny Pfannschmidt', None), ('Floris Bruynooghe', None), ('Brianna Laugher', None), ('Florian Bruhin and others', None)]
E         At index 0 diff: ('Holger Krekel', '') != ('Holger Krekel', None)
E         Full diff:
E           [
E         -  ('Holger Krekel', None),
E         ?                    ^^^^
E         +  ('Holger Krekel', ''),
E         ?                    ^^
E         -  ('Bruno Oliveira', None),
E         ?                     ^^^^
E         +  ('Bruno Oliveira', ''),
E         ?                     ^^
E         -  ('Ronny Pfannschmidt', None),
E         ?                         ^^^^
E         +  ('Ronny Pfannschmidt', ''),
E         ?                         ^^
E         -  ('Floris Bruynooghe', None),
E         ?                        ^^^^
E         +  ('Floris Bruynooghe', ''),
E         ?                        ^^
E         -  ('Brianna Laugher', None),
E         ?                      ^^^^
E         +  ('Brianna Laugher', ''),
E         ?                      ^^
E         -  ('Florian Bruhin and others', None),
E         ?                                ^^^^
E         +  ('Florian Bruhin and others', ''),
E         ?                                ^^
E           ]

/home/diazona/programming/setuptools-pyproject-migration/tests/distribution/test_distribution_packages.py:155: AssertionError

I seem to remember having to make the test support code use a string in a couple places rather than None to satisfy type checking, or something like that, but I'm not sure. None is probably a better representation of the absence of an email address if we can do it.

Generate changelog for initial release

I figured that even though this is supposed to be wrapped up as part of the release process, making an issue for this is probably a good way to help make sure we don't forget to do it. Basically this just entails running towncrier (see #88), but given that it's the first release, we might want to manually edit in some extra changelog entries (or backfill changelog fragments for a bunch of the changes that were already merged, if that makes more sense) to give a more thorough overview of the package's development history.

Of course the generation of the changelog does not itself need a changelog fragment ๐Ÿ˜„

KeyError: 'long_description'

When running the distribution package test for pytest-localserver, we get a KeyError on line 311 of __init__.py:

                long_description_source = dist.command_options["metadata"]["long_description"][1]

To reproduce, run

$ tox run -e py311 -- 'tests/distribution/test_distribution_packages.py' -k pytest-localserver --runxfail

(or same on any other Python version)

Wrong dependencies computed for pytest

When running the test tests/distribution/test_distribution_packages.py::TestExternalProject::test_dependencies[pytest==7.3.0], setuptools-pyproject-migration generates three extra dependencies compared to what is extracted from pytest's own core metadata. (Though I didn't check whether the error is in setuptools-pyproject-migration or in the test support code that parses the core metadata.)

self = <test_distribution_packages.TestExternalProject object at 0x7f32b0ca5d50>
expected = StandardMetadata(name='pytest', version=<Version('7.3.0')>, description='pytest: simple powerful testing with Python',...are Development :: Testing', 'Topic :: Utilities'], keywords=['test,unittest'], scripts={}, gui_scripts={}, dynamic=[])
actual = StandardMetadata(name='pytest', version=<Version('7.3.0')>, description='pytest: simple powerful testing with Python',..., 'unittest'], scripts={'pytest': 'pytest:console_main', 'py.test': 'pytest:console_main'}, gui_scripts={}, dynamic=[])

    def test_dependencies(self, expected: StandardMetadata, actual: StandardMetadata):
>       assert sorted(expected.dependencies, key=str) == sorted(actual.dependencies, key=str)
E       assert [<Requirement('colorama; sys_platform == "win32"')>, <Requirement('exceptiongroup>=1.0.0rc8; python_version < "3.11"')>, <Requirement('importlib-metadata>=0.12; python_version < "3.8"')>, <Requirement('tomli>=1.0.0; python_version < "3.11"')>] == [<Requirement('colorama; sys_platform == "win32"')>, <Requirement('exceptiongroup>=1.0.0rc8; python_version < "3.11"')>, <Requirement('importlib-metadata>=0.12; python_version < "3.8"')>, <Requirement('iniconfig')>, <Requirement('packaging')>, <Requirement('pluggy<2.0,>=0.12')>, <Requirement('tomli>=1.0.0; python_version < "3.11"')>]
E         At index 3 diff: <Requirement('tomli>=1.0.0; python_version < "3.11"')> != <Requirement('iniconfig')>
E         Right contains 3 more items, first extra item: <Requirement('packaging')>
E         Full diff:
E           [
E            <Requirement('colorama; sys_platform == "win32"')>,
E            <Requirement('exceptiongroup>=1.0.0rc8; python_version < "3.11"')>,
E            <Requirement('importlib-metadata>=0.12; python_version < "3.8"')>,
E         -  <Requirement('iniconfig')>,
E         -  <Requirement('packaging')>,
E         -  <Requirement('pluggy<2.0,>=0.12')>,
E            <Requirement('tomli>=1.0.0; python_version < "3.11"')>,
E           ]

/home/diazona/programming/setuptools-pyproject-migration/tests/distribution/test_distribution_packages.py:138: AssertionError

Separate static checks from pytest

I want to separate the static code checks (black, mypy, ruff) so that they don't run as part of pytest. Instead they should run either as part of pre-commit, or as their own standalone tox environments. We only need to run these checks once, not for every Python version as we do with pytest, and besides the dependencies needed to run these tests as part of pytest are breaking compatibility with Python 3.6.

setuptools-pyproject-migration barfs if `long_description` specified in `setup.py`

So, aioax25 actually specifies everything in setup.py, including reading the README.md itself and importing the to-be-installed module to pick up the version number. Supporting that kind of abuse is probably against the scope of this project, but thankfully, the hand-edits to make it work weren't big:

I hand-edited the setup.py from this to this:

#!/usr/bin/env python3

from setuptools import setup
from os.path import dirname, join
from sys import version_info

requirements = [
        'pyserial',
        'signalslot',
        'pyserial_asyncio'
]

packages = [
        'aioax25',
        'aioax25.aprs',
]

setup(
        name='aioax25',
        url='https://github.com/sjlongland/aioax25/',
        version="0.0.12",
        author='Stuart Longland VK4MSL',
        author_email='[email protected]',
        license='GPL-2.0-or-later',
        packages=packages,
        requires=requirements,
        install_requires=requirements,
        description='Asynchronous AX.25 interface in pure Python using asyncio',
        long_description='file:README.md',
        long_description_content_type='text/markdown',
        classifiers=[
            'Development Status :: 2 - Pre-Alpha',
            'Environment :: No Input/Output (Daemon)',
            'Framework :: AsyncIO',
            'Intended Audience :: Developers',
            'License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+)',
            'Operating System :: POSIX',
            'Programming Language :: Python :: 3 :: Only',
            'Topic :: Communications :: Ham Radio'
        ]
)

This crashes, because when setuptools is invoked in this manner, it does not create a metadata key in the command_options property dict:

  File "/home/stuartl/.local/pipx/shared/lib/python3.11/site-packages/setuptools/_distutils/core.py", line 201, in run_commands
    dist.run_commands()
  File "/home/stuartl/.local/pipx/shared/lib/python3.11/site-packages/setuptools/_distutils/dist.py", line 969, in run_commands
    self.run_command(cmd)
  File "/home/stuartl/.local/pipx/shared/lib/python3.11/site-packages/setuptools/dist.py", line 989, in run_command
    super().run_command(command)
  File "/home/stuartl/.local/pipx/shared/lib/python3.11/site-packages/setuptools/_distutils/dist.py", line 988, in run_command
    cmd_obj.run()
  File "/home/stuartl/.local/pipx/venvs/setuptools-pyproject-migration/lib/python3.11/site-packages/setuptools_pyproject_migration/__init__.py", line 366, in run
    tomlkit.dump(self._generate(), sys.stdout)
                 ^^^^^^^^^^^^^^^^
  File "/home/stuartl/.local/pipx/venvs/setuptools-pyproject-migration/lib/python3.11/site-packages/setuptools_pyproject_migration/__init__.py", line 281, in _generate
    long_description_source: str = dist.command_options["metadata"]["long_description"][1]
                                   ~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^
KeyError: 'metadata'

Support authors and maintainers

This issue entails adding support for the authors and maintainers fields in pyproject.toml when they are defined statically in the setuptools configuration.

ModuleNotFoundError: No module named 'packaging'

I'm not sure what's different about my environment:

% pipx install setuptools-pyproject-migration
  installed package setuptools-pyproject-migration 0.1.0, installed using Python 3.11.5
  These apps are now globally available
    - setup-to-pyproject
done! โœจ ๐ŸŒŸ โœจ

% setup-to-pyproject
Traceback (most recent call last):
  File "/Users/nbatchelder/.local/bin/setup-to-pyproject", line 5, in <module>
    from setuptools_pyproject_migration.cli import main
  File "/Users/nbatchelder/.local/pipx/venvs/setuptools-pyproject-migration/lib/python3.11/site-packages/setuptools_pyproject_migration/__init__.py", line 7, in <module>
    from packaging.specifiers import SpecifierSet
ModuleNotFoundError: No module named 'packaging'

Change name of console script to match name of package

The pipx run command makes it very convenient to download a package and run a script entry point which has the same name as the package. If we want to take advantage of that convenience (and I'd say we do), we should change the name of our console script from setup-to-pyproject to setuptools-pyproject-migration. (Or at least we need to add a console script with that name, but I don't think there's any point in having two scripts that do the same thing, except for backward compatibility but we don't really have to care about that while the package is at such an early stage of development.)

Exclude generated files from coverage

The distribution package tests create a lot of Python files in temporary directories which get picked up by our coverage tool, but those files are from external packages and shouldn't be counted in our test coverage statistics. For example, everything under /tmp/pytest-of-diazona/pytest-104 here:

$ tox run -e py311 -- 'tests/distribution/test_distribution_packages.py'
[...]
---------- coverage: platform linux, python 3.11.6-final-0 -----------
Name                                                                                                                                                           Stmts   Miss  Cover   Missing
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
/tmp/pytest-of-diazona/pytest-104/aioax25==0.0.11.post00/project/aioax25-0.0.11.post0/aioax25/__init__.py                                                          5      0   100%
/tmp/pytest-of-diazona/pytest-104/pytest==7.3.00/project/pytest-7.3.0/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/__init__.py                            11      0   100%
/tmp/pytest-of-diazona/pytest-104/pytest==7.3.00/project/pytest-7.3.0/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_config.py                             80      7    91%   40, 44, 56, 67, 71-77
/tmp/pytest-of-diazona/pytest-104/pytest==7.3.00/project/pytest-7.3.0/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_entrypoints.py                        77     40    48%   15-16, 23-38, 70-74, 79-83, 91-106, 116, 126, 135-139
/tmp/pytest-of-diazona/pytest-104/pytest==7.3.00/project/pytest-7.3.0/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_get_version_impl.py                   73     31    58%   27-33, 40-42, 75-82, 95, 98-99, 112, 151-159, 163-174
/tmp/pytest-of-diazona/pytest-104/pytest==7.3.00/project/pytest-7.3.0/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_integration/__init__.py                0      0   100%
/tmp/pytest-of-diazona/pytest-104/pytest==7.3.00/project/pytest-7.3.0/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_integration/dump_version.py           36      7    81%   49-55, 65-66, 71, 92
/tmp/pytest-of-diazona/pytest-104/pytest==7.3.00/project/pytest-7.3.0/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_integration/pyproject_reading.py      53     21    60%   26, 37-43, 58-59, 65-69, 72, 74, 76-84
/tmp/pytest-of-diazona/pytest-104/pytest==7.3.00/project/pytest-7.3.0/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_integration/setuptools.py             62     22    65%   30, 56, 75-101, 113, 115, 118-119
/tmp/pytest-of-diazona/pytest-104/pytest==7.3.00/project/pytest-7.3.0/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_integration/toml.py                   37     12    68%   15, 18, 31-36, 51-55
/tmp/pytest-of-diazona/pytest-104/pytest==7.3.00/project/pytest-7.3.0/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_log.py                                59     25    58%   20, 24, 35-38, 60-69, 74-85
/tmp/pytest-of-diazona/pytest-104/pytest==7.3.00/project/pytest-7.3.0/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_modify_version.py                     30     21    30%   9-10, 14-18, 22-33, 37-45, 49-54, 60-61
/tmp/pytest-of-diazona/pytest-104/pytest==7.3.00/project/pytest-7.3.0/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_overrides.py                          28      2    93%   28, 47
/tmp/pytest-of-diazona/pytest-104/pytest==7.3.00/project/pytest-7.3.0/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_run_cmd.py                            95     57    40%   20, 41, 55, 64, 72-77, 90-93, 108-119, 123-126, 138-170, 175-176, 182-198, 206-207
/tmp/pytest-of-diazona/pytest-104/pytest==7.3.00/project/pytest-7.3.0/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_types.py                              16      2    88%   13-14
/tmp/pytest-of-diazona/pytest-104/pytest==7.3.00/project/pytest-7.3.0/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/_version_cls.py                        51     25    51%   10-12, 29-32, 36, 40, 46-48, 52, 54, 62-66, 73-78, 83-91
/tmp/pytest-of-diazona/pytest-104/pytest==7.3.00/project/pytest-7.3.0/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/discover.py                            33      3    91%   25, 39, 65
/tmp/pytest-of-diazona/pytest-104/pytest==7.3.00/project/pytest-7.3.0/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/fallbacks.py                           33     12    64%   9, 29, 33-44
/tmp/pytest-of-diazona/pytest-104/pytest==7.3.00/project/pytest-7.3.0/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/integration.py                         16      0   100%
/tmp/pytest-of-diazona/pytest-104/pytest==7.3.00/project/pytest-7.3.0/.eggs/setuptools_scm-8.0.4-py3.11.egg/setuptools_scm/version.py                            226    136    40%   20-23, 49-70, 74-82, 91-107, 112-113, 147, 150, 157, 173, 182-183, 191-196, 226-227, 231-234, 240-250, 254-262, 268-289, 293-299, 303-306, 321, 336-381, 385-395, 403, 407, 411, 415, 419-422, 431-440
src/setuptools_pyproject_migration/__init__.py                                                                                                                   155     14    91%   48, 138, 155, 231-241, 329, 345, 375, 390, 394, 403
test_support/test_support/__init__.py                                                                                                                             77     26    66%   23-24, 68, 112-123, 132, 141-147, 159-162, 176-177, 186, 220-222
test_support/test_support/distribution.py                                                                                                                        274     37    86%   35-46, 51-52, 67, 87, 125, 132, 138, 176, 311-314, 350, 358, 409-410, 444-445, 469, 504, 506, 512-513, 533-537, 555-556, 561-564, 567-569, 589
test_support/test_support/metadata.py                                                                                                                            131     27    79%   16-34, 46, 51-53, 56, 58, 103, 114, 116, 129, 140, 169, 177, 192, 203-204, 208, 215
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
TOTAL                                                                                                                                                           1658    527    68%
[...]

Add tests for TOML formatting style

As mentioned in PR #112, it'd be good to add a check to see that the default format more-or-less matches typical formatting styles used in the setuptools documentation; notably fields like license and authors use the inline table format where possible, as this is the style generally used in setuptools documentation.

Update development status to 3

This is a reminder that before releasing an initial version, we should update the trove classifier in setup.cfg to Development Status :: 3 - Alpha.

Rewrite release logic

I have a few changes in mind for the release logic:

  • Make it so that a release can only be uploaded to PyPI from Github (or more precisely, remove the logic that automates publishing a release with one command in order to make it difficult to upload a release without using Github). This is for traceability: it should be possible for anyone reviewing the project to see exactly how each release was generated and uploaded, and so that we have the "audit trail" of a Github tag and associated release notes for every release that makes it to PyPI.
  • Use trusted publishing instead of a token for authenticating to PyPI.
  • Upload any release to Test PyPI first to ensure that the upload works.

Support urls

This issue entails adding support for writing the urls field in pyproject.toml when it is defined statically in the setuptools configuration.

Can this generate pyproject.toml from requirements.txt or from import statements

I've been looking at building a tool that generates 'pyproject.toml' files from my python scripts and found this repo on Github.

What I'm looking for:

  1. you pip install <package name>
  2. Once its installed it scans the python code and generates the pyproject.toml file based on the existing scripts, settings or .idea since we are 100% a jetbrains shop.
  3. I'd like to help update the docs on a few items so you will see me lurking around the repo, loving the design of this.

Fix trusted publishing configuration

Something went wrong with our first release candidate, related to trusted publishing; that needs to be fixed. I'm not sure if it requires a fix in the code (unlikely), in the project settings here on Github, or in the project settings on Test PyPI (and in that case probably also regular PyPI).

Support readme

This issue entails adding support for writing the readme field in pyproject.toml when it is defined statically in the setuptools configuration.

Reduce code duplication in test_readme.py

In test_readme.py there are some pairs of tests that test essentially the same thing but with one using setup.py and the other using setup.cfg. It would be nice if there were a way to reduce that duplication, maybe by writing a fixture that can take the attributes to test as input and write out either file as needed.

Based on a comment on PR #103

Support requires-python

This issue entails adding support for writing the requires-python field in pyproject.toml when it is defined statically in the setuptools configuration.

Tests for Python 3.12 take a long time

I've noticed that the tests with Python 3.12 take much longer to finish, like 4-5 minutes compared to 1 minute for other Python versions. We should figure out why that is and fix it, especially if the same happens when using the project for real, not just in testing.

Enable pre-commit.ci

https://pre-commit.ci/ is a service that automatically runs pre-commit on all pull requests and can optionally automatically apply any necessary fixes, as well as automatically proposing updates to the hook versions in the pre-commit configuration.

@sjlongland what do you think, should we enable it? I don't think there's much to do except log in on the pre-commit.ci website and register the project.

Reduce frequency of pre-commit autoupdates

Right now every week we get a PR from the pre-commit CI service that tries to update all our hooks, including updating the ruff hook to a version which is incompatible with Python 3.6. We probably don't need weekly updates to this configuration, as there are basically never serious problems with the hooks that require an immediate update, so this issue would entail changing it to monthly or quarterly to reduce how often we have to deal with those PRs. (I've been meaning to make that change for a long time but never got around to it, just out of laziness.)

Or we could stop using the pre-commit.ci service entirely and just implement our own pre-commit workflow in this repo. That would let us avoid automatic updates entirely. (In fact we could even write our own separate logic to handle them, although that would be outside the scope of this issue.)

Optional dependencies not listed with their corresponding extras

When running the test tests/distribution/test_distribution_packages.py::TestExternalProject::test_optional_dependencies[pytest==7.3.0], setuptools-pyproject-migration does not list the corresponding extras as part of the Requirement objects.

I'm not sure what the correct approach should be; we can figure that out while solving this issue.

self = <test_distribution_packages.TestExternalProject object at 0x7f32b0ca7090>
expected = StandardMetadata(name='pytest', version=<Version('7.3.0')>, description='pytest: simple powerful testing with Python',...are Development :: Testing', 'Topic :: Utilities'], keywords=['test,unittest'], scripts={}, gui_scripts={}, dynamic=[])
actual = StandardMetadata(name='pytest', version=<Version('7.3.0')>, description='pytest: simple powerful testing with Python',..., 'unittest'], scripts={'pytest': 'pytest:console_main', 'py.test': 'pytest:console_main'}, gui_scripts={}, dynamic=[])

    def test_optional_dependencies(self, expected: StandardMetadata, actual: StandardMetadata):
        # Check that the set of extras is the same
        assert expected.optional_dependencies.keys() == actual.optional_dependencies.keys()
    
        # Check that the dependencies associated with each extra are the same
        for extra in expected.optional_dependencies:
>           assert sorted(expected.optional_dependencies[extra], key=str) == sorted(
                actual.optional_dependencies[extra], key=str
            )
E           assert [<Requirement('argcomplete; extra == "testing"')>, <Requirement('attrs>=19.2.0; extra == "testing"')>, <Requirement('hypothesis>=3.56; extra == "testing"')>, <Requirement('mock; extra == "testing"')>, <Requirement('nose; extra == "testing"')>, <Requirement('pygments>=2.7.2; extra == "testing"')>, <Requirement('requests; extra == "testing"')>, <Requirement('xmlschema; extra == "testing"')>] == [<Requirement('argcomplete')>, <Requirement('attrs>=19.2.0')>, <Requirement('hypothesis>=3.56')>, <Requirement('mock')>, <Requirement('nose')>, <Requirement('pygments>=2.7.2')>, <Requirement('requests')>, <Requirement('xmlschema')>]
E             At index 0 diff: <Requirement('argcomplete; extra == "testing"')> != <Requirement('argcomplete')>
E             Full diff:
E               [
E             -  <Requirement('argcomplete')>,
E             +  <Requirement('argcomplete; extra == "testing"')>,
E             ?                           ++++++++++++++++++++
E             -  <Requirement('attrs>=19.2.0')>,
E             +  <Requirement('attrs>=19.2.0; extra == "testing"')>,
E             ?                             ++++++++++++++++++++
E             -  <Requirement('hypothesis>=3.56')>,
E             +  <Requirement('hypothesis>=3.56; extra == "testing"')>,
E             ?                                ++++++++++++++++++++
E             -  <Requirement('mock')>,
E             -  <Requirement('nose')>,
E             +  <Requirement('mock; extra == "testing"')>,
E             +  <Requirement('nose; extra == "testing"')>,
E             -  <Requirement('pygments>=2.7.2')>,
E             +  <Requirement('pygments>=2.7.2; extra == "testing"')>,
E             ?                               ++++++++++++++++++++
E             -  <Requirement('requests')>,
E             -  <Requirement('xmlschema')>,
E             +  <Requirement('requests; extra == "testing"')>,
E             +  <Requirement('xmlschema; extra == "testing"')>,
E               ]

/home/diazona/programming/setuptools-pyproject-migration/tests/distribution/test_distribution_packages.py:146: AssertionError

"No module named 'distutils'" with old setuptools on Python 3.12

On Python 3.12, when running tests with old versions of setuptools (using --force-dep in tox), specifically version 56, the pre-testing setup fails with this error:

$ tox -r -e py312 --force-dep setuptools==56
[...]
py312: commands[0]> pytest tests/test_classifiers.py
ImportError while loading conftest '/home/diazona/programming/setuptools-pyproject-migration/tests/conftest.py'.
tests/conftest.py:4: in <module>
    import test_support
test_support/test_support/__init__.py:1: in <module>
    import distutils.core
E   ModuleNotFoundError: No module named 'distutils'
py312: exit 4 (0.40 seconds) /home/diazona/programming/setuptools-pyproject-migration> pytest tests/test_classifiers.py pid=31540

Discovered in this example in CI.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.