2121from itertools import takewhile , dropwhile , chain
2222from re import compile as re
2323import itertools
24- from collections import defaultdict , namedtuple
24+ from collections import defaultdict , namedtuple , Set
2525
2626try : # 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
0 commit comments