Hello community,

here is the log from the commit of package python-cpplint for openSUSE:Factory 
checked in at 2020-04-01 19:20:56
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-cpplint (Old)
 and      /work/SRC/openSUSE:Factory/.python-cpplint.new.3248 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-cpplint"

Wed Apr  1 19:20:56 2020 rev:2 rq:790634 version:1.4.5

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-cpplint/python-cpplint.changes    
2019-02-26 22:22:45.938058395 +0100
+++ /work/SRC/openSUSE:Factory/.python-cpplint.new.3248/python-cpplint.changes  
2020-04-01 19:20:57.567601874 +0200
@@ -1,0 +2,8 @@
+Wed Apr  1 14:13:44 UTC 2020 - Marketa Calabkova <mcalabk...@suse.com>
+
+- update to 1.4.5
+  * Add support for c++17 tuple destructuring
+  * Travis CI: Add Python 3.8 to the testing
+  * Fix linting unnecessary elif after break
+
+-------------------------------------------------------------------

Old:
----
  cpplint-1.4.4.tar.gz

New:
----
  cpplint-1.4.5.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-cpplint.spec ++++++
--- /var/tmp/diff_new_pack.9qd62u/_old  2020-04-01 19:20:58.271602191 +0200
+++ /var/tmp/diff_new_pack.9qd62u/_new  2020-04-01 19:20:58.275602192 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package python-cpplint
 #
-# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2020 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -18,13 +18,14 @@
 
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 Name:           python-cpplint
-Version:        1.4.4
+Version:        1.4.5
 Release:        0
 Summary:        An automated checker to make sure a C++ file follows Google's 
C++ style guide
 License:        BSD-3-Clause
 Group:          Development/Languages/Python
 URL:            https://github.com/cpplint/cpplint
 Source:         
https://files.pythonhosted.org/packages/source/c/cpplint/cpplint-%{version}.tar.gz
+BuildRequires:  %{python_module pytest}
 BuildRequires:  %{python_module setuptools}
 BuildRequires:  fdupes
 BuildRequires:  python-rpm-macros
@@ -41,6 +42,9 @@
 %prep
 %setup -q -n cpplint-%{version}
 sed -i -e '/^#!\//, 1d' cpplint.py
+sed -i 's/pytest-runner//' setup.py
+sed -i 's/pytest-cov//' test-requirements
+sed -i 's/--cov-fail-under=75 --cov=cpplint//' setup.cfg
 
 %build
 %python_build
@@ -50,7 +54,7 @@
 %python_expand %fdupes %{buildroot}%{$python_sitelib}
 
 %check
-%python_exec setup.py test
+%pytest
 
 %files %{python_files}
 %license LICENSE

++++++ cpplint-1.4.4.tar.gz -> cpplint-1.4.5.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cpplint-1.4.4/MANIFEST.in 
new/cpplint-1.4.5/MANIFEST.in
--- old/cpplint-1.4.4/MANIFEST.in       2019-02-24 08:42:20.000000000 +0100
+++ new/cpplint-1.4.5/MANIFEST.in       2019-12-14 13:50:36.000000000 +0100
@@ -1,6 +1,17 @@
 # MANIFEST.in file required to deliver test files with source tar
 include *.py
 include LICENSE
+include test-requirements
+include dev-requirements
 
 # all samples for clitest
 graft samples
+
+global-exclude .tox
+global-exclude *~
+global-exclude __pycache__
+global-exclude .coverage
+global-exclude *.py[co]
+global-exclude *.db
+global-exclude .git*
+global-exclude *.orig
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cpplint-1.4.4/PKG-INFO new/cpplint-1.4.5/PKG-INFO
--- old/cpplint-1.4.4/PKG-INFO  2019-02-25 13:32:15.000000000 +0100
+++ new/cpplint-1.4.5/PKG-INFO  2020-01-13 08:42:33.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: cpplint
-Version: 1.4.4
+Version: 1.4.5
 Summary: Automated checker to ensure C++ files follow Google's style guide
 Home-page: https://github.com/cpplint/cpplint
 Maintainer: cpplint Developers
@@ -35,7 +35,7 @@
             :target: https://pypi.python.org/pypi/cpplint
         
         Cpplint is a command-line tool to check C/C++ files for style issues 
following `Google's C++ style guide 
<http://google.github.io/styleguide/cppguide.html>`_.
-        Cpplint is developed and maintained by Google Inc. at 
`google/styleguide <https://github.com/google/styleguide>`_, also see see the 
`wikipedia entry <http://en.wikipedia.org/wiki/Cpplint>`_
+        Cpplint is developed and maintained by Google Inc. at 
`google/styleguide <https://github.com/google/styleguide>`_, also see the 
`wikipedia entry <http://en.wikipedia.org/wiki/Cpplint>`_
         
         While Google maintains cpplint, Google is not (very) responsive to 
issues and pull requests, this fork aims to be (somewhat) more open to add 
fixes to cpplint to enable fixes, when those fixes make cpplint usable in wider 
contexts.
         
@@ -103,4 +103,5 @@
 Classifier: Environment :: Console
 Classifier: Topic :: Software Development :: Quality Assurance
 Classifier: License :: Freely Distributable
+Provides-Extra: test
 Provides-Extra: dev
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cpplint-1.4.4/README.rst new/cpplint-1.4.5/README.rst
--- old/cpplint-1.4.4/README.rst        2019-02-24 08:42:20.000000000 +0100
+++ new/cpplint-1.4.5/README.rst        2019-12-14 13:51:06.000000000 +0100
@@ -26,7 +26,7 @@
     :target: https://pypi.python.org/pypi/cpplint
 
 Cpplint is a command-line tool to check C/C++ files for style issues following 
`Google's C++ style guide <http://google.github.io/styleguide/cppguide.html>`_.
-Cpplint is developed and maintained by Google Inc. at `google/styleguide 
<https://github.com/google/styleguide>`_, also see see the `wikipedia entry 
<http://en.wikipedia.org/wiki/Cpplint>`_
+Cpplint is developed and maintained by Google Inc. at `google/styleguide 
<https://github.com/google/styleguide>`_, also see the `wikipedia entry 
<http://en.wikipedia.org/wiki/Cpplint>`_
 
 While Google maintains cpplint, Google is not (very) responsive to issues and 
