Skip to content
This repository was archived by the owner on Nov 3, 2023. It is now read-only.

Commit 5ce1bbf

Browse files
committed
#133: Code review fixes
1 parent c525bfe commit 5ce1bbf

File tree

4 files changed

+81
-50
lines changed

4 files changed

+81
-50
lines changed

docs/release_notes.rst

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,10 @@ New Features
2222
will now be checked by default instead of D203, which required a single
2323
blank line before a class docstring (#137).
2424

25-
* Now handles configuration filed correctly. The closer a configuration file
26-
is to a checked file the more it matters (#133).
25+
* Configuration files are now handles correctly. The closer a configuration file
26+
is to a checked file the more it matters.
27+
Configuration files no longer support ``explain``, ``source``, ``debug``,
28+
``verbose`` or ``count`` (#133).
2729

2830
Bug Fixes
2931

docs/snippets/config.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ Inheritance
2727
###########
2828

2929
By default, when finding a configuration file, ``pep257`` tries to inherit
30-
the parent directory's configuration and migrate them to the local ones.
30+
the parent directory's configuration and merge them to the local ones.
3131

32-
The migration process is as follows:
32+
The merge process is as follows:
3333

3434
* If one of ``select``, ``ignore`` or ``convention`` was specified in the child
3535
configuration - Ignores the parent configuration and set the new error codes

src/pep257.py

Lines changed: 51 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
from itertools import takewhile, dropwhile, chain
2222
from re import compile as re
2323
import itertools
24-
from collections import defaultdict, namedtuple
24+
from collections import defaultdict, namedtuple, Set
2525

2626
try: # Python 3.x
2727
from ConfigParser import RawConfigParser
@@ -724,7 +724,7 @@ class ConfigurationParser(object):
724724
725725
Configuration files are nested within the file system, meaning that the
726726
closer a configuration file is to a checked file, the more relevant it will
727-
be. For instance, imagine this folder structure:
727+
be. For instance, imagine this directory structure:
728728
729729
A
730730
+-- tox.ini: sets `select=D100`
@@ -735,15 +735,15 @@ class ConfigurationParser(object):
735735
Then `foo.py` will not be checked for `D100`.
736736
The configuration build algorithm is described in `self._get_config`.
737737
738-
Note: If any of `MUTUALLY_EXCLUSIVE_OPTIONS` was selected in the CLI, all
738+
Note: If any of `BASE_ERROR_SELECTION_OPTIONS` was selected in the CLI, all
739739
configuration files will be ignored and each file will be checked for
740740
the error codes supplied in the CLI.
741741
742742
"""
743743

744744
CONFIG_FILE_OPTIONS = ('convention', 'select', 'ignore', 'add-select',
745745
'add-ignore', 'match', 'match-dir')
746-
MUTUALLY_EXCLUSIVE_OPTIONS = ('ignore', 'select', 'convention')
746+
BASE_ERROR_SELECTION_OPTIONS = ('ignore', 'select', 'convention')
747747

748748
DEFAULT_MATCH_RE = '(?!test_).*\.py'
749749
DEFAULT_MATCH_DIR_RE = '[^\.].*'
@@ -768,7 +768,7 @@ def get_default_run_configuration(self):
768768
def parse(self):
769769
"""Parse the configuration.
770770
771-
If one of `MUTUALLY_EXCLUSIVE_OPTIONS` was selected, overrides all
771+
If one of `BASE_ERROR_SELECTION_OPTIONS` was selected, overrides all
772772
error codes to check and disregards any error code related
773773
configurations from the configuration files.
774774
@@ -791,13 +791,16 @@ def get_user_run_configuration(self):
791791

792792
@check_initialized
793793
def get_files_to_check(self):
794-
"""Return a generator of files and error codes to check on each file.
794+
"""Generate files and error codes to check on each one.
795795
796796
Walk dir trees under `self._arguments` and generate yield filnames
797797
that `match` under each directory that `match_dir`.
798798
The method locates the configuration for each file name and yields a
799799
tuple of (filename, [error_codes]).
800800
801+
With every discovery of a new configuration file `IllegalConfiguration`
802+
might be raised.
803+
801804
"""
802805
def _get_matches(config):
803806
"""Return the `match` and `match_dir` functions for `config`."""
@@ -834,25 +837,25 @@ def _get_config(self, node):
834837
835838
The algorithm:
836839
-------------
837-
1. If the current directory's configuration exists in
838-
`self._cache` - return it.
839-
2. If a configuration file does not exist in this directory:
840-
3. If there's a parent directory:
841-
4. Cache it's configuration as this directory's and return it.
842-
5. Else:
843-
6. Cache a default configuration and return it.
844-
7. Else:
845-
8. Read the configuration file.
846-
9. If a parent directory exists AND the configuration file
847-
allows inheritance:
848-
10. Read the parent configuration by calling this function with the
849-
parent directory as `node`.
850-
11. Migrate the parent configuration with the current one and
851-
cache it.
852-
12. If the user has specified one of `MUTUALLY_EXCLUSIVE_OPTIONS` in
853-
the CLI - return the CLI configuration with the configuration match
854-
clauses
855-
13. Set the `--add-select` and `--add-ignore` CLI configurations.
840+
* If the current directory's configuration exists in
841+
`self._cache` - return it.
842+
* If a configuration file does not exist in this directory:
843+
* If the directory is not a root directory:
844+
* Cache its configuration as this directory's and return it.
845+
* Else:
846+
* Cache a default configuration and return it.
847+
* Else:
848+
* Read the configuration file.
849+
* If a parent directory exists AND the configuration file
850+
allows inheritance:
851+
* Read the parent configuration by calling this function with the
852+
parent directory as `node`.
853+
* Merge the parent configuration with the current one and
854+
cache it.
855+
* If the user has specified one of `BASE_ERROR_SELECTION_OPTIONS` in
856+
the CLI - return the CLI configuration with the configuration match
857+
clauses
858+
* Set the `--add-select` and `--add-ignore` CLI configurations.
856859
857860
"""
858861
path = os.path.abspath(node)
@@ -873,16 +876,16 @@ def _get_config(self, node):
873876
# Use the default configuration or the one given in the CLI.
874877
config = self._create_check_config(self._options)
875878
else:
876-
# There's a config file! Read it and migrate if necessary.
879+
# There's a config file! Read it and merge if necessary.
877880
options, inherit = self._read_configuration_file(config_file)
878881

879882
parent_dir, tail = os.path.split(path)
880883
if tail and inherit:
881-
# There is a parent dir and we should try to migrate.
884+
# There is a parent dir and we should try to merge.
882885
parent_config = self._get_config(parent_dir)
883-
config = self._migrate_configuration(parent_config, options)
886+
config = self._merge_configuration(parent_config, options)
884887
else:
885-
# No need to migrate or parent dir does not exist.
888+
# No need to merge or parent dir does not exist.
886889
config = self._create_check_config(options)
887890

888891
# Make the CLI always win
@@ -949,8 +952,8 @@ def _read_configuration_file(self, path):
949952

950953
return options, should_inherit
951954

952-
def _migrate_configuration(self, parent_config, child_options):
953-
"""Migrate parent config into the child options.
955+
def _merge_configuration(self, parent_config, child_options):
956+
"""Merge parent config into the child options.
954957
955958
The migration process requires an `options` object for the child in
956959
order to distinguish between mutually exclusive codes, add-select and
@@ -1057,18 +1060,18 @@ def _get_checked_errors(cls, options):
10571060

10581061
cls._set_add_options(checked_codes, options)
10591062

1060-
return checked_codes - set('')
1063+
return checked_codes
10611064

10621065
@classmethod
10631066
def _validate_options(cls, options):
10641067
"""Validate the mutually exclusive options.
10651068
1066-
Return `True` iff only zero or one of `MUTUALLY_EXCLUSIVE_OPTIONS` was
1067-
selected.
1069+
Return `True` iff only zero or one of `BASE_ERROR_SELECTION_OPTIONS`
1070+
was selected.
10681071
10691072
"""
10701073
for opt1, opt2 in \
1071-
itertools.permutations(cls.MUTUALLY_EXCLUSIVE_OPTIONS, 2):
1074+
itertools.permutations(cls.BASE_ERROR_SELECTION_OPTIONS, 2):
10721075
if getattr(options, opt1) and getattr(options, opt2):
10731076
log.error('Cannot pass both {0} and {1}. They are '
10741077
'mutually exclusive.'.format(opt1, opt2))
@@ -1085,27 +1088,34 @@ def _validate_options(cls, options):
10851088
def _has_exclusive_option(cls, options):
10861089
"""Return `True` iff one or more exclusive options were selected."""
10871090
return any([getattr(options, opt) for opt in
1088-
cls.MUTUALLY_EXCLUSIVE_OPTIONS])
1091+
cls.BASE_ERROR_SELECTION_OPTIONS])
10891092

10901093
@staticmethod
10911094
def _fix_set_options(options):
10921095
"""Alter the set options from None/strings to sets in place."""
10931096
optional_set_options = ('ignore', 'select')
10941097
mandatory_set_options = ('add_ignore', 'add_select')
10951098

1099+
def _get_set(value):
1100+
"""Split `value` by the delimiter `,` and return a set.
1101+
1102+
Removes any occurrences of '' in the set.
1103+
1104+
"""
1105+
return set(value.split(',')) - set('')
1106+
10961107
for opt in optional_set_options:
10971108
value = getattr(options, opt)
10981109
if value is not None:
1099-
value = set(value.split(','))
1100-
setattr(options, opt, value)
1110+
setattr(options, opt, _get_set(value))
11011111

11021112
for opt in mandatory_set_options:
11031113
value = getattr(options, opt)
11041114
if value is None:
11051115
value = ''
11061116

1107-
if not isinstance(value, set):
1108-
value = set(value.split(','))
1117+
if not isinstance(value, Set):
1118+
value = _get_set(value)
11091119

11101120
setattr(options, opt, value)
11111121

@@ -1258,6 +1268,7 @@ def run_pep257():
12581268
for filename, checked_codes in conf.get_files_to_check():
12591269
errors.extend(check((filename,), select=checked_codes))
12601270
except IllegalConfiguration:
1271+
# An illegal configuration file was found during file generation.
12611272
return INVALID_OPTIONS_RETURN_CODE
12621273

12631274
code = NO_VIOLATIONS_RETURN_CODE

src/tests/test_pep257.py

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,21 @@ def foo():
186186
assert 'D103' not in err
187187

188188

189+
def test_verbose():
190+
"""Test that passing --verbose to pep257 prints more information."""
191+
with Pep257Env() as env:
192+
with env.open('example.py', 'wt') as example:
193+
example.write('"""Module docstring."""\n')
194+
195+
out, _, code = env.invoke_pep257()
196+
assert code == 0
197+
assert 'example.py' not in out
198+
199+
out, _, code = env.invoke_pep257(args="--verbose")
200+
assert code == 0
201+
assert 'example.py' in out
202+
203+
189204
def test_count():
190205
"""Test that passing --count to pep257 correctly prints the error num."""
191206
with Pep257Env() as env:
@@ -405,7 +420,7 @@ def foo():
405420
def test_config_file_inheritance():
406421
"""Test configuration files inheritance.
407422
408-
The test creates 3 configuration files:
423+
The test creates 2 configuration files:
409424
410425
env_base
411426
+-- tox.ini
@@ -416,10 +431,13 @@ def test_config_file_inheritance():
416431
+-- test.py
417432
The file will contain code that violates D100,D103.
418433
419-
When invoking pep257 `test.py` the first config file will not set any
420-
of select/ignore/convention, therefore `pep257` will be set as the default
421-
convention. The config sets `inherit=false`, therefore we expect it not to
422-
set `select=` and raise all the errors stated above.
434+
When invoking pep257, the first config file found in the base directory
435+
will set `select=`, so no error codes should be checked.
436+
The `A/tox.ini` configuration file sets `inherit=false` but has an empty
437+
configuration, therefore the default convention will be checked.
438+
439+
We expect pep257 to ignore the `select=` configuration and raise all
440+
the errors stated above.
423441
424442
"""
425443
with Pep257Env() as env:
@@ -579,7 +597,7 @@ def test_cli_overrides_config_file():
579597
580598
We shall run pep257 with `--convention=pep257`.
581599
We expect `base.py` to be checked and violate `D100` and that `A/a.py` will
582-
not be checked because of `match-dir=B` in the config file.
600+
not be checked because of `match-dir=foo` in the config file.
583601
584602
"""
585603
with Pep257Env() as env:

0 commit comments

Comments
 (0)