21
21
from itertools import takewhile , dropwhile , chain
22
22
from re import compile as re
23
23
import itertools
24
- from collections import defaultdict , namedtuple
24
+ from collections import defaultdict , namedtuple , Set
25
25
26
26
try : # Python 3.x
27
27
from ConfigParser import RawConfigParser
@@ -724,7 +724,7 @@ class ConfigurationParser(object):
724
724
725
725
Configuration files are nested within the file system, meaning that the
726
726
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:
728
728
729
729
A
730
730
+-- tox.ini: sets `select=D100`
@@ -735,15 +735,15 @@ class ConfigurationParser(object):
735
735
Then `foo.py` will not be checked for `D100`.
736
736
The configuration build algorithm is described in `self._get_config`.
737
737
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
739
739
configuration files will be ignored and each file will be checked for
740
740
the error codes supplied in the CLI.
741
741
742
742
"""
743
743
744
744
CONFIG_FILE_OPTIONS = ('convention' , 'select' , 'ignore' , 'add-select' ,
745
745
'add-ignore' , 'match' , 'match-dir' )
746
- MUTUALLY_EXCLUSIVE_OPTIONS = ('ignore' , 'select' , 'convention' )
746
+ BASE_ERROR_SELECTION_OPTIONS = ('ignore' , 'select' , 'convention' )
747
747
748
748
DEFAULT_MATCH_RE = '(?!test_).*\.py'
749
749
DEFAULT_MATCH_DIR_RE = '[^\.].*'
@@ -768,7 +768,7 @@ def get_default_run_configuration(self):
768
768
def parse (self ):
769
769
"""Parse the configuration.
770
770
771
- If one of `MUTUALLY_EXCLUSIVE_OPTIONS ` was selected, overrides all
771
+ If one of `BASE_ERROR_SELECTION_OPTIONS ` was selected, overrides all
772
772
error codes to check and disregards any error code related
773
773
configurations from the configuration files.
774
774
@@ -791,13 +791,16 @@ def get_user_run_configuration(self):
791
791
792
792
@check_initialized
793
793
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 .
795
795
796
796
Walk dir trees under `self._arguments` and generate yield filnames
797
797
that `match` under each directory that `match_dir`.
798
798
The method locates the configuration for each file name and yields a
799
799
tuple of (filename, [error_codes]).
800
800
801
+ With every discovery of a new configuration file `IllegalConfiguration`
802
+ might be raised.
803
+
801
804
"""
802
805
def _get_matches (config ):
803
806
"""Return the `match` and `match_dir` functions for `config`."""
@@ -834,25 +837,25 @@ def _get_config(self, node):
834
837
835
838
The algorithm:
836
839
-------------
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.
856
859
857
860
"""
858
861
path = os .path .abspath (node )
@@ -873,16 +876,16 @@ def _get_config(self, node):
873
876
# Use the default configuration or the one given in the CLI.
874
877
config = self ._create_check_config (self ._options )
875
878
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.
877
880
options , inherit = self ._read_configuration_file (config_file )
878
881
879
882
parent_dir , tail = os .path .split (path )
880
883
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 .
882
885
parent_config = self ._get_config (parent_dir )
883
- config = self ._migrate_configuration (parent_config , options )
886
+ config = self ._merge_configuration (parent_config , options )
884
887
else :
885
- # No need to migrate or parent dir does not exist.
888
+ # No need to merge or parent dir does not exist.
886
889
config = self ._create_check_config (options )
887
890
888
891
# Make the CLI always win
@@ -949,8 +952,8 @@ def _read_configuration_file(self, path):
949
952
950
953
return options , should_inherit
951
954
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.
954
957
955
958
The migration process requires an `options` object for the child in
956
959
order to distinguish between mutually exclusive codes, add-select and
@@ -1057,18 +1060,18 @@ def _get_checked_errors(cls, options):
1057
1060
1058
1061
cls ._set_add_options (checked_codes , options )
1059
1062
1060
- return checked_codes - set ( '' )
1063
+ return checked_codes
1061
1064
1062
1065
@classmethod
1063
1066
def _validate_options (cls , options ):
1064
1067
"""Validate the mutually exclusive options.
1065
1068
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.
1068
1071
1069
1072
"""
1070
1073
for opt1 , opt2 in \
1071
- itertools .permutations (cls .MUTUALLY_EXCLUSIVE_OPTIONS , 2 ):
1074
+ itertools .permutations (cls .BASE_ERROR_SELECTION_OPTIONS , 2 ):
1072
1075
if getattr (options , opt1 ) and getattr (options , opt2 ):
1073
1076
log .error ('Cannot pass both {0} and {1}. They are '
1074
1077
'mutually exclusive.' .format (opt1 , opt2 ))
@@ -1085,27 +1088,34 @@ def _validate_options(cls, options):
1085
1088
def _has_exclusive_option (cls , options ):
1086
1089
"""Return `True` iff one or more exclusive options were selected."""
1087
1090
return any ([getattr (options , opt ) for opt in
1088
- cls .MUTUALLY_EXCLUSIVE_OPTIONS ])
1091
+ cls .BASE_ERROR_SELECTION_OPTIONS ])
1089
1092
1090
1093
@staticmethod
1091
1094
def _fix_set_options (options ):
1092
1095
"""Alter the set options from None/strings to sets in place."""
1093
1096
optional_set_options = ('ignore' , 'select' )
1094
1097
mandatory_set_options = ('add_ignore' , 'add_select' )
1095
1098
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
+
1096
1107
for opt in optional_set_options :
1097
1108
value = getattr (options , opt )
1098
1109
if value is not None :
1099
- value = set (value .split (',' ))
1100
- setattr (options , opt , value )
1110
+ setattr (options , opt , _get_set (value ))
1101
1111
1102
1112
for opt in mandatory_set_options :
1103
1113
value = getattr (options , opt )
1104
1114
if value is None :
1105
1115
value = ''
1106
1116
1107
- if not isinstance (value , set ):
1108
- value = set (value . split ( ',' ) )
1117
+ if not isinstance (value , Set ):
1118
+ value = _get_set (value )
1109
1119
1110
1120
setattr (options , opt , value )
1111
1121
@@ -1258,6 +1268,7 @@ def run_pep257():
1258
1268
for filename , checked_codes in conf .get_files_to_check ():
1259
1269
errors .extend (check ((filename ,), select = checked_codes ))
1260
1270
except IllegalConfiguration :
1271
+ # An illegal configuration file was found during file generation.
1261
1272
return INVALID_OPTIONS_RETURN_CODE
1262
1273
1263
1274
code = NO_VIOLATIONS_RETURN_CODE
0 commit comments