@@ -186,6 +186,9 @@ class ConfigurationParser:
186186 DEFAULT_MATCH_RE = r'(?!test_).*\.py'
187187 DEFAULT_MATCH_DIR_RE = r'[^\.].*'
188188 DEFAULT_IGNORE_DECORATORS_RE = ''
189+ DEFAULT_PROPERTY_DECORATORS = (
190+ "property,cached_property,functools.cached_property"
191+ )
189192 DEFAULT_CONVENTION = conventions .pep257
190193
191194 PROJECT_CONFIG_FILES = (
@@ -266,12 +269,21 @@ def _get_ignore_decorators(conf):
266269 re (conf .ignore_decorators ) if conf .ignore_decorators else None
267270 )
268271
272+ def _get_property_decorators (conf ):
273+ """Return the `property_decorators` as None or set."""
274+ return (
275+ set (conf .property_decorators .split ("," ))
276+ if conf .property_decorators
277+ else None
278+ )
279+
269280 for name in self ._arguments :
270281 if os .path .isdir (name ):
271282 for root , dirs , filenames in os .walk (name ):
272283 config = self ._get_config (os .path .abspath (root ))
273284 match , match_dir = _get_matches (config )
274285 ignore_decorators = _get_ignore_decorators (config )
286+ property_decorators = _get_property_decorators (config )
275287
276288 # Skip any dirs that do not match match_dir
277289 dirs [:] = [d for d in dirs if match_dir (d )]
@@ -283,13 +295,20 @@ def _get_ignore_decorators(conf):
283295 full_path ,
284296 list (config .checked_codes ),
285297 ignore_decorators ,
298+ property_decorators ,
286299 )
287300 else :
288301 config = self ._get_config (os .path .abspath (name ))
289302 match , _ = _get_matches (config )
290303 ignore_decorators = _get_ignore_decorators (config )
304+ property_decorators = _get_property_decorators (config )
291305 if match (name ):
292- yield (name , list (config .checked_codes ), ignore_decorators )
306+ yield (
307+ name ,
308+ list (config .checked_codes ),
309+ ignore_decorators ,
310+ property_decorators ,
311+ )
293312
294313 # --------------------------- Private Methods -----------------------------
295314
@@ -485,7 +504,12 @@ def _merge_configuration(self, parent_config, child_options):
485504 self ._set_add_options (error_codes , child_options )
486505
487506 kwargs = dict (checked_codes = error_codes )
488- for key in ('match' , 'match_dir' , 'ignore_decorators' ):
507+ for key in (
508+ 'match' ,
509+ 'match_dir' ,
510+ 'ignore_decorators' ,
511+ 'property_decorators' ,
512+ ):
489513 kwargs [key ] = getattr (child_options , key ) or getattr (
490514 parent_config , key
491515 )
@@ -519,9 +543,15 @@ def _create_check_config(cls, options, use_defaults=True):
519543 checked_codes = cls ._get_checked_errors (options )
520544
521545 kwargs = dict (checked_codes = checked_codes )
522- for key in ('match' , 'match_dir' , 'ignore_decorators' ):
546+ defaults = {
547+ 'match' : "MATCH_RE" ,
548+ 'match_dir' : "MATCH_DIR_RE" ,
549+ 'ignore_decorators' : "IGNORE_DECORATORS_RE" ,
550+ 'property_decorators' : "PROPERTY_DECORATORS" ,
551+ }
552+ for key , default in defaults .items ():
523553 kwargs [key ] = (
524- getattr (cls , f' DEFAULT_{ key . upper () } _RE' )
554+ getattr (cls , f" DEFAULT_{ default } " )
525555 if getattr (options , key ) is None and use_defaults
526556 else getattr (options , key )
527557 )
@@ -855,14 +885,33 @@ def _create_option_parser(cls):
855885 )
856886 ),
857887 )
888+ option (
889+ '--property-decorators' ,
890+ metavar = '<property-decorators>' ,
891+ default = None ,
892+ help = (
893+ "consider any method decorated with one of these "
894+ "decorators as a property, and consequently allow "
895+ "a docstring which is not in imperative mood; default "
896+ "is --property-decorators='{}'" .format (
897+ cls .DEFAULT_PROPERTY_DECORATORS
898+ )
899+ ),
900+ )
858901
859902 return parser
860903
861904
862905# Check configuration - used by the ConfigurationParser class.
863906CheckConfiguration = namedtuple (
864907 'CheckConfiguration' ,
865- ('checked_codes' , 'match' , 'match_dir' , 'ignore_decorators' ),
908+ (
909+ 'checked_codes' ,
910+ 'match' ,
911+ 'match_dir' ,
912+ 'ignore_decorators' ,
913+ 'property_decorators' ,
914+ ),
866915)
867916
868917
0 commit comments