Giter VIP home page Giter VIP logo

setup-cfg-fmt's Introduction

build status pre-commit.ci status

setup-cfg-fmt

apply a consistent format to setup.cfg files

installation

pip install setup-cfg-fmt

as a pre-commit hook

See pre-commit for instructions

Sample .pre-commit-config.yaml:

-   repo: https://github.com/asottile/setup-cfg-fmt
    rev: v2.5.0
    hooks:
    -   id: setup-cfg-fmt

cli

Consult the help for the latest usage:

$ setup-cfg-fmt --help

what does it do?

sets a consistent ordering for attributes

For example, name and version (the most important metadata) will always appear at the top.

 [metadata]
-version = 1.14.4
-name = pre_commit
+name = pre_commit
+version = 1.14.4

normalizes dashes to underscores in project name

  • pip will normalize names to dashes foo_bar => foo-bar
  • python setup.py sdist produces a filename with the name verbatim
  • pip wheel . produces a filename with an underscore-normalized name
$ # with dashed name
$ python setup.py sdist && pip wheel -w dist .
...
$ ls dist/ | cat
setup_cfg_fmt-0.0.0-py2.py3-none-any.whl
setup-cfg-fmt-0.0.0.tar.gz
$ # with underscore name
$ python setup.py sdist && pip wheel -w dist .
...
$ ls dist/ | cat
setup_cfg_fmt-0.0.0-py2.py3-none-any.whl
setup_cfg_fmt-0.0.0.tar.gz

This makes it easier to upload packages to pypi since they end up with the same filename prefix.

 [metadata]
-name = pre-commit
+name = pre_commit

normalizes dashes to underscores in keys

setuptools allows dashed names but does not document them.

 [metadata]
 name = pre-commit
-long-description = file: README.md
+long_description = file: README.md

adds long_description if README is present

This will show up on the pypi project page

 [metadata]
 name = pre_commit
 version = 1.14.5
+long_description = file: README.md
+long_description_content_type = text/markdown

adds license_file / license / license classifier if LICENSE exists

 [metadata]
 name = pre_commit
 version = 1.14.5
+license = MIT
+license_file = LICENSE
+classifiers =
+    License :: OSI Approved :: MIT License

set python_requires

A few sources are searched for guessing python_requires:

  • the existing python_requires setting itself
  • envlist in tox.ini if present
  • python version classifiers that are already set
  • the --min-py-version argument

adds python version classifiers

classifiers are generated based on:

  • the python_requires setting
  • the --max-py-version argument (currently defaulting to 3.11)
  • --include-version-classifiers is specified
 name = pkg
 version = 1.0
+classifiers =
+    Programming Language :: Python :: 3
+    Programming Language :: Python :: 3.7
+    Programming Language :: Python :: 3.8
+    Programming Language :: Python :: 3.9
+    Programming Language :: Python :: 3.10
+    Programming Language :: Python :: 3.11

without --include-version-classifiers only the major version will be included:

 name = pkg
 version = 1.0
+classifiers =
+    Programming Language :: Python :: 3

sorts classifiers

 [metadata]
 name = pre_commit
 version = 1.14.5
 classifiers =
-    Programming Language :: Python :: 3
-    License :: OSI Approved :: MIT License
+    License :: OSI Approved :: MIT License
+    Programming Language :: Python :: 3
     Programming Language :: Python :: 3.6

removes empty options in any section

 [options]
-dependency_links =
 python_requires = >= 3.6.1

related projects

setup-cfg-fmt's People

Contributors

1nf0rmed avatar asottile avatar basic-ph avatar gaborbernat avatar henryiii avatar hugovk avatar jkittner avatar jonaspammer avatar joshkarpel avatar mxr avatar nicoddemus avatar pre-commit-ci[bot] avatar ronnypfannschmidt avatar

Stargazers

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

Watchers

 avatar  avatar

setup-cfg-fmt's Issues

Wrongly formating "compatible release" clause

diff --git a/setup.cfg b/setup.cfg
index efc3a0f..662e52c 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -43,15 +43,15 @@ console_scripts =
 [options.extras_require]
 doc =
     furo
-    sphinx~=3.0
-    sphinx-autodoc-typehints~=1.10
-    sphinxcontrib-autoprogram~=0.1.0
+    sphinx-autodoc-typehints~~=1.10
+    sphinxcontrib-autoprogram~~=0.1.0
+    sphinx~~=3.0
 test =
-    filelock~=3.0
+    filelock~~=3.0
     pytest>=5,<=6
