Repository: asottile/setup-cfg-fmt

Issue:
Identify other types of READMEs
https://github.com/asottile/setup-cfg-fmt/blob/3492c51eaa557e645c78a217de82f54ba6df75a3/setup_cfg_fmt.py#L46-L49

Might be able to leverage [`identify`](https://github.com/chriskuehl/identify) as well

Comments:

Patch:
diff --git a/setup_cfg_fmt.py b/setup_cfg_fmt.py
index ef7c2f7..2fb21cf 100644
--- a/setup_cfg_fmt.py
+++ b/setup_cfg_fmt.py
@@ -1,8 +1,11 @@
 import argparse
 import configparser
+import glob
 import io
 import os.path
+import re
 from typing import Dict
+from typing import Match
 from typing import Optional
 from typing import Sequence
 from typing import Tuple
@@ -66,6 +69,30 @@ def _adjacent_filename(setup_cfg: str, filename: str) -> str:
     return os.path.join(os.path.dirname(setup_cfg), filename)
 
 
+GLOB_PART = re.compile(r'(\[[^]]+\]|.)')
+
+
+def _case_insensitive_glob(s: str) -> str:
+    def cb(match: Match[str]) -> str:
+        match_s = match.group()
+        if len(match_s) == 1:
+            return f'[{match_s.upper()}{match_s.lower()}]'
+        else:
+            inner = ''.join(f'{c.upper()}{c.lower()}' for c in match_s[1:-1])
+            return f'[{inner}]'
+
+    return GLOB_PART.sub(cb, s)
+
+
+def _first_file(setup_cfg: str, prefix: str) -> Optional[str]:
+    prefix = _case_insensitive_glob(prefix)
+    path = _adjacent_filename(setup_cfg, prefix)
+    for filename in glob.iglob(f'{path}*'):
+        return filename
+    else:
+        return None
+
+
 def format_file(filename: str) -> bool:
     with open(filename) as f:
         contents = f.read()
@@ -77,14 +104,23 @@ def format_file(filename: str) -> bool:
     cfg['metadata']['name'] = cfg['metadata']['name'].replace('-', '_')
 
     # if README.md exists, set `long_description` + content type
-    if os.path.exists(_adjacent_filename(filename, 'README.md')):
-        cfg['metadata']['long_description'] = 'file: README.md'
-        cfg['metadata']['long_description_content_type'] = 'text/markdown'
+    readme = _first_file(filename, 'readme')
+    if readme is not None:
+        long_description = f'file: {os.path.basename(readme)}'
+        cfg['metadata']['long_description'] = long_description
+
+        tags = identify.tags_from_filename(readme)
+        if 'markdown' in tags:
+            cfg['metadata']['long_description_content_type'] = 'text/markdown'
+        elif 'rst' in tags:
+            cfg['metadata']['long_description_content_type'] = 'text/x-rst'
+        else:
+            cfg['metadata']['long_description_content_type'] = 'text/plain'
 
     # set license fields if a license exists
-    license_filename = _adjacent_filename(filename, 'LICENSE')
-    if os.path.exists(license_filename):
-        cfg['metadata']['license_file'] = 'LICENSE'
+    license_filename = _first_file(filename, 'licen[sc]e')
+    if license_filename is not None:
+        cfg['metadata']['license_file'] = os.path.basename(license_filename)
 
         license_id = identify.license_id(license_filename)
         if license_id is not None:


Test patch:
diff --git a/tests/setup_cfg_fmt_test.py b/tests/setup_cfg_fmt_test.py
index cfda96a..c01262c 100644
--- a/tests/setup_cfg_fmt_test.py
+++ b/tests/setup_cfg_fmt_test.py
@@ -1,8 +1,21 @@
 import pytest
 
+from setup_cfg_fmt import _case_insensitive_glob
 from setup_cfg_fmt import main
 
 
+@pytest.mark.parametrize(
+    ('s', 'expected'),
+    (
+        ('foo', '[Ff][Oo][Oo]'),
+        ('FOO', '[Ff][Oo][Oo]'),
+        ('licen[sc]e', '[Ll][Ii][Cc][Ee][Nn][SsCc][Ee]'),
+    ),
+)
+def test_case_insensitive_glob(s, expected):
+    assert _case_insensitive_glob(s) == expected
+
+
 def test_noop(tmpdir):
     setup_cfg = tmpdir.join('setup.cfg')
     setup_cfg.write(
@@ -87,8 +100,18 @@ def test_rewrite(input_s, expected, tmpdir):
     assert setup_cfg.read() == expected
 
 
-def test_adds_long_description_with_readme(tmpdir):
-    tmpdir.join('README.md').write('my project!')
+@pytest.mark.parametrize(
+    ('filename', 'content_type'),
+    (
+        ('README.rst', 'text/x-rst'),
+        ('README.markdown', 'text/markdown'),
+        ('README.md', 'text/markdown'),
+        ('README', 'text/plain'),
+        ('readme.txt', 'text/plain'),
+    ),
+)
+def test_adds_long_description_with_readme(filename, content_type, tmpdir):
+    tmpdir.join(filename).write('my project!')
     setup_cfg = tmpdir.join('setup.cfg')
     setup_cfg.write(
         '[metadata]\n'
@@ -99,16 +122,19 @@ def test_adds_long_description_with_readme(tmpdir):
     assert main((str(setup_cfg),))
 
     assert setup_cfg.read() == (
-        '[metadata]\n'
-        'name = pkg\n'
-        'version = 1.0\n'
-        'long_description = file: README.md\n'
-        'long_description_content_type = text/markdown\n'
+        f'[metadata]\n'
+        f'name = pkg\n'
+        f'version = 1.0\n'
+        f'long_description = file: {filename}\n'
+        f'long_description_content_type = {content_type}\n'
     )
 
 
-def test_sets_license_file_if_license_exists(tmpdir):
-    tmpdir.join('LICENSE').write('COPYRIGHT (C) 2019 ME')
+@pytest.mark.parametrize(
+    'filename', ('LICENSE', 'LICENCE', 'LICENSE.md', 'license.txt'),
+)
+def test_sets_license_file_if_license_exists(filename, tmpdir):
+    tmpdir.join(filename).write('COPYRIGHT (C) 2019 ME')
     setup_cfg = tmpdir.join('setup.cfg')
     setup_cfg.write(
         '[metadata]\n'
@@ -119,10 +145,10 @@ def test_sets_license_file_if_license_exists(tmpdir):
     assert main((str(setup_cfg),))
 
     assert setup_cfg.read() == (
-        '[metadata]\n'
-        'name = pkg\n'
-        'version = 1.0\n'
-        'license_file = LICENSE\n'
+        f'[metadata]\n'
+        f'name = pkg\n'
+        f'version = 1.0\n'
+        f'license_file = {filename}\n'
     )