diff --git a/.github/workflows/codespell-private.yml b/.github/workflows/codespell-private.yml index fa9c5fa51e..711c4104d4 100644 --- a/.github/workflows/codespell-private.yml +++ b/.github/workflows/codespell-private.yml @@ -2,6 +2,9 @@ # For general usage in your repo, see the example in codespell.yml # https://github.com/codespell-project/codespell name: codespell Private Actions +concurrency: + group: ${{ github.workflow }}-${{ github.event.number }}-${{ github.event.ref }} + cancel-in-progress: true on: [push, pull_request] jobs: test: @@ -10,12 +13,13 @@ jobs: # Make sure we're using the latest aspell dictionary runs-on: ubuntu-20.04 strategy: + fail-fast: false matrix: python-version: - - 3.6 - - 3.7 - - 3.8 - - 3.9 + - '3.7' + - '3.8' + - '3.9' + - '3.10' name: Python ${{ matrix.python-version }} test steps: - uses: actions/checkout@v3 diff --git a/README.rst b/README.rst index 9a3f7c7425..058e565f5c 100644 --- a/README.rst +++ b/README.rst @@ -23,7 +23,7 @@ Useful links Requirements ------------ -Python 3.6 or above. +Python 3.7 or above. Installation ------------ @@ -107,6 +107,13 @@ This is equivalent to running:: codespell --quiet-level 3 --count --skip "*.po,*.ts,./src/3rdParty,./src/Test" +Now codespell also support ``pyproject.toml``:: + + [tool.codespell] + skip = '*.po,*.ts,./src/3rdParty,./src/Test' + count = '' + quiet-level = 3 + Any options specified in the command line will *override* options from the config file. diff --git a/codespell_lib/_codespell.py b/codespell_lib/_codespell.py index fdad69d4e5..e2c73d3bcd 100644 --- a/codespell_lib/_codespell.py +++ b/codespell_lib/_codespell.py @@ -392,7 +392,8 @@ def parse_options(args): help='print LINES of surrounding context') parser.add_argument('--config', type=str, help='path to config file.') - + parser.add_argument('--toml', type=str, + help='path to a pyproject.toml file.') parser.add_argument('files', nargs='*', help='files or directories to check') @@ -404,6 +405,18 @@ def parse_options(args): if options.config: cfg_files.append(options.config) config = configparser.ConfigParser() + + # Read toml before other config files. + if options.toml: + try: + import tomli + except Exception as exc: + raise ImportError( + f'tomli is required to read pyproject.toml but could not be ' + f'imported, got: {exc}') from None + with open(options.toml, 'rb') as f: + data = tomli.load(f).get('tool', {}) + config.read_dict(data) config.read(cfg_files) if config.has_section('codespell'): diff --git a/codespell_lib/tests/test_basic.py b/codespell_lib/tests/test_basic.py index 64beddd6af..5679f7fa32 100644 --- a/codespell_lib/tests/test_basic.py +++ b/codespell_lib/tests/test_basic.py @@ -791,35 +791,45 @@ def test_uri_regex_def(): assert not uri_regex.findall(boilerplate % uri), uri -def test_config(tmpdir, capsys): - """ - Tests loading options from a config file. - """ - d = str(tmpdir) - - # Create sample files. - with open(op.join(d, 'bad.txt'), 'w') as f: +@pytest.mark.parametrize('kind', ('toml', 'cfg')) +def test_config_toml(tmp_path, capsys, kind): + """Test loading options from a config file or toml.""" + d = tmp_path / 'files' + d.mkdir() + with open(d / 'bad.txt', 'w') as f: f.write('abandonned donn\n') - with open(op.join(d, 'good.txt'), 'w') as f: + with open(d / 'good.txt', 'w') as f: f.write("good") - # Create a config file. - conffile = op.join(d, 'config.cfg') - with open(conffile, 'w') as f: - f.write( - '[codespell]\n' - 'skip = bad.txt\n' - 'count = \n' - ) - # Should fail when checking both. - code, stdout, _ = cs.main(d, count=True, std=True) + code, stdout, _ = cs.main(str(d), count=True, std=True) # Code in this case is not exit code, but count of misspellings. assert code == 2 assert 'bad.txt' in stdout + if kind == 'cfg': + conffile = str(tmp_path / 'config.cfg') + args = ('--config', conffile) + with open(conffile, 'w') as f: + f.write("""\ +[codespell] +skip = bad.txt, whatever.txt +count = +""") + else: + assert kind == 'toml' + pytest.importorskip('tomli') + tomlfile = str(tmp_path / 'pyproject.toml') + args = ('--toml', tomlfile) + with open(tomlfile, 'w') as f: + f.write("""\ +[tool.codespell] +skip = 'bad.txt,whatever.txt' +count = false +""") + # Should pass when skipping bad.txt - code, stdout, _ = cs.main('--config', conffile, d, count=True, std=True) + code, stdout, _ = cs.main(str(d), *args, count=True, std=True) assert code == 0 assert 'bad.txt' not in stdout diff --git a/setup.cfg b/setup.cfg index d46869cad7..fe05ee4f73 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,5 @@ [tool:pytest] -addopts = --cov=codespell_lib --showlocals -rs --cov-report= +addopts = --cov=codespell_lib -rs --cov-report= --tb=short [flake8] exclude = build, ci-helpers diff --git a/setup.py b/setup.py index 8a6c8c7349..1971123436 100755 --- a/setup.py +++ b/setup.py @@ -43,7 +43,7 @@ 'Operating System :: Unix', 'Operating System :: MacOS'], platforms='any', - python_requires='>=3.6', + python_requires='>=3.7', packages=[ 'codespell_lib', 'codespell_lib.tests', @@ -58,9 +58,12 @@ 'codespell = codespell_lib:_script_main' ], }, + # TODO: toml will need to be updated when 3.11 comes out as it's a + # CPython module there extras_require={ "dev": ["check-manifest", "flake8", "pytest", "pytest-cov", - "pytest-dependency"], + "pytest-dependency", "tomli"], "hard-encoding-detection": ["chardet"], + "toml": ["tomli"], } )