-    pytest-cov~=2.0
+    pytest-cov~~=2.0
     pytest-mock>=2,<=3
-    pytest-xdist~=1.34
+    pytest-xdist~~=1.34
 typing =
     mypy==0.790
     typing-extensions>=3.7.4.3

https://www.python.org/dev/peps/pep-0440/#compatible-release

check mode

Add a --check flag that prints the diff and fails the invocation.

Custom defined classifiers are stipped

Thanks, for this great tool for ensuring a consitent formatting of setup.cfg. I just came across it, and really like the intent of the project.

Unfortunately, I've hit a minor (hopefully in terms of fix as well) issue where any custom defined classifer that we have is stripped from the file.

One of the important uses for custom classifiers for us, is that we use them is to assist in preventing the unintentional uploading of internal package to pypi. Enabling a way to keep these custom classifiers, simple list of exclusions maybe via CLI would suffice.

Unable to install - error: command 'x86_64-linux-gnu-gcc' failed with exit status 1

I have tried adding

  -   repo: https://github.com/asottile/setup-cfg-fmt
      rev: v1.11.0
      hooks:
      -   id: setup-cfg-fmt
      

to my pre-commit-config.yaml file, and then running pre-commit run --all. However, I then get a very long error message. I've attached the .cache/pre-commit/pre-commit.log file
pre-commit.log

EDIT

for anyone else who lands here, do

sudo apt-get install python3 python-dev python3-dev      build-essential libssl-dev libffi-dev      libxml2-dev libxslt1-dev zlib1g-dev      

fix: add option for defining long_description

Hello!
Thanks for this awesome project and you determination to open source.

I use Asciidoctor for documentation.

Because PyPI does not support rendering this format, I made a CI workflow to convert my README.adoc to a README.md before building the python wheels and uploading to PyPI etc (unrelevant to this ticket, just a info).

The current alphabetical-sort determination made by this hook ranks .adoc (with content_type of text/plain) as first,
which results in PyPI showing The author of this package has not provided a project description as it does not support Asciidoctor.

I tried to do a workaround by renaming the markdown file to README-.md for it to rank first but then python/pypi does not like it:

...(README-.md file is not being copied)...

/tmp/build-env-cbglbinp/lib/python3.8/site-packages/setuptools/config/expand.py:142: UserWarning: File '/tmp/build-via-sdist-wi26p40b/test_application-0.3.6/README-.md' cannot be found
  warnings.warn(f"File {path!r} cannot be found")

warning: sdist: standard file not found: should have one of README, README.rst, README.txt, README.md

I then tried to do a workaround by renaming the markdown file to README, but then this hook determines it as text/plain.
I reverted to commenting this pre-commit hook out for now.

I'd like to add an option for defining the filename for long_description like this:

  - repo: https://github.com/asottile/setup-cfg-fmt
    rev: v1.20.2
    hooks:
      - id: setup-cfg-fmt
        long_description: README.md

I'd love to make my first PR for this!

`license_file` is deprecated; don't add it

When running python -m build

C:\Users\demberto\AppData\Local\Temp\build-env-nvavhwft\lib\site-packages\setuptools\config\setupcfg.py:463: SetuptoolsDeprecationWarning: The 
license_file parameter is deprecated, use license_files instead.
  warnings.warn(msg, warning_class)

Support `file:` for requires statements

Setuptools have added support file: for requires statements (as a beta feature)

I don't know if it makes sense to add support for this already, I just noticed it when going to test this feature.

Example

A simple setup.cfg (which works fine):

[metadata]
name = hi
version = 0.1.0
classifiers =
    Programming Language :: Python :: 3
    Programming Language :: Python :: 3 :: Only

[options]
packages = find:
python_requires = >=3.8

[options.extras_require]
dev = file:requirements-dev.txt

Then run $ setup-cfg-fmt setup.cfgt

 [options.extras_require]
-dev = file:requirements-dev.txt
+dev =
+    file:requirements-dev.txt

Then try to install the package (with pip install -e .[dev]), and setuptools will raise an error because can't parse this. Also, if we have a space between : and the filename, setup-cfg-fmt will exclude the filename.

 [options.extras_require]
-dev = file: requirements-dev.txt
+dev =
+    file:

interpolation, & extras that reference other extras

(edited: sorry, issue got submitted before done)

In order to create extras that reference other extras in setup.cfg, I have been using this hack/workaround mentioned in the setuptools issues: pypa/setuptools#1260 (comment)

[options.extras_require]
testing =
    pytest