pull requests, this fork aims to be (somewhat) more open to add fixes to 
cpplint to enable fixes, when those fixes make cpplint usable in wider contexts.
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cpplint-1.4.4/cpplint.egg-info/PKG-INFO 
new/cpplint-1.4.5/cpplint.egg-info/PKG-INFO
--- old/cpplint-1.4.4/cpplint.egg-info/PKG-INFO 2019-02-25 13:32:15.000000000 
+0100
+++ new/cpplint-1.4.5/cpplint.egg-info/PKG-INFO 2020-01-13 08:42:33.000000000 
+0100
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: cpplint
-Version: 1.4.4
+Version: 1.4.5
 Summary: Automated checker to ensure C++ files follow Google's style guide
 Home-page: https://github.com/cpplint/cpplint
 Maintainer: cpplint Developers
@@ -35,7 +35,7 @@
             :target: https://pypi.python.org/pypi/cpplint
         
         Cpplint is a command-line tool to check C/C++ files for style issues 
following `Google's C++ style guide 
<http://google.github.io/styleguide/cppguide.html>`_.
-        Cpplint is developed and maintained by Google Inc. at 
`google/styleguide <https://github.com/google/styleguide>`_, also see see the 
`wikipedia entry <http://en.wikipedia.org/wiki/Cpplint>`_
+        Cpplint is developed and maintained by Google Inc. at 
`google/styleguide <https://github.com/google/styleguide>`_, also see the 
`wikipedia entry <http://en.wikipedia.org/wiki/Cpplint>`_
         
         While Google maintains cpplint, Google is not (very) responsive to 
issues and pull requests, this fork aims to be (somewhat) more open to add 
fixes to cpplint to enable fixes, when those fixes make cpplint usable in wider 
contexts.
         
@@ -103,4 +103,5 @@
 Classifier: Environment :: Console
 Classifier: Topic :: Software Development :: Quality Assurance
 Classifier: License :: Freely Distributable
+Provides-Extra: test
 Provides-Extra: dev
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cpplint-1.4.4/cpplint.egg-info/SOURCES.txt 
new/cpplint-1.4.5/cpplint.egg-info/SOURCES.txt
--- old/cpplint-1.4.4/cpplint.egg-info/SOURCES.txt      2019-02-25 
13:32:15.000000000 +0100
+++ new/cpplint-1.4.5/cpplint.egg-info/SOURCES.txt      2020-01-13 
08:42:33.000000000 +0100
@@ -4,14 +4,17 @@
 cpplint.py
 cpplint_clitest.py
 cpplint_unittest.py
+dev-requirements
 setup.cfg
 setup.py
+test-requirements
 cpplint.egg-info/PKG-INFO
 cpplint.egg-info/SOURCES.txt
 cpplint.egg-info/dependency_links.txt
 cpplint.egg-info/entry_points.txt
 cpplint.egg-info/requires.txt
 cpplint.egg-info/top_level.txt
+samples/boost-sample/exclude.def
 samples/boost-sample/headers_simple.def
 samples/boost-sample/simple.def
 samples/boost-sample/include/boost/math/octonion.hpp
@@ -31,6 +34,8 @@
 samples/silly-sample/filters.def
 samples/silly-sample/simple.def
 samples/silly-sample/src/sillycode.cpp
+samples/simple-sample/main.cpp
+samples/simple-sample/main.h
 samples/vlc-sample/simple.def
 samples/vlc-sample/src/libvlc.c
 samples/vlc-sample/src/libvlc.h
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cpplint-1.4.4/cpplint.egg-info/requires.txt 
new/cpplint-1.4.5/cpplint.egg-info/requires.txt
--- old/cpplint-1.4.4/cpplint.egg-info/requires.txt     2019-02-25 
13:32:15.000000000 +0100
+++ new/cpplint-1.4.5/cpplint.egg-info/requires.txt     2020-01-13 
08:42:33.000000000 +0100
@@ -1,5 +1,12 @@
 
 [dev]
-pylint
-flake8
-yapf
+flake8>=3.7.8
+pylint>=1.8.4
+tox>=3.0.0
+tox-pyenv
+pytest<5.0,>=4.6
+pytest-cov
+
+[test]
+pytest<5.0,>=4.6
+pytest-cov
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cpplint-1.4.4/cpplint.py new/cpplint-1.4.5/cpplint.py
--- old/cpplint-1.4.4/cpplint.py        2019-02-25 01:49:29.000000000 +0100
+++ new/cpplint-1.4.5/cpplint.py        2020-01-13 08:38:09.000000000 +0100
@@ -59,7 +59,7 @@
 # if empty, use defaults
 _valid_extensions = set([])
 
-__VERSION__ = '1.4.4'
+__VERSION__ = '1.4.5'
 
 try:
   xrange          # Python 2
@@ -678,7 +678,7 @@
 
 # Treat all headers starting with 'h' equally: .h, .hpp, .hxx etc.
 # This is set by --headers flag.
-_hpp_headers = set(['h', 'hh', 'hpp', 'hxx', 'h++', 'cuh'])
+_hpp_headers = set([])
 
 # {str, bool}: a map from error categories to booleans which indicate if the
 # category should be suppressed for every line.
@@ -687,30 +687,39 @@
 def ProcessHppHeadersOption(val):
   global _hpp_headers
   try:
-    _hpp_headers = set(val.split(','))
-    # Automatically append to extensions list so it does not have to be set 2 
times
-    _valid_extensions.update(_hpp_headers)
+    _hpp_headers = {ext.strip() for ext in val.split(',')}
   except ValueError:
     PrintUsage('Header extensions must be comma separated list.')
 
 def IsHeaderExtension(file_extension):
-  return file_extension in _hpp_headers
+  return file_extension in GetHeaderExtensions()
 
 def GetHeaderExtensions():
-  return _hpp_headers or ['h']
+  if _hpp_headers:
+    return _hpp_headers
+  if _valid_extensions:
+    return {h for h in _valid_extensions if 'h' in h}
+  return set(['h', 'hh', 'hpp', 'hxx', 'h++', 'cuh'])
 
 # The allowed extensions for file names
 # This is set by --extensions flag
 def GetAllExtensions():
