Skip to content
This repository has been archived by the owner on Dec 16, 2022. It is now read-only.

Add support for pyproject.toml for configuration #173

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 64 additions & 33 deletions darglint/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@
Optional,
)

try:
import tomli
except ImportError:
_has_tomli = False
else:
_has_tomli = True

from .docstring.style import DocstringStyle
from .strictness import Strictness

Expand All @@ -39,6 +46,7 @@ def get_logger(): # type: () -> Logger
'.darglint',
'setup.cfg',
'tox.ini',
'pyproject.toml',
)

DEFAULT_DISABLED = {'DAR104'}
Expand Down Expand Up @@ -202,14 +210,14 @@ def load_config_file(filename): # type: (str) -> Configuration
filename: A valid filename to read from.

Raises:
ImportError: When trying to load a ".toml"-file without `tomli` installed.
Exception: When the configuration style is not a valid choice.

Returns:
A Configuration object.

"""
config = configparser.ConfigParser()
config.read(filename)
darglint_config = None
ignore = list()
enable = list()
message_template = None
Expand All @@ -220,46 +228,58 @@ def load_config_file(filename): # type: (str) -> Configuration
strictness = Strictness.FULL_DESCRIPTION
indentation = 4
log_level = LogLevel.CRITICAL
if 'darglint' in config.sections():
if 'ignore' in config['darglint']:
errors = config['darglint']['ignore']
if filename.lower().endswith('.toml'):
if not _has_tomli:
raise ImportError("Missing optional dependency `tomli`. Install with `pip install darglint['toml']`.")
with open(filename, "rb") as bin_config_file:
config = tomli.load(bin_config_file)
if 'darglint' in config['tool']:
darglint_config = config['tool']['darglint']
else:
config = configparser.ConfigParser()
config.read(filename)
if 'darglint' in config.sections():
darglint_config = config['darglint']
if darglint_config is not None:
if 'ignore' in darglint_config:
errors = darglint_config['ignore']
for error in errors.split(','):
ignore.append(error.strip())
if 'enable' in config['darglint']:
to_enable = config['darglint']['enable']
if 'enable' in darglint_config:
to_enable = darglint_config['enable']
for error in to_enable.split(','):
enable.append(error.strip())
if 'message_template' in config['darglint']:
message_template = config['darglint']['message_template']
if 'ignore_regex' in config['darglint']:
ignore_regex = config['darglint']['ignore_regex']
if 'ignore_raise' in config['darglint']:
to_ignore_raise = config['darglint']['ignore_raise']
if 'message_template' in darglint_config:
message_template = darglint_config['message_template']
if 'ignore_regex' in darglint_config:
ignore_regex = darglint_config['ignore_regex']
if 'ignore_raise' in darglint_config:
to_ignore_raise = darglint_config['ignore_raise']
for exception in to_ignore_raise.split(','):
ignore_raise.append(exception.strip())
if 'ignore_properties' in config['darglint']:
ignore_properties = bool(config['darglint']['ignore_properties'])
if 'docstring_style' in config['darglint']:
raw_style = config['darglint']['docstring_style']
if 'ignore_properties' in darglint_config:
ignore_properties = bool(darglint_config['ignore_properties'])
if 'docstring_style' in darglint_config:
raw_style = darglint_config['docstring_style']
style = DocstringStyle.from_string(raw_style)

if 'strictness' in config['darglint']:
raw_strictness = config['darglint']['strictness']
if 'strictness' in darglint_config:
raw_strictness = darglint_config['strictness']
strictness = Strictness.from_string(raw_strictness)

if 'indentation' in config['darglint']:
if 'indentation' in darglint_config:
try:
indentation = int(config['darglint']['indentation'])
indentation = int(darglint_config['indentation'])
except ValueError:
raise Exception(
'Unrecognized value for indentation. Expected '
'a non-zero, positive integer, but received {}'.format(
config['darglint']['indentation']
darglint_config['indentation']
)
)

if 'log_level' in config['darglint']:
log_level = LogLevel.from_string(config['darglint']['log_level'])
if 'log_level' in darglint_config:
log_level = LogLevel.from_string(darglint_config['log_level'])
return Configuration(
ignore=ignore,
message_template=message_template,
Expand Down Expand Up @@ -311,16 +331,27 @@ def find_config_file_in_path(path): # type: (str) -> Optional[str]
return None
for filename in filenames:
if filename in POSSIBLE_CONFIG_FILENAMES:
config = configparser.ConfigParser()
fully_qualified_path = os.path.join(path, filename)
try:
config.read(fully_qualified_path)
if 'darglint' in config.sections():
return fully_qualified_path
except configparser.ParsingError:
get_logger().error('Unable to parse file {}'.format(
fully_qualified_path
))
if filename.lower().endswith('.toml'):
try:
with open(filename, "rb") as bin_config_file:
config = tomli.load(bin_config_file)
if 'darglint' in config['tool']:
return fully_qualified_path
except tomli.TOMLDecodeError:
get_logger().error('Unable to parse file {}'.format(
fully_qualified_path
))
else:
config = configparser.ConfigParser()
try:
config.read(fully_qualified_path)
if 'darglint' in config.sections():
return fully_qualified_path
except configparser.ParsingError:
get_logger().error('Unable to parse file {}'.format(
fully_qualified_path
))
return None


Expand Down
2 changes: 2 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ def read_full_documentation(fname):


requirements = []
extra_requirements = {"toml": "tomli"}


class CleanCommand(Command):
Expand Down Expand Up @@ -72,6 +73,7 @@ def run(self):
setup_requires=requirements,
tests_require=['pytest', 'tox'] + requirements,
python_requires='>=3.6',
extras_require=extra_requirements,
classifiers=[
'Intended Audience :: Developers',
'Topic :: Software Development :: Documentation',
Expand Down
9 changes: 8 additions & 1 deletion tests/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,10 @@ def test_really_long_path(self, mock_getcwd):
class FindConfigFileInPathTestCase(TestCase):
"""Test that the config file is being found."""

@mock.patch('darglint.config.tomli')
@mock.patch('darglint.config.configparser.ConfigParser')
@mock.patch('darglint.config.os.listdir')
def test_filename_checked(self, mock_listdir, mock_ConfigParser):
def test_filename_checked(self, mock_listdir, mock_ConfigParser, mock_tomli):
"""Check that only the necessary filenames are identified. # noqa """
fake_files = [
''.join([choice(ascii_letters + '_-')
Expand All @@ -82,6 +83,12 @@ def read_file(filename):
return mock.MagicMock()

config_parser.read = read_file

def load_file(reader):
contents_checked.append('./' + reader.name)
return mock.MagicMock()

mock_tomli.load = load_file

find_config_file_in_path('./')

Expand Down
5 changes: 5 additions & 0 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ addopts = --ignore bin --ignore integration_tests/repos --ignore _data/

[testenv]
deps=pytest
extras=toml
commands=
pytest --ignore=integration_tests/ --ignore=_data/

Expand All @@ -15,6 +16,8 @@ commands=
[testenv:docker]
deps =
pytest
extras =
toml
allowlist_externals =
docker
commands =
Expand Down Expand Up @@ -62,6 +65,8 @@ deps=
flake8
flake8-docstrings
flake8-rst-docstrings
extras=
toml
commands =
# E2E tests
pytest integration_tests/end_to_end.py
Expand Down