dev =
    ipython
    mypy
    %(testing)s  # also include everything in the testing extras

It's been working fine for me for a while now.... though from what I gather, it really is a "hack" and seems to be taking advantage of interpolation which may be disappearing eventually?

It fails with setup-cfg-fmt however:

  File "/site-packages/setup_cfg_fmt.py", line 280, in _req_base
    assert basem
AssertionError

re.match(BASE_NAME_REGEX, lib) fails in _req_base... since lib is the empty string, caused by the fact that the ConfigParser cfg.get('options.extras_require', 'dev') would insert an extra line there: '\nipython\nmypy\n\npytest'

Moreover, even if it did work, setup-cfg-fmt would just return the literal pytest instead of the variable %(testing)s.

I see the problem is not related to this repo, so this is not so much a bug report as a question: do you have any workarounds for that use case that you use? Or do you just avoid doing that altogether?

Requirements starting with a capital letter are put at the beginning

Minimal example:

[metadata]
name = example_project
long_description = file: README.md
long_description_content_type = text/markdown

[options]
packages = find_namespace:
install_requires =
    aiohttp
    Babel

is rewritten to:

[metadata]
name = example_project
long_description = file: README.md
long_description_content_type = text/markdown

[options]
packages = find_namespace:
install_requires =
    Babel
    aiohttp

Add helpful error message when `assert basem` fails

def _req_base(lib: str) -> str:
basem = re.match(BASE_NAME_REGEX, lib)
assert basem
can fail with error that I'm finding hard to interpret. For example running this on https://github.com/ianhi/mpl-interactions/blob/0.18.0/setup.cfg fails with the below error and it's not clear to me how to fix it.