-  if not _valid_extensions:
-    return GetHeaderExtensions().union(set(['c', 'cc', 'cpp', 'cxx', 'c++', 
'cu']))
-  return _valid_extensions
+  return GetHeaderExtensions().union(_valid_extensions or set(
+    ['c', 'cc', 'cpp', 'cxx', 'c++', 'cu']))
+
+def ProcessExtensionsOption(val):
+  global _valid_extensions
+  try:
+    extensions = [ext.strip() for ext in val.split(',')]
+    _valid_extensions = set(extensions)
+  except ValueError:
+    PrintUsage('Extensions should be a comma-separated list of values;'
+               'for example: extensions=hpp,cpp\n'
+               'This could not be parsed: "%s"' % (val,))
 
 def GetNonHeaderExtensions():
   return GetAllExtensions().difference(GetHeaderExtensions())
 
-
-
 def ParseNolintSuppressions(filename, raw_line, linenum, error):
   """Updates the global list of line error-suppressions.
 
@@ -1117,9 +1126,9 @@
     num_failures = len(self._junit_failures)
 
     testsuite = xml.etree.ElementTree.Element('testsuite')
-    testsuite.attrib['name'] = 'cpplint'
     testsuite.attrib['errors'] = str(num_errors)
     testsuite.attrib['failures'] = str(num_failures)
+    testsuite.attrib['name'] = 'cpplint'
 
     if num_errors == 0 and num_failures == 0:
       testsuite.attrib['tests'] = str(1)
@@ -1313,7 +1322,7 @@
     If we have a real absolute path name here we can try to do something smart:
     detecting the root of the checkout and truncating /path/to/checkout from
     the name so that we get header guards that don't include things like
-    "C:\Documents and Settings\..." or "/home/username/..." in them and thus
+    "C:\\Documents and Settings\\..." or "/home/username/..." in them and thus
     people on different computers who have checked the source out to different
     locations won't see bogus errors.
     """
@@ -3144,7 +3153,8 @@
         Search(r'\bstd\s*::\s*initializer_list\b', constructor_args[0]))
     copy_constructor = bool(
         onearg_constructor and
-        Match(r'(const\s+)?%s(\s*<[^>]*>)?(\s+const)?\s*(?:<\w+>\s*)?&'
+        Match(r'((const\s+(volatile\s+)?)?|(volatile\s+(const\s+)?))?'
+              r'%s(\s*<[^>]*>)?(\s+const)?\s*(?:<\w+>\s*)?&'
               % re.escape(base_classname), constructor_args[0].strip()))
 
     if (not is_marked_explicit and
@@ -3316,7 +3326,7 @@
       if Search(r'(;|})', start_line):  # Declarations and trivial functions
         body_found = True
         break                              # ... ignore
-      elif Search(r'{', start_line):
+      if Search(r'{', start_line):
         body_found = True
         function = Search(r'((\w|:)*)\(', line).group(1)
         if Match(r'TEST', function):    # Handle TEST... macros
@@ -3510,8 +3520,8 @@
   line = clean_lines.elided[linenum]
 
   # You shouldn't have spaces before your brackets, except maybe after
-  # 'delete []' or 'return []() {};'
-  if Search(r'\w\s+\[', line) and not Search(r'(?:delete|return)\s+\[', line):
+  # 'delete []', 'return []() {};', or 'auto [abc, ...] = ...;'.
+  if Search(r'\w\s+\[', line) and not Search(r'(?:auto&?|delete|return)\s+\[', 
line):
     error(filename, linenum, 'whitespace/braces', 5,
           'Extra space before [')
 
@@ -4815,7 +4825,19 @@
               'Do not include .' + extension + ' files from other packages')
         return
 
-    if not _THIRD_PARTY_HEADERS_PATTERN.match(include):
+    # We DO want to include a 3rd party looking header if it matches the
+    # filename. Otherwise we get an erroneous error "...should include its
+    # header" error later.
+    third_src_header = False
+    for ext in GetHeaderExtensions():
+      basefilename = filename[0:len(filename) - len(fileinfo.Extension())]
+      headerfile = basefilename + '.' + ext
+      headername = FileInfo(headerfile).RepositoryName()
+      if headername in include or include in headername:
+        third_src_header = True
+        break
+
+    if third_src_header or not _THIRD_PARTY_HEADERS_PATTERN.match(include):
       include_state.include_list[-1].append((include, linenum))
 
       # We want to ensure that headers appear in the right order:
@@ -5614,11 +5636,11 @@
                      )),
     ('<limits>', ('numeric_limits',)),
     ('<list>', ('list',)),
-    ('<map>', ('map', 'multimap',)),
+    ('<map>', ('multimap',)),
     ('<memory>', ('allocator', 'make_shared', 'make_unique', 'shared_ptr',
                   'unique_ptr', 'weak_ptr')),
     ('<queue>', ('queue', 'priority_queue',)),
-    ('<set>', ('set', 'multiset',)),
+    ('<set>', ('multiset',)),
     ('<stack>', ('stack',)),
     ('<string>', ('char_traits', 'basic_string',)),
     ('<tuple>', ('tuple',)),
@@ -5652,6 +5674,16 @@
         (re.compile(r'[^>.]\b' + _template + r'(<.*?>)?\([^\)]'),
             _template,
             _header))
+# Match set<type>, but not foo->set<type>, foo.set<type>
+_re_pattern_headers_maybe_templates.append(
+    (re.compile(r'[^>.]\bset\s*\<'),
+        'set<>',
+        '<set>'))
+# Match 'map<type> var' and 'std::map<type>(...)', but not 'map<type>(...)''
+_re_pattern_headers_maybe_templates.append(
+    (re.compile(r'(std\b::\bmap\s*\<)|(^(std\b::\b)map\b\(\s*\<)'),
+        'map<>',
+        '<map>'))
 
 # Other scripts may reach in and modify this pattern.
 _re_pattern_templates = []
@@ -6259,14 +6291,7 @@
             except ValueError:
               _cpplint_state.PrintError('Line length must be numeric.')
           elif name == 'extensions':
-            global _valid_extensions
-            try:
-              extensions = [ext.strip() for ext in val.split(',')]
-              _valid_extensions = set(extensions)
-            except ValueError:
-              sys.stderr.write('Extensions should be a comma-separated list of 
values;'
-                               'for example: extensions=hpp,cpp\n'
-                               'This could not be parsed: "%s"' % (val,))
+            ProcessExtensionsOption(val)
           elif name == 'root':
             global _root
             # root directories are specified relative to CPPLINT.cfg dir.
@@ -6489,11 +6514,7 @@
         _excludes = set()
       _excludes.update(glob.glob(val))
     elif opt == '--extensions':
-      global _valid_extensions
-      try:
-        _valid_extensions = set(val.split(','))
-      except ValueError:
-        PrintUsage('Extensions must be comma seperated list.')
+      ProcessExtensionsOption(val)
     elif opt == '--headers':
       ProcessHppHeadersOption(val)
     elif opt == '--recursive':
@@ -6545,15 +6566,35 @@
   for filename in expanded:
     if os.path.splitext(filename)[1][1:] in GetAllExtensions():
       filtered.append(filename)
-
   return filtered
 
-def _FilterExcludedFiles(filenames):
+def _FilterExcludedFiles(fnames):
   """Filters out files listed in the --exclude command line switch. File paths
   in the switch are evaluated relative to the current working directory
   """
   exclude_paths = [os.path.abspath(f) for f in _excludes]
-  return [f for f in filenames if os.path.abspath(f) not in exclude_paths]
+  # because globbing does not work recursively, exclude all subpath of all 
excluded entries
+  return [f for f in fnames
+          if not any(e for e in exclude_paths
+                  if _IsParentOrSame(e, os.path.abspath(f)))]
+
+def _IsParentOrSame(parent, child):
+  """Return true if child is subdirectory of parent.
+  Assumes both paths are absolute and don't contain symlinks.
+  """
+  parent = os.path.normpath(parent)
+  child = os.path.normpath(child)
+  if parent == child:
+    return True
+
+  prefix = os.path.commonprefix([parent, child])
+  if prefix != parent:
+    return False
+  # Note: os.path.commonprefix operates on character basis, so
+  # take extra care of situations like '/foo/ba' and '/foo/bar/baz'
+  child_suffix = child[len(prefix):]
+  child_suffix = child_suffix.lstrip(os.sep)
+  return child == os.path.join(prefix, child_suffix)
 
 def main():
   filenames = ParseArguments(sys.argv[1:])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cpplint-1.4.4/cpplint_clitest.py 
new/cpplint-1.4.5/cpplint_clitest.py
--- old/cpplint-1.4.4/cpplint_clitest.py        2019-02-24 08:57:12.000000000 
+0100
+++ new/cpplint-1.4.5/cpplint_clitest.py        2020-01-13 08:26:47.000000000 
+0100
@@ -160,7 +160,7 @@
         self.checkAllInFolder('./samples/silly-sample', 2)
 
     def testBoostSample(self):
-        self.checkAllInFolder('./samples/boost-sample', 2)
+        self.checkAllInFolder('./samples/boost-sample', 3)
 
     def testProtobufSample(self):
         self.checkAllInFolder('./samples/protobuf-sample', 1)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cpplint-1.4.4/cpplint_unittest.py 
new/cpplint-1.4.5/cpplint_unittest.py
--- old/cpplint-1.4.4/cpplint_unittest.py       2019-02-24 08:57:12.000000000 
+0100
+++ new/cpplint-1.4.5/cpplint_unittest.py       2020-01-13 08:26:47.000000000 
+0100
@@ -42,7 +42,7 @@
 import sys
 import tempfile
 import unittest
-
+import pytest
 
 import cpplint
 