Traceback (most recent call last):
  File "/home/ian/mambaforge/envs/mpl-dev/bin/setup-cfg-fmt", line 8, in <module>
    sys.exit(main())
  File "/home/ian/mambaforge/envs/mpl-dev/lib/python3.9/site-packages/setup_cfg_fmt.py", line 502, in main
    if format_file(
  File "/home/ian/mambaforge/envs/mpl-dev/lib/python3.9/site-packages/setup_cfg_fmt.py", line 412, in format_file
    group_requires = _requires(cfg, key, 'options.extras_require')
  File "/home/ian/mambaforge/envs/mpl-dev/lib/python3.9/site-packages/setup_cfg_fmt.py", line 220, in _requires
    normalized = sorted(
  File "/home/ian/mambaforge/envs/mpl-dev/lib/python3.9/site-packages/setup_cfg_fmt.py", line 221, in <genexpr>
    (_normalize_req(req) for req in require_group),
  File "/home/ian/mambaforge/envs/mpl-dev/lib/python3.9/site-packages/setup_cfg_fmt.py", line 230, in _normalize_req
    normalized = _normalize_lib(lib)
  File "/home/ian/mambaforge/envs/mpl-dev/lib/python3.9/site-packages/setup_cfg_fmt.py", line 244, in _normalize_lib
    base = _req_base(lib)
  File "/home/ian/mambaforge/envs/mpl-dev/lib/python3.9/site-packages/setup_cfg_fmt.py", line 261, in _req_base
    assert basem
AssertionError

Add Implementation :: tags

    Programming Language :: Python :: Implementation :: CPython
    Programming Language :: Python :: Implementation :: PyPy

can probably use tox.ini as a heuristic

`variant=CommonMark` gets stripped from `long_description_content_type`

Minimal example:

  • setup.cfg:
[metadata]
name = example_project
long_description = file: README.md
long_description_content_type = text/markdown; charset=UTF-8; variant=CommonMark
  • README.md:
# Header

text

setup.cfg gets rewritten to:

[metadata]
name = example_project
long_description = file: README.md
long_description_content_type = text/markdown

This spec can be found here:
https://packaging.python.org/en/latest/specifications/core-metadata/#description-content-type

Support for stdin/stdout?

๐Ÿ‘‹ Thanks for setup-cfg-fmt, I'd be curious if you'd accept a patching adding support for reading the file from stdin and writing the output to stdout?

The use-case is for editor integration x)

additional extras removed

setup-cfg-fmt appears to remove any extras after the first one for requirements defined via URI:

install_requires =
    black@git+https://github.com/psf/black.git#egg=black[colorama,jupyter]
    black[colorama,jupyter]
install_requires =
    black@git+https://github.com/psf/black.git#egg=black[colorama
    black[colorama,jupyter]

Same happens for requirements defined in [options.extras_require]

Is there another way to define such extras? (or is it a bug)

Thanks for looking into it!

setup-cfg-fmt wipes valid empty extras

The following file is valid:

[metadata]
name = something
version = 1.0

[options]
packages = find:
install_requires =
    pytest>=6;extra == "test"

[options.extras_require]
test =

However, setup-cfg-fmt strips out the extras_require.test (and extras_require too due to #99, but the problem here is not an empty section, it's an empty item in a section), which breaks this usage of PEP 508 suggested as a replacement for #81. Empty extras should not be stripped, they are still valid. (You also might want an empty extra for other reasons, like something that used to be an extra dependency and isn't anymore - even if the current handling of extras is sloppy and doesn't error if one is requested and doesn't exist). But this turns a working file into a broken one.

How to use this plugin with setup.cfg comments?

I'm trying to add some comments to setup.cfg, but it seems like setup-cfg-fmt strips these from the file, and I couldn't find any docs about this in the README. Is this intended behaviour? Is there a way I can keep comments in setup.cfg?

Here's an example section, where the lines beginning with # get stripped by setup-cfg-fmt:

[options.extras_require]
docs =
    napari[all]
    numpydoc
    pydata-sphinx-theme
    # Disabled for now, as doesn't work on readthedocs
    # qtgallery 
    sphinx
    sphinx-automodapi
    sphinx-gallery

Setup-cfg-fmt doesn't respect newline convention of source file nor read/write it with the correct encoding

Setup-cfg-fmt does not respect the EOL of the setup.cfg, and instead converts it to a platform-dependent default. I'm not aware of a case where that would be the desirable behavior, whereas many/most projects standardize on one newline convention (typically \n) for all source files, which this breaks. Furthermore, if using an EoL fixer with pre-commit, it will catch this but aside from extra noise in the output, if it isn't sequenced after this hook in the config file, it will cause the next run to fail too.

Fixing this is very simpleโ€”just check the current EoL character when reading in the file, and pass that explicitly on writing it. So at the top of format_file(), on the line after read()ing the file, you'd just add newline = f.newlines, and then pass newline=newline in the call to open() when writing it,

In addition, neither open() call specifies the correct encoding to use, which means the platform and environment-dependent locale encoding will be assumed. As setup.cfg is required to be UTF-8, this means loading will fail on Windows if any non-ASCII characters are present (common in e.g. authors' names), or on any platform that doesn't have UTF-8 mode enabled, and even if loading were to succeed, the file would be written in the incorrect encoding. Furthermore, not specifying an encoding when opening in text mode will be an optional warning in Python 3.10, with a DeprecationWarning planned to follow in later versions. To fix this, simply explicitly pass encoding="utf-8" to both calls.

Happy to submit a PR to fix both of these if you'd like. Thanks!

Identify licenses more generically

# TODO: pick a better way to identify licenses
if 'Permission is hereby granted, free of charge, to any' in license_s:
cfg['metadata']['license'] = 'MIT'
cfg['metadata']['classifiers'] = (
cfg['metadata'].get('classifiers', '').rstrip() +
'\nLicense :: OSI Approved :: MIT License'
)

github uses this

I haven't found an equivalent in python, but it would probably be easy to write one that does the same approach

`setup-cfg` removes the empty `packages`

When I run setup-cfg-fmt setup.cfg, it removes the following valid line from the file.

[options]
python_requires = >=3.8
-packages = 
+

Since I have setup-cfg as part of my pre-commit hook, it made me set the skipsdist to true in tox.

_normalize_req causes error when requirement uses url

This isn't a bug with setup-cfg-fmt but a bug in all python versions< 3.9 or released before 2021-12-16.
If the requirement uses an URL for example

qtsass@https://github.com/spyder-ide/qtsass/archive/refs/heads/master.zip ;python_version >= '3.10'

It needs a space before the ; or it will cause a parsing error

InvalidRequirement: Parse error at "">= '3.10"": Expected string_end

This makes setup-cfg-fmt unusable for projects which have to use an URL in their requirements.

return f'{normalized};{envs}'

This change should fix the issue.

-     return f'{normalized};{envs}'
+     return f'{normalized} ;{envs}'

Since nearly all python versions are affected it would be nice if setup-cfg-fmt would implement this workaround.

pre-commit fails to install setup-cfg-fmt hook

This hooks is not working for me. It looks like pre-commit fails to build/install dependencies of this hook. I get the following error

          gcc -Wno-unused-result -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -fomit-frame-pointer -g -fno-semantic-interposition -fomit-frame-pointer -g -fno-semantic-interposition -fomit-frame-pointer -g -fno-semantic-interposition -DTHREAD_STACK_SIZE=0x100000 -fPIC -I. -I/home/circleci/.cache/pre-commit/repok21wtj75/py_env-python3/include -I/usr/include/python3.8 -c _ukkonen.cpp -o build/temp.linux-x86_64-3.8/_ukkonen.o
          _ukkonen.cpp:4:23: error: 'int64_t' does not name a type
              4 | template <typename T> int64_t edit_distance_k_impl(
                |                       ^~~~~~~
          _ukkonen.cpp:99:12: error: 'int64_t' does not name a type
             99 | extern "C" int64_t edit_distance_k(
                |            ^~~~~~~
          error: command '/usr/bin/gcc' failed with exit code 1

I'm building running it from within my docker container which is located at https://github.com/Sceptre/sceptre-circleci/blob/v0.8.0/Dockerfile

Here is the environment:

~/sceptrelint $ cat /etc/os-release
NAME="Alpine Linux"
ID=alpine
VERSION_ID=3.13.5
PRETTY_NAME="Alpine Linux v3.13"
HOME_URL="https://alpinelinux.org/"
BUG_REPORT_URL="https://bugs.alpinelinux.org/"

~/sceptrelint $ uname -a
Linux b802316d64f6 5.10.47-linuxkit #1 SMP Sat Jul 3 21:51:47 UTC 2021 x86_64 Linux

~/sceptrelint $ python -V
Python 3.8.9

(test1) ~/sceptrelint $ pip freeze
attrs==21.4.0
cfgv==3.3.1
covdefaults==2.2.0
coverage==6.3.2
distlib==0.3.4
filelock==3.6.0
identify==2.4.11
iniconfig==1.1.1
nodeenv==1.6.0
packaging==21.3
platformdirs==2.5.1
pluggy==1.0.0

pre-commit==2.17.0
py==1.11.0
pyparsing==3.0.7
pytest==7.0.1
PyYAML==6.0
six==1.16.0
toml==0.10.2
tomli==2.0.1
virtualenv==20.13.2


(test1) ~/sceptrelint $ cat .pre-commit-config.yaml
repos:
-   repo: https://github.com/asottile/setup-cfg-fmt
    rev: v1.20.0
    hooks:
    -   id: setup-cfg-fmt

pre-commit run log

Standardise on license_files, omit when possible?

About:

adds license_file / license / license classifier if LICENSE exists

Newly released Setuptools 56.0.0 (changelog, docs, PR, issue) has deprecated license_file, and license_files should be used instead.

Further, if license_files is omitted, it defaults to LICEN[CS]E*, COPYING*, NOTICE*, AUTHORS*, matching the behaviour of bdist_wheel.


To simplify a project's config, I removed license_file = LICENCE from a project's setup.cfg, but then setup-cfg-fmt put it back :)


Should setup-cfg-fmt standardise license_file -> license_files?

And, if the value matches the glob pattern, should setup-cfg-fmt omit it completely?

Thanks!

allow passing '-' as filename, print reformatted setup.cfg to stdout

Was trying to set this up to autoformat my setup.cfg files in neovim, and the easiest way to do that (with the plugin I use) is to be able to read from STDIN/write back to STDOUT which then replaces the contents of the buffer. I ended up just wrapping it in a script like:

#!/usr/bin/env bash
set -e
tfile="$(mktemp -t setup.cfg.XXXXXX -p "$(pwd)")"
cat >"$tfile"
setup-cfg-fmt "$@" "$tfile" >&2 || true
cat "$tfile"
command rm -f "$tfile"

and that works, but would be nice to be able to avoid the tempfile.

So, proposed feature is to be able to call this with like setup-cfg-fmt - <setup.cfg, and it prints the formatted setup.cfg to stdout

If you're ok with adding this, I can make a PR

KeyError: 'metadata'

Here is my setup.cfg file:

[bumpversion]
current_version = 0.2.1

[flake8]
ignore = E203,E503,W504
max-line-length = 120
exclude = venv,.*

[pydocstyle]
add-ignore = D104

[mypy]
disallow_untyped_defs = True

[mypy-pytest]
ignore_missing_imports = True

[mypy-_pytest.capture]
ignore_missing_imports = True

[mypy-setuptools]
ignore_missing_imports = True

[mypy-setup]
ignore_errors = True

[mypy-conf]
ignore_errors = True

Here's the error from pre-commit run --all:

setup-cfg-fmt............................................................Failed
- hook id: setup-cfg-fmt
- exit code: 1

Traceback (most recent call last):
  File "/home/marco/.cache/pre-commit/repoowkkinfn/py_env-python3/bin/setup-cfg-fmt", line 8, in <module>
    sys.exit(main())
  File "/home/marco/.cache/pre-commit/repoowkkinfn/py_env-python3/lib/python3.8/site-packages/setup_cfg_fmt.py", line 456, in main
    if format_file(
  File "/home/marco/.cache/pre-commit/repoowkkinfn/py_env-python3/lib/python3.8/site-packages/setup_cfg_fmt.py", line 331, in format_file
    cfg['metadata']['name'] = cfg['metadata']['name'].replace('-', '_')
  File "/usr/lib/python3.8/configparser.py", line 960, in __getitem__
    raise KeyError(key)
KeyError: 'metadata'

Interpolation variables aren't handled properly

Minimal example 1:

[metadata]
name = example_project

[options]
packages = find_namespace:

[options.extras_require]
all =
    %(postgres)s
postgres =
    asyncpg

gets rewritten to:

[metadata]
name = example_project

[options]
packages = find_namespace:

[options.extras_require]
all =
    asyncpg
postgres =
    asyncpg

Minimal example 2:

[metadata]
name = example_project

[options]
packages = find_namespace:

[options.extras_require]
postgres =
    asyncpg
sqlite =
    aiosqlite
all =
    %(postgres)s
    %(sqlite)s

raises:

Traceback (most recent call last):
  File "/home/ubuntu/check-how-setup-cfg-fmt-works/bin/setup-cfg-fmt", line 8, in <module>
    sys.exit(main())
  File "/home/ubuntu/check-how-setup-cfg-fmt-works/lib/python3.8/site-packages/setup_cfg_fmt.py", line 503, in main
    if format_file(
  File "/home/ubuntu/check-how-setup-cfg-fmt-works/lib/python3.8/site-packages/setup_cfg_fmt.py", line 413, in format_file
    group_requires = _requires(cfg, key, 'options.extras_require')
  File "/home/ubuntu/check-how-setup-cfg-fmt-works/lib/python3.8/site-packages/setup_cfg_fmt.py", line 220, in _requires
    normalized = sorted(
  File "/home/ubuntu/check-how-setup-cfg-fmt-works/lib/python3.8/site-packages/setup_cfg_fmt.py", line 221, in <genexpr>
    (_normalize_req(req) for req in require_group),
  File "/home/ubuntu/check-how-setup-cfg-fmt-works/lib/python3.8/site-packages/setup_cfg_fmt.py", line 230, in _normalize_req
    normalized = _normalize_lib(lib)
  File "/home/ubuntu/check-how-setup-cfg-fmt-works/lib/python3.8/site-packages/setup_cfg_fmt.py", line 244, in _normalize_lib
    base = _req_base(lib)
  File "/home/ubuntu/check-how-setup-cfg-fmt-works/lib/python3.8/site-packages/setup_cfg_fmt.py", line 261, in _req_base
    assert basem
AssertionError

Return 0 to avoid errors with setup-cfg-fmt in Makefile

Hi!

I am using setup-cfg-fmt in a makefile. When I run make format it returns an error.

The makefile command

format:
	setup-cfg-fmt setup.cfg

Output from terminal when I run make format

setup-cfg-fmt setup.cfg
Rewriting setup.cfg
make: *** [format] Error 1

The script works as expected and updates setup.cfg.

I cannot see any error in your script, but maybe it is because the script returns the variable retv set to 1 if it completes successfully, and Make expects programs return 0 if there aren't any errors.

Can you make a small change to the script and set the variable retv to 0 if it runs successfully? Another option is to not return retv if it isn't used.

Packages within the optional extras_requires "features" are not sorted

Currently the packages listed within an optional extra is not sorted but the identifers themselves are.

If we start with the following snippet contained within a setup.cfg. Where dev and ci are not sorted, as well as the packages within dev are not sorted.

[options.extras_require]
dev =
    pytest
    hypothesis
ci =
    hypothesis
    pytest

Running pre-commit fails as expected.

$ pre-commit run setup-cfg-fmt --all-files
setup-cfg-fmt............................................................Failed
- hook id: setup-cfg-fmt
- files were modified by this hook

Rewriting setup.cfg

However, it only returns the following:

[options.extras_require]
ci =
    hypothesis
    pytest
dev =
    pytest
    hypothesis

While the ci feature is sorted and placed above dev correctly, currently the packages contained within dev are not sorted similarly to how install_requires and setup_requires

I'm thinking there should be consistent behaviour, with the extra_require packages being sorted as well, therefore resulting in the following when checked:

[options.extras_require]
ci =
    hypothesis
    pytest
dev =
    hypothesis
    pytest

Is this something that you'd like to support and are you happy to accept a PR on this change in behaviour?

Min version in envlist, when less than the default value for `min-py3-version`, is overridden

When setup-cfg-fmt is run on a library with no arguments and no config except tox.ini with an envlist, then the tool uses a minimum version parsed from tox.ini. For example this test passes:

def test_guess_python_envlist_py38(tmpdir):
    tmpdir.join('tox.ini').write('[tox]\nenvlist = py38\n')
    setup_cfg = tmpdir.join('setup.cfg')
    setup_cfg.write(
        '[metadata]\n'
        'name = pkg\n'
        'version = 1.0\n',
    )

    assert main((str(setup_cfg), ))

    assert setup_cfg.read() == (
        '[metadata]\n'
        'name = pkg\n'
        'version = 1.0\n'
        'classifiers =\n'
        '    Programming Language :: Python :: 3\n'
        '    Programming Language :: Python :: 3 :: Only\n'
        '    Programming Language :: Python :: Implementation :: CPython\n'
        '\n'
        '[options]\n'
        'python_requires = >=3.8\n'
    )
$ pytest -q -k test_guess_python_envlist_py38 tests\setup_cfg_fmt_test.py
.                                                                                                                               [100%]
1 passed, 66 deselected in 0.04s

But when envlist has a lower minimum version (ex: py36) than the default, then python_requires gets set to >= 3.7 incorrectly.

def test_guess_python_envlist_py36(tmpdir):
    tmpdir.join('tox.ini').write('[tox]\nenvlist = py36\n')
    setup_cfg = tmpdir.join('setup.cfg')
    setup_cfg.write(
        '[metadata]\n'
        'name = pkg\n'
        'version = 1.0\n',
    )

    assert main((str(setup_cfg), ))

    assert setup_cfg.read() == (
        '[metadata]\n'
        'name = pkg\n'
        'version = 1.0\n'
        'classifiers =\n'
        '    Programming Language :: Python :: 3\n'
        '    Programming Language :: Python :: 3 :: Only\n'
        '    Programming Language :: Python :: Implementation :: CPython\n'
        '\n'
        '[options]\n'
        'python_requires = >=3.6.1\n'
    )
$ pytest -q -k test_guess_python_envlist_py36 tests\setup_cfg_fmt_test.py
F                                                                                                                               [100%]
============================================================== FAILURES ==============================================================
___________________________________________________ test_guess_python_envlist_py36 ___________________________________________________

tmpdir = local('C:\\Users\\maxr\\AppData\\Local\\Temp\\pytest-of-maxr\\pytest-20\\test_guess_python_envlist_py360')

    def test_guess_python_envlist_py36(tmpdir):
        tmpdir.join('tox.ini').write('[tox]\nenvlist = py36\n')
        setup_cfg = tmpdir.join('setup.cfg')
        setup_cfg.write(
            '[metadata]\n'
            'name = pkg\n'
            'version = 1.0\n',
        )

        assert main((str(setup_cfg), ))

>       assert setup_cfg.read() == (
            '[metadata]\n'
            'name = pkg\n'
            'version = 1.0\n'
            'classifiers =\n'
            '    Programming Language :: Python :: 3\n'
            '    Programming Language :: Python :: 3 :: Only\n'
            '    Programming Language :: Python :: Implementation :: CPython\n'
            '\n'
            '[options]\n'
            'python_requires = >=3.6.1\n'
        )
E       AssertionError: assert '[metadata]\n...res = >=3.7\n' == '[metadata]\n...s = >=3.6.1\n'
E         Skipping 225 identical leading characters in diff, use -v to show
E         - res = >=3.6.1
E         ?           ^^^
E         + res = >=3.7
E         ?           ^

tests\setup_cfg_fmt_test.py:639: AssertionError
-------------------------------------------------------- Captured stdout call --------------------------------------------------------
Rewriting C:\Users\maxr\AppData\Local\Temp\pytest-of-maxr\pytest-20\test_guess_python_envlist_py360\setup.cfg
====================================================== short test summary info =======================================================
FAILED tests/setup_cfg_fmt_test.py::test_guess_python_envlist_py36 - AssertionError: assert '[metadata]\n...res = >=3.7\n' == '[metadata]\n...s = >=3.6.1\n'
1 failed, 66 deselected in 0.07s

`python_requires` gets rewriten even when `--min-py-version` is **not** specified

Currently setup-cfg-fmt applies the default setting of 3.8 even to config files that specify they allow smaller python version. This should happen in my opinion, only if the user specifies a --min-py-version should it override the existing values.

steps to reproduce:

assume the following setup.cfg:

[metadata]
name = tinker
classifiers =
    Programming Language :: Python :: 3
    Programming Language :: Python :: 3 :: Only
    Programming Language :: Python :: 3.7
    Programming Language :: Python :: 3.8

[options]
python_requires = >=3.7

now running setup-cfg-fmt --include-version-classifiers setup.cfg will update the version-classifiers and require_python to a minimum of 3.8

Notes

this is already fixed in #178. installing pip install -U git+https://github.com/mxr/setup-cfg-fmt#parse-min and running the command again results in the expected behavior

setup-cfg-fmt removes comments from setup.cfg

I've used setup-cfg-fmt 1.11.0 as a pre-commit hook with my setup.cfg and as a result setup-cfg-fmt removed all comments from init file.
I think it better to get opportunity to settings up this behaviour

`python_requires` not written when only `--min-py3-version` is specified

See repro:

def test_guess_python_min_version(tmpdir):
    setup_cfg = tmpdir.join('setup.cfg')
    setup_cfg.write(
        '[metadata]\n'
        'name = pkg\n'
        'version = 1.0\n',
    )

    assert main((str(setup_cfg), '--min-py3-version=3.8'))
$ pytest -vvv -k test_guess_python_min_version tests/setup_cfg_fmt_test.py
========================================= test session starts ==========================================
platform darwin -- Python 3.9.15, pytest-6.2.4, py-1.10.0, pluggy-0.13.1 -- /Users/mxr/src/mxr/unkey/venv/bin/python
cachedir: .pytest_cache
rootdir: /Users/mxr/src/asottile/setup-cfg-fmt
collected 67 items / 66 deselected / 1 selected                                                        

tests/setup_cfg_fmt_test.py::test_guess_python_min_version FAILED                                [100%]

=============================================== FAILURES ===============================================
____________________________________ test_guess_python_min_version _____________________________________

tmpdir = local('/private/var/folders/mg/2_7nx7493qg0vn9jhdp951tw0000gp/T/pytest-of-mxr/pytest-10/test_guess_python_min_version0')

    def test_guess_python_min_version(tmpdir):
        setup_cfg = tmpdir.join('setup.cfg')
        setup_cfg.write(
            '[metadata]\n'
            'name = pkg\n'
            'version = 1.0\n',
        )
    
>       assert main((str(setup_cfg), '--min-py3-version=3.8'))
E       AssertionError: assert 0
E        +  where 0 = main(('/private/var/folders/mg/2_7nx7493qg0vn9jhdp951tw0000gp/T/pytest-of-mxr/pytest-10/test_guess_python_min_version0/setup.cfg', '--min-py3-version=3.8'))

tests/setup_cfg_fmt_test.py:667: AssertionError
======================================= short test summary info ========================================
FAILED tests/setup_cfg_fmt_test.py::test_guess_python_min_version - AssertionError: assert 0
=================================== 1 failed, 66 deselected in 0.17s ===================================

Support comments

Hi,

I like the tool and would like to use it in pre-commit, but it removes comments (lines starting with #) from my setup.cfg.

I know the support won't be that easy since ConfigParser doesn't keep the comments in a structure.

automatically striping python 3.4

My expression of:

python_requires = >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*
automatically is rewritten to:

python_requires = >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*

Why is that?

classifiers should be version sorted

notably they currently sort like this which seems bad:

    Programming Language :: Python :: 3
    Programming Language :: Python :: 3 :: Only
    Programming Language :: Python :: 3.10
    Programming Language :: Python :: 3.7
    Programming Language :: Python :: 3.8
    Programming Language :: Python :: 3.9

license_file parameter is deprecated

setup-cfg-fmt forces a deprecated parameter - license_file

$ python -m build
/tmp/build-env-8hhvq6p_/lib/python3.10/site-packages/setuptools/config/setupcfg.py:459: SetuptoolsDeprecationWarning: The license_file parameter is deprecated, use license_files instead.
  warnings.warn(msg, warning_class)

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.