@@ -1119,6 +1119,35 @@
         """,
         'Add #include <utility> for swap'
         '  [build/include_what_you_use] [4]')
+    # False positive for std::set
+    self.TestIncludeWhatYouUse(
+        """
+        #include <string>
+        struct Foo {
+            template <typename T>
+            void set(const std::string& name, const T& value);
+        };
+        Foo bar;
+        Foo* pbar = &bar;
+        bar.set<int>("int", 5);
+        pbar->set<bool>("bool", false);""",
+        '')
+    # False positive for std::map
+    self.TestIncludeWhatYouUse(
+        """
+        template <typename T>
+        struct Foo {
+            T t;
+        };
+        template <typename T>
+        Foo<T> map(T t) {
+            return Foo<T>{ t };
+        }
+        struct Bar {
+        };
+        auto res = map<Bar>();
+        """,
+        '')
 
     # Test the UpdateIncludeState code path.
     mock_header_contents = ['#include "blah/foo.h"', '#include "blah/bar.h"']
@@ -1643,6 +1672,24 @@
       self.TestMultiLineLint(
           """
           class Foo {
+            Foo(volatile Foo&);
+          };""",
+          '')
+      self.TestMultiLineLint(
+          """
+          class Foo {
+            Foo(volatile const Foo&);
+          };""",
+          '')
+      self.TestMultiLineLint(
+          """
+          class Foo {
+            Foo(const volatile Foo&);
+          };""",
+          '')
+      self.TestMultiLineLint(
+          """
+          class Foo {
             Foo(Foo const&);
           };""",
           '')
@@ -4017,19 +4064,32 @@
       self.assertEquals(['foo.cc', 'foo.h'],
                         cpplint.ParseArguments(['foo.cc', 'foo.h']))
 
+      cpplint._hpp_headers = old_headers
+      cpplint._valid_extensions = old_valid_extensions
       self.assertEqual(['foo.h'],
                        cpplint.ParseArguments(['--linelength=120', 'foo.h']))
       self.assertEqual(120, cpplint._line_length)
+      self.assertEqual(set(['h', 'hh', 'hpp', 'hxx', 'h++', 'cuh']), 
cpplint.GetHeaderExtensions())  # Default value
 
+      cpplint._hpp_headers = old_headers
+      cpplint._valid_extensions = old_valid_extensions
+      self.assertEqual(['foo.h'],
+                       cpplint.ParseArguments(['--headers=h', 'foo.h']))
+      self.assertEqual(set(['h', 'c', 'cc', 'cpp', 'cxx', 'c++', 'cu']), 
cpplint.GetAllExtensions())
+
+      cpplint._hpp_headers = old_headers
+      cpplint._valid_extensions = old_valid_extensions
       self.assertEqual(['foo.h'],
                        cpplint.ParseArguments(['--extensions=hpp,cpp,cpp', 
'foo.h']))
-      self.assertEqual(set(['hpp', 'cpp']), cpplint._valid_extensions)
+      self.assertEqual(set(['hpp', 'cpp']), cpplint.GetAllExtensions())
+      self.assertEqual(set(['hpp']), cpplint.GetHeaderExtensions())
 
-      self.assertEqual(set(['h', 'hh', 'hpp', 'hxx', 'h++', 'cuh']), 
cpplint._hpp_headers)  # Default value
+      cpplint._hpp_headers = old_headers
+      cpplint._valid_extensions = old_valid_extensions
       self.assertEqual(['foo.h'],
                        cpplint.ParseArguments(['--extensions=cpp,cpp', 
'--headers=hpp,h', 'foo.h']))
-      self.assertEqual(set(['hpp', 'h']), cpplint._hpp_headers)
-      self.assertEqual(set(['hpp', 'h', 'cpp']), cpplint._valid_extensions)
+      self.assertEqual(set(['hpp', 'h']), cpplint.GetHeaderExtensions())
+      self.assertEqual(set(['hpp', 'h', 'cpp']), cpplint.GetAllExtensions())
 
     finally:
       sys.stdout == sys.__stdout__
@@ -4054,6 +4114,7 @@
       os.chdir(temp_dir)
       expected = ['one.cpp', os.path.join('src', 'two.cpp'),
                   os.path.join('src', 'nested', 'three.cpp')]
+      cpplint._excludes = None
       actual = cpplint.ParseArguments(['--recursive', 'one.cpp', 'src'])
       self.assertEquals(set(expected), set(actual))
     finally:
@@ -4071,36 +4132,66 @@
       open(os.path.join(src_dir, "three.cc"), 'w').close()
       os.chdir(temp_dir)
       expected = ['one.cpp', os.path.join('src', 'two.cpp')]
+      cpplint._excludes = None
       actual = cpplint.ParseArguments(['--recursive', '--extensions=cpp',
           'one.cpp', 'src'])
       self.assertEquals(set(expected), set(actual))
     finally:
         os.chdir(working_dir)
         shutil.rmtree(temp_dir)
-        cpplint._header_extensions = set([])
+        cpplint._hpp_headers = set([])
         cpplint._valid_extensions = set([])
 
-  def testExclude(self):
+  def testRecursiveExclude(self):
     working_dir = os.getcwd()
     temp_dir = tempfile.mkdtemp()
     try:
       src_dir = os.path.join(temp_dir, 'src')
+      src2_dir = os.path.join(temp_dir, 'src2')
       os.makedirs(src_dir)
+      os.makedirs(src2_dir)
       open(os.path.join(src_dir, 'one.cc'), 'w').close()
       open(os.path.join(src_dir, 'two.cc'), 'w').close()
       open(os.path.join(src_dir, 'three.cc'), 'w').close()
+      open(os.path.join(src2_dir, 'one.cc'), 'w').close()
+      open(os.path.join(src2_dir, 'two.cc'), 'w').close()
+      open(os.path.join(src2_dir, 'three.cc'), 'w').close()
       os.chdir(temp_dir)
 
+      expected = [
+        os.path.join('src', 'one.cc'),
+        os.path.join('src', 'two.cc'),
+        os.path.join('src', 'three.cc')
+      ]
+      cpplint._excludes = None
+      actual = cpplint.ParseArguments(['src'])
+      self.assertEquals(set(['src']), set(actual))
+
+      cpplint._excludes = None
+      actual = cpplint.ParseArguments(['--recursive', 'src'])
+      self.assertEquals(set(expected), set(actual))
+
       expected = [os.path.join('src', 'one.cc')]
+      cpplint._excludes = None
       actual = cpplint.ParseArguments(['--recursive',
           '--exclude=src{0}t*'.format(os.sep), 'src'])
       self.assertEquals(set(expected), set(actual))
 
       expected = [os.path.join('src', 'one.cc')]
+      cpplint._excludes = None
       actual = cpplint.ParseArguments(['--recursive',
           '--exclude=src/two.cc', '--exclude=src/three.cc', 'src'])
       self.assertEquals(set(expected), set(actual))
 
+      expected = set([
+        os.path.join('src2', 'one.cc'),
+        os.path.join('src2', 'two.cc'),
+        os.path.join('src2', 'three.cc')
+      ])
+      cpplint._excludes = None
+      actual = cpplint.ParseArguments(['--recursive',
+          '--exclude=src', '.'])
+      self.assertEquals(expected, set(actual))
     finally:
         os.chdir(working_dir)
         shutil.rmtree(temp_dir)
@@ -4671,6 +4762,74 @@
     # Restore previous CWD.
     os.chdir(cur_dir)
 
+  def testIncludeItsHeader(self):
+    temp_directory = tempfile.mkdtemp()
+    cur_dir = os.getcwd()
+    try:
+      test_directory = os.path.join(temp_directory, "test")
+      os.makedirs(test_directory)
+      file_path = os.path.join(test_directory, 'foo.h')
+      open(file_path, 'a').close()
+      file_path = os.path.join(test_directory, 'Bar.h')
+      open(file_path, 'a').close()
+
+      os.chdir(temp_directory)
+
+      error_collector = ErrorCollector(self.assertTrue)
+      cpplint.ProcessFileData(
+        'test/foo.cc', 'cc',
+        [''],
+        error_collector)
+      expected = "{dir}/{fn}.cc should include its header file {dir}/{fn}.h  
[build/include] [5]".format(
+          fn="foo",
+          dir=test_directory)
+      self.assertEqual(
+        1,
+        error_collector.Results().count(expected))
+
+      error_collector = ErrorCollector(self.assertTrue)
+      cpplint.ProcessFileData(
+        'test/foo.cc', 'cc',
+        [r'#include "test/foo.h"',
+         ''
+         ],
+        error_collector)
+      self.assertEqual(
+        0,
+        error_collector.Results().count(expected))
+
+      # This should continue to work
+      error_collector = ErrorCollector(self.assertTrue)
+      cpplint.ProcessFileData(
+        'test/Bar.cc', 'cc',
+        [r'#include "test/Bar.h"',
+         ''
+         ],
+        error_collector)
+      expected = "{dir}/{fn}.cc should include its header file {dir}/{fn}.h  
[build/include] [5]".format(
+          fn="Bar",
+          dir=test_directory)
+      self.assertEqual(
+        0,
+        error_collector.Results().count(expected))
+
+      # Since Bar.cc & Bar.h look 3rd party-ish, it should be ok without the 
include dir
+      error_collector = ErrorCollector(self.assertTrue)
+      cpplint.ProcessFileData(
+        'test/Bar.cc', 'cc',
+        [r'#include "Bar.h"',
+         ''
+         ],
+        error_collector)
+      self.assertEqual(
+        0,
+        error_collector.Results().count(expected))
+
+    finally:
+      # Restore previous CWD.
+      os.chdir(cur_dir)
+      shutil.rmtree(temp_directory)
+
   def testPathSplitToList(self):
     self.assertEquals([''],
                       cpplint.PathSplitToList(os.path.join('')))
@@ -5190,7 +5349,7 @@
                                       False))
 
   def testTryDropCommonSuffixes(self):
-    cpplint._header_extensions = set([])
+    cpplint._hpp_headers = set([])
     cpplint._valid_extensions = set([])
     self.assertEqual('foo/foo', cpplint._DropCommonSuffixes('foo/foo-inl.h'))
     self.assertEqual('foo/foo', cpplint._DropCommonSuffixes('foo/foo-inl.hxx'))
@@ -6218,6 +6377,10 @@
     # Output with no errors must be completely blank!
     self.assertEquals("", output)
 
+#class FileFilterTest(unittest.TestCase):
+#  def testFilterExcludedFiles(self):
+#    self.assertEquals([], _FilterExcludedFiles([]))
+
 # pylint: disable=C6409
 def setUp():
   """Runs before all tests are executed.
@@ -6243,6 +6406,13 @@
     pass
 
 
+@pytest.fixture(autouse=True)
+def run_around_tests():
+  setUp()
+  yield
+  tearDown()
+
+
 if __name__ == '__main__':
   # We don't want to run the VerifyAllCategoriesAreSeen() test unless
   # we're running the full test suite: if we only run one test,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cpplint-1.4.4/dev-requirements 
new/cpplint-1.4.5/dev-requirements
--- old/cpplint-1.4.4/dev-requirements  1970-01-01 01:00:00.000000000 +0100
+++ new/cpplint-1.4.5/dev-requirements  2019-12-14 13:50:36.000000000 +0100
@@ -0,0 +1,12 @@
+# requirements to run development steps
+
+# also change in tox.ini
+flake8>=3.7.8
+pylint>=1.8.4
+tox>=3.0.0
+tox-pyenv
+
+# Below only run with python3, installed in tox.ini
+# mypy
+# coala
+# coala-bears
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cpplint-1.4.4/samples/boost-sample/exclude.def 
new/cpplint-1.4.5/samples/boost-sample/exclude.def
--- old/cpplint-1.4.4/samples/boost-sample/exclude.def  1970-01-01 
01:00:00.000000000 +0100
+++ new/cpplint-1.4.5/samples/boost-sample/exclude.def  2020-01-13 
08:26:47.000000000 +0100
@@ -0,0 +1,73 @@
+--recursive --exclude=headers/* src
+1
+3
+Done processing src/tr1/c_policy.hpp
+Total errors found: 66
+
+src/tr1/c_policy.hpp:0:  No #ifndef header guard found, suggested CPP variable 
is: SAMPLES_BOOST_SAMPLE_SRC_TR1_C_POLICY_HPP_  [build/header_guard] [5]
+src/tr1/c_policy.hpp:9:  Missing space before {  [whitespace/braces] [5]
+src/tr1/c_policy.hpp:13:  Line ends in whitespace.  Consider deleting these 
extra spaces.  [whitespace/end_of_line] [4]
+src/tr1/c_policy.hpp:14:  Line ends in whitespace.  Consider deleting these 
extra spaces.  [whitespace/end_of_line] [4]
+src/tr1/c_policy.hpp:15:  Line ends in whitespace.  Consider deleting these 
extra spaces.  [whitespace/end_of_line] [4]
+src/tr1/c_policy.hpp:16:  Line ends in whitespace.  Consider deleting these 
extra spaces.  [whitespace/end_of_line] [4]
+src/tr1/c_policy.hpp:17:  Line ends in whitespace.  Consider deleting these 
extra spaces.  [whitespace/end_of_line] [4]
+src/tr1/c_policy.hpp:18:  Lines should be <= 80 characters long  
[whitespace/line_length] [2]
+src/tr1/c_policy.hpp:19:  { should almost always be at the end of the previous 
line  [whitespace/braces] [4]
+src/tr1/c_policy.hpp:20:  public: should be indented +1 space inside struct 
policy  [whitespace/indent] [3]
+src/tr1/c_policy.hpp:21:  Weird number of spaces at line-start.  Are you using 
a 2-space indent?  [whitespace/indent] [3]
+src/tr1/c_policy.hpp:22:  Weird number of spaces at line-start.  Are you using 
a 2-space indent?  [whitespace/indent] [3]
+src/tr1/c_policy.hpp:23:  Weird number of spaces at line-start.  Are you using 
a 2-space indent?  [whitespace/indent] [3]
+src/tr1/c_policy.hpp:24:  Weird number of spaces at line-start.  Are you using 
a 2-space indent?  [whitespace/indent] [3]
+src/tr1/c_policy.hpp:25:  Weird number of spaces at line-start.  Are you using 
a 2-space indent?  [whitespace/indent] [3]
+src/tr1/c_policy.hpp:26:  Weird number of spaces at line-start.  Are you using 
a 2-space indent?  [whitespace/indent] [3]
+src/tr1/c_policy.hpp:27:  Weird number of spaces at line-start.  Are you using 
a 2-space indent?  [whitespace/indent] [3]
+src/tr1/c_policy.hpp:28:  Weird number of spaces at line-start.  Are you using 
a 2-space indent?  [whitespace/indent] [3]
+src/tr1/c_policy.hpp:30:  Weird number of spaces at line-start.  Are you using 
a 2-space indent?  [whitespace/indent] [3]
+src/tr1/c_policy.hpp:32:  Weird number of spaces at line-start.  Are you using 
a 2-space indent?  [whitespace/indent] [3]
+src/tr1/c_policy.hpp:34:  Weird number of spaces at line-start.  Are you using 
a 2-space indent?  [whitespace/indent] [3]
+src/tr1/c_policy.hpp:35:  Weird number of spaces at line-start.  Are you using 
a 2-space indent?  [whitespace/indent] [3]
+src/tr1/c_policy.hpp:36:  Weird number of spaces at line-start.  Are you using 
a 2-space indent?  [whitespace/indent] [3]
+src/tr1/c_policy.hpp:37:  Weird number of spaces at line-start.  Are you using 
a 2-space indent?  [whitespace/indent] [3]
+src/tr1/c_policy.hpp:38:  Weird number of spaces at line-start.  Are you using 
a 2-space indent?  [whitespace/indent] [3]
+src/tr1/c_policy.hpp:39:  Weird number of spaces at line-start.  Are you using 
a 2-space indent?  [whitespace/indent] [3]
+src/tr1/c_policy.hpp:44:  Line ends in whitespace.  Consider deleting these 
extra spaces.  [whitespace/end_of_line] [4]
+src/tr1/c_policy.hpp:45:  Line ends in whitespace.  Consider deleting these 
extra spaces.  [whitespace/end_of_line] [4]
+src/tr1/c_policy.hpp:46:  Line ends in whitespace.  Consider deleting these 
extra spaces.  [whitespace/end_of_line] [4]
+src/tr1/c_policy.hpp:47:  Line ends in whitespace.  Consider deleting these 
extra spaces.  [whitespace/end_of_line] [4]
+src/tr1/c_policy.hpp:48:  Line ends in whitespace.  Consider deleting these 
extra spaces.  [whitespace/end_of_line] [4]
+src/tr1/c_policy.hpp:49:  Line ends in whitespace.  Consider deleting these 
extra spaces.  [whitespace/end_of_line] [4]
+src/tr1/c_policy.hpp:50:  Line ends in whitespace.  Consider deleting these 
extra spaces.  [whitespace/end_of_line] [4]
+src/tr1/c_policy.hpp:51:  Lines should be <= 80 characters long  
[whitespace/line_length] [2]
+src/tr1/c_policy.hpp:52:  { should almost always be at the end of the previous 
line  [whitespace/braces] [4]
+src/tr1/c_policy.hpp:53:  public: should be indented +1 space inside struct 
policy  [whitespace/indent] [3]
+src/tr1/c_policy.hpp:54:  Weird number of spaces at line-start.  Are you using 
a 2-space indent?  [whitespace/indent] [3]
+src/tr1/c_policy.hpp:55:  Weird number of spaces at line-start.  Are you using 
a 2-space indent?  [whitespace/indent] [3]
+src/tr1/c_policy.hpp:56:  Weird number of spaces at line-start.  Are you using 
a 2-space indent?  [whitespace/indent] [3]
+src/tr1/c_policy.hpp:57:  Weird number of spaces at line-start.  Are you using 
a 2-space indent?  [whitespace/indent] [3]
+src/tr1/c_policy.hpp:58:  Weird number of spaces at line-start.  Are you using 
a 2-space indent?  [whitespace/indent] [3]
+src/tr1/c_policy.hpp:59:  Weird number of spaces at line-start.  Are you using 
a 2-space indent?  [whitespace/indent] [3]
+src/tr1/c_policy.hpp:60:  Weird number of spaces at line-start.  Are you using 
a 2-space indent?  [whitespace/indent] [3]
+src/tr1/c_policy.hpp:61:  Weird number of spaces at line-start.  Are you using 
a 2-space indent?  [whitespace/indent] [3]
+src/tr1/c_policy.hpp:63:  Weird number of spaces at line-start.  Are you using 
a 2-space indent?  [whitespace/indent] [3]
+src/tr1/c_policy.hpp:65:  Weird number of spaces at line-start.  Are you using 
a 2-space indent?  [whitespace/indent] [3]
+src/tr1/c_policy.hpp:67:  Weird number of spaces at line-start.  Are you using 
a 2-space indent?  [whitespace/indent] [3]
+src/tr1/c_policy.hpp:68:  Weird number of spaces at line-start.  Are you using 
a 2-space indent?  [whitespace/indent] [3]
+src/tr1/c_policy.hpp:69:  Weird number of spaces at line-start.  Are you using 
a 2-space indent?  [whitespace/indent] [3]
+src/tr1/c_policy.hpp:70:  Weird number of spaces at line-start.  Are you using 
a 2-space indent?  [whitespace/indent] [3]
+src/tr1/c_policy.hpp:71:  Weird number of spaces at line-start.  Are you using 
a 2-space indent?  [whitespace/indent] [3]
+src/tr1/c_policy.hpp:72:  Weird number of spaces at line-start.  Are you using 
a 2-space indent?  [whitespace/indent] [3]
+src/tr1/c_policy.hpp:76:  Lines should be <= 80 characters long  
[whitespace/line_length] [2]
+src/tr1/c_policy.hpp:88:  { should almost always be at the end of the previous 
line  [whitespace/braces] [4]
+src/tr1/c_policy.hpp:89:  Weird number of spaces at line-start.  Are you using 
a 2-space indent?  [whitespace/indent] [3]
+src/tr1/c_policy.hpp:89:  Lines should be <= 80 characters long  
[whitespace/line_length] [2]
+src/tr1/c_policy.hpp:93:  Lines should be <= 80 characters long  
[whitespace/line_length] [2]
+src/tr1/c_policy.hpp:105:  { should almost always be at the end of the 
previous line  [whitespace/braces] [4]
+src/tr1/c_policy.hpp:106:  Weird number of spaces at line-start.  Are you 
using a 2-space indent?  [whitespace/indent] [3]
+src/tr1/c_policy.hpp:106:  Lines should be <= 80 characters long  
[whitespace/line_length] [2]
+src/tr1/c_policy.hpp:109:  Namespace should be terminated with "// namespace 
policies"  [readability/namespace] [5]
+src/tr1/c_policy.hpp:109:  Namespace should be terminated with "// namespace 
math"  [readability/namespace] [5]
+src/tr1/c_policy.hpp:109:  Namespace should be terminated with "// namespace 
boost"  [readability/namespace] [5]
+src/tr1/c_policy.hpp:109:  At least two spaces is best between code and 
comments  [whitespace/comments] [2]
+src/tr1/c_policy.hpp:111:  Missing space before {  [whitespace/braces] [5]
+src/tr1/c_policy.hpp:131:  Namespace should be terminated with "// namespace 
c_policies"  [readability/namespace] [5]
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cpplint-1.4.4/samples/simple-sample/main.cpp 
new/cpplint-1.4.5/samples/simple-sample/main.cpp
--- old/cpplint-1.4.4/samples/simple-sample/main.cpp    1970-01-01 
01:00:00.000000000 +0100
+++ new/cpplint-1.4.5/samples/simple-sample/main.cpp    2019-12-14 
08:47:24.000000000 +0100
@@ -0,0 +1,7 @@
+// Copyright 2020 foo
+#include <main.h>
+int main(int argc, char** argv) {
+    char* h = "Hello";
+    printf(h);
+    return 0;
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cpplint-1.4.4/samples/simple-sample/main.h 
new/cpplint-1.4.5/samples/simple-sample/main.h
--- old/cpplint-1.4.4/samples/simple-sample/main.h      1970-01-01 
01:00:00.000000000 +0100
+++ new/cpplint-1.4.5/samples/simple-sample/main.h      2019-12-14 
08:48:17.000000000 +0100
@@ -0,0 +1,2 @@
+// Copyright 2020 foo
+#include <some_module/feature.h>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cpplint-1.4.4/setup.cfg new/cpplint-1.4.5/setup.cfg
--- old/cpplint-1.4.4/setup.cfg 2019-02-25 13:32:15.000000000 +0100
+++ new/cpplint-1.4.5/setup.cfg 2020-01-13 08:42:33.000000000 +0100
@@ -1,7 +1,15 @@
 [aliases]
+test = pytest
 style = flake8
 ci = lint style test
 
+[tool:pytest]
+python_files = *test.py
+testpaths = .
+addopts = --cov-fail-under=75 --cov=cpplint
+filterwarnings = 
+       ignore:.*:DeprecationWarning
+
 [egg_info]
 tag_build = 
 tag_date = 0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cpplint-1.4.4/setup.py new/cpplint-1.4.5/setup.py
--- old/cpplint-1.4.4/setup.py  2019-02-24 08:57:12.000000000 +0100
+++ new/cpplint-1.4.5/setup.py  2019-12-14 13:50:36.000000000 +0100
@@ -1,19 +1,15 @@
 #! /usr/bin/env python
 
 from setuptools import setup, Command
-from setuptools.command.test import test as TestCommand
 from subprocess import check_call
-from multiprocessing import cpu_count
 from distutils.spawn import find_executable
 import cpplint as cpplint
 
-class Test(TestCommand):
-    def run_tests(self):
-        check_call(('./cpplint_unittest.py'))
-        check_call(('./cpplint_clitest.py'))
-
-
 class Cmd(Command):
+    '''
+    Superclass for other commands to run via setup.py, declared in setup.cfg.
+    These commands will auto-install setup_requires in a temporary folder.
+    '''
     user_options = [
       ('executable', 'e', 'The executable to use for the command')
     ]
@@ -29,30 +25,19 @@
 
 
 class Lint(Cmd):
+    '''run with python setup.py lint'''
     description = 'Run linting of the code'
     user_options = Cmd.user_options + [
       ('jobs', 'j', 'Use multiple processes to speed up the linting')
     ]
     executable = 'pylint'
 
-    def initialize_options(self):
-        self.jobs = cpu_count()
-
-    def finalize_options(self):
-        self.jobs = int(self.jobs)
-        if self.jobs < 1:
-            raise ValueError('Jobs must be one or larger')
-
     def run(self):
-        self.execute('-j', str(self.jobs), 'cpplint.py')
+        self.execute('cpplint.py')
 
 
-class Format(Cmd):
-    description = 'Formats the code'
-    executable = 'yapf'
-
-    def run(self):
-        self.execute('--parallel', '--in-place', 'cpplint.py')
+with open('test-requirements') as f:
+    test_required = f.read().splitlines()
 
 
 setup(name='cpplint',
@@ -60,9 +45,9 @@
       py_modules=['cpplint'],
       # generate platform specific start script
       entry_points={
-        'console_scripts': [
-            'cpplint = cpplint:main'
-        ]
+          'console_scripts': [
+              'cpplint = cpplint:main'
+          ]
       },
       install_requires=[],
       url='https://github.com/cpplint/cpplint',
@@ -86,15 +71,15 @@
       description='Automated checker to ensure C++ files follow Google\'s 
style guide',
       long_description=open('README.rst').read(),
       license='BSD-3-Clause',
+      setup_requires=[
+          "pytest-runner"
+      ],
+      tests_require=test_required,
+      # extras_require allow pip install .[dev]
       extras_require={
-        'dev': [
-            'pylint',
-            'flake8',
-            'yapf',
-        ]
+          'test': test_required,
+          'dev': open('dev-requirements').read().splitlines() + test_required
       },
       cmdclass={
-        'test': Test,
-        'lint': Lint,
-        'format': Format
+          'lint': Lint
       })
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/cpplint-1.4.4/test-requirements 
new/cpplint-1.4.5/test-requirements
--- old/cpplint-1.4.4/test-requirements 1970-01-01 01:00:00.000000000 +0100
+++ new/cpplint-1.4.5/test-requirements 2019-12-14 13:50:36.000000000 +0100
@@ -0,0 +1,4 @@
+# minimal requirements to run python setup.py test
+# 5.x requires python 3.5
+pytest>=4.6,<5.0
+pytest-cov


Reply via email to