flake8-class-newline-1.6.0/0000775000175000017500000000000013177122424015361 5ustar jriverojriveroflake8-class-newline-1.6.0/setup.py0000664000175000017500000000345713177122424017104 0ustar jriverojriveroimport io import os from setuptools import setup __dir__ = os.path.dirname(__file__) def read(*filenames, **kwargs): encoding = kwargs.get('encoding', 'utf-8') sep = kwargs.get('sep', '\n') buf = [] for filename in filenames: with io.open(filename, encoding=encoding) as f: buf.append(f.read()) return sep.join(buf) LONG_DESCRIPTION = read(os.path.join(__dir__, 'README.rst')) version = {} with open( os.path.join(__dir__, 'flake8_class_newline', '__version__.py') ) as file: exec(file.read(), version) setup( name='flake8-class-newline', author='Alexander van Eck', author_email='alex@x-all.nl', url='https://github.com/AlexanderVanEck/flake8-class-newline', version=version['__version__'], install_requires=[ 'flake8', ], long_description=LONG_DESCRIPTION, description='Flake8 lint for newline after class definitions.', packages=['flake8_class_newline'], test_suite='tests', include_package_data=True, entry_points={ 'flake8.extension': [ 'CNL100 = flake8_class_newline:new_line_checker' ], }, license='MIT', zip_safe=True, keywords='flake8 lint class new line', classifiers=[ 'Development Status :: 3 - Alpha', 'Environment :: Console', 'Intended Audience :: Developers', 'Operating System :: OS Independent', 'License :: OSI Approved :: MIT License', 'Programming Language :: Python', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.4', 'Topic :: Software Development :: Libraries :: Python Modules', 'Topic :: Software Development :: Quality Assurance', ] ) flake8-class-newline-1.6.0/tests/0000775000175000017500000000000013177122424016523 5ustar jriverojriveroflake8-class-newline-1.6.0/tests/__init__.py0000664000175000017500000000000013177122424020622 0ustar jriverojriveroflake8-class-newline-1.6.0/tests/test_checks.py0000664000175000017500000000620213177122424021374 0ustar jriverojriverofrom flake8_class_newline import new_line_checker from unittest import TestCase class TestChecks(TestCase): def check_file(self, lines, filename): errors = [] for line_number, line in enumerate(lines): errors.append( list( new_line_checker( logical_line=line, line_number=line_number + 1, filename=filename ) ) ) return errors def test_checks_class_new_lines(self): expected_errors = [ [], [((2, 0), 'CNL100 Class definition does not have a new line.')], [], [], [], [], [], [((8, 0), 'CNL100 Class definition does not have a new line.')], [], [], [], ] an_error_file = [ 'class ClassWithoutANewLineDecorator(object):', ' @property', ' def aaasome_arg(self):', ' return "a_string"', '', '', 'class ClassWithoutANewLineMethod(object):', ' def aaasome_arg(self):', ' return "a_string"', '', '', ] # This should produce no error. no_error_file = [ 'class ClassWithANewLineDecorator(object):', '', ' @property', ' def aaasome_arg(self):', ' return "a_string"', '', '', 'class ClassWithANewLineMethod(object):', '', ' def aaasome_arg(self):', ' return "a_string"', '', '', 'class ClassWithoutANewLineArgument(object):', ' an_arg = "a_value"', '', '', 'class ClassWithoutANewLineArgument(object):', ' definetly_an_argument = "a_value"', '', '', 'class ClassWithMultipleBases(AClassWithNewLine,' ' ClassWithDoubleDocstring,' ' object):', # The same logical line " ''' A docstring '''", ' some_arg = "a_string"', '', '', 'class ClassWithDoubleDocstringShouldBeIgnored(object):', '""" A docstring """', ' some_arg = "a_string"', '', '', 'class ClassWithSingleDocstringShouldBeIgnored(object):', " ''' A docstring '''", ' some_arg = "a_string"', '', '', 'class ClassWithClassMetaobject):', " class Meta:", ' an_arg = "a_value"', '', '', ] an_error_file_errors = self.check_file(an_error_file, 'a_file') no_error_file_errors = self.check_file(no_error_file, 'another_file') self.assertEqual(expected_errors, an_error_file_errors) self.assertEqual( [[] for _ in no_error_file_errors], no_error_file_errors ) flake8-class-newline-1.6.0/README.rst0000664000175000017500000000331513177122424017052 0ustar jriverojriveroFlake8 Extension to lint for a method newline after a Class definition =========================================== .. image:: https://travis-ci.org/AlexvEck/flake8-class-newline.svg?branch=master :target: https://travis-ci.org/AlexvEck/flake8-class-newline :alt: Build Status Usage ----- If you are using flake8, you can install this package through pip. .. code:: shell pip install flake8-class-newline This plugin is then automatically triggered when you run; .. code:: shell flake8 It produces only 1 error type; "CNL100 Class definition does not have a new line." NOTE; Documentation blocks (or docblocks) should be on the newline, they are therefore ignored by this plugin. See https://www.python.org/dev/peps/pep-0008/#documentation-strings Example ----- PEP8 says we should surround every class method with a single blank line. See https://www.python.org/dev/peps/pep-0008/#blank-lines However flake8 is ambiguous about the first method having a blank line above it. Basically; .. code:: python class AClassWithoutANewLine(object): def a_method(self): return 'a_value' class AClassWithoutANewLineProperty(object): @property def a_method(self): return 'a_value' or .. code:: python class AClassWithANewLine(object): def a_method(self): return 'a_value' class AClassWithANewLineProperty(object): @property def a_method(self): return 'a_value' This plugin was made to enforce the latter. NOTE; properties of a class do not need a surrounding blank line, only methods. Special Notice ----- This package was inspired by flake8-quotes created by @zheller. Thanks for the inspiration! flake8-class-newline-1.6.0/release.sh0000664000175000017500000000145013177122424017335 0ustar jriverojrivero#!/usr/bin/env bash # Exit on first error set -e # Parse our CLI arguments version_number="$1" if test "$version_number" = ""; then echo "Expected a version to be provided to \`release.sh\` but none was provided." 1>&2 echo "Usage: $0 [version] # (e.g. $0 1.0.0)" 1>&2 exit 1 fi # Bump the version echo "__version__ = '$version_number'" > flake8_class_newline/__version__.py # Verify our version made it into the file if ! grep "$version_number" flake8_class_newline/__version__.py &> /dev/null; then echo "Expected \`__version__\` to update via \`sed\` but it didn't" 1>&2 exit 1 fi # Commit the change git add flake8_class_newline/__version__.py git commit -a -m "Release $version_number" # Tag the release git tag "$version_number" # Publish the release to GitHub git push git push --tags flake8-class-newline-1.6.0/CHANGELOG.md0000664000175000017500000000147213177122424017176 0ustar jriverojrivero# 1.5.1 - Fixed a case where arguments on the newline that started with def (like 'default') where recognised as a method definition. # 1.5.0 - PEP8 specifies only methods need a surrounding blank line, therefore class arguments are allowed on the newline. # 1.4.0 - Went from physical lines to logical lines, since classes with multiple line base classes do not need to be flagged. # 1.2.1 - Fixed an issue where the line numbers of one file would bleed into the second file, therefore eventually producing errors on every line # 1.2.0 - For simplicity, completely rewrote the line checker into a function - Removed the docstrings configuration option previously added in 1.1.0, will add this again in the future. # 1.1.0 - Added configuration setting to ignore docstrings on a newline # 1.0.0 - Added new line checkerflake8-class-newline-1.6.0/.gitignore0000664000175000017500000000005213177122424017346 0ustar jriverojrivero*.egg *.egg-info *.py[cod] .tox dist buildflake8-class-newline-1.6.0/setup.cfg0000664000175000017500000000024013177122424017176 0ustar jriverojrivero[flake8] max-line-length = 80 # Force jobs to 1 as a workaround to avoid the PicklingError in Flake8 3.x # see https://gitlab.com/pycqa/flake8/issues/164 jobs=1flake8-class-newline-1.6.0/LICENSE0000664000175000017500000000177613177122424016401 0ustar jriverojriveroPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.flake8-class-newline-1.6.0/tox.ini0000664000175000017500000000040613177122424016674 0ustar jriverojrivero[tox] envlist = py27 py35 [testenv] usedevelop = true deps = -rrequirements-dev.txt commands = sh test.sh # Add environment to use the default python3 installation [testenv:py35] deps = flake8==3 basepython = python3 [testenv:py27] basepython = pythonflake8-class-newline-1.6.0/flake8_class_newline/0000775000175000017500000000000013177122424021441 5ustar jriverojriveroflake8-class-newline-1.6.0/flake8_class_newline/__init__.py0000664000175000017500000000235313177122424023555 0ustar jriverojriverofrom flake8_class_newline.__version__ import __version__ new_lines_on = {} DOUBLE_QUOTE = '"' SINGLE_QUOTE = "'" CLASS = 'class' METHOD = 'def ' DECORATOR = '@' def new_line_checker(logical_line, line_number, filename): if filename not in new_lines_on: new_lines_on[filename] = [] if logical_line.startswith(CLASS): new_lines_on[filename].append(line_number + 1) if line_number in new_lines_on[filename]: # if the line is not only whitespace and not empty double_quotes = logical_line.strip().startswith(DOUBLE_QUOTE * 3) quotes = logical_line.strip().startswith(SINGLE_QUOTE * 3) is_method = logical_line.strip().startswith(METHOD) is_decorator = logical_line.strip().startswith(DECORATOR) is_callable = is_method or is_decorator not_only_space = not logical_line.isspace() and logical_line not_is_docstring = not (quotes or double_quotes) if not_only_space and not_is_docstring and is_callable: # this means there's something on the line offset = line_number, 0 yield offset, 'CNL100 Class definition does not have a new line.' new_line_checker.name = 'new_line_checker' new_line_checker.version = __version__ flake8-class-newline-1.6.0/flake8_class_newline/__version__.py0000664000175000017500000000002613177122424024272 0ustar jriverojrivero__version__ = '1.6.0' flake8-class-newline-1.6.0/test.sh0000664000175000017500000000022413177122424016672 0ustar jriverojrivero#!/usr/bin/env bash # Exit on first error and echo commands set -e set -x # Run our linter and tests flake8 *.py tests/*.py python setup.py test $*flake8-class-newline-1.6.0/MANIFEST.in0000664000175000017500000000013113177122424017112 0ustar jriverojriveroinclude LICENSE recursive-include flake8_class_newline *.py recursive-include tests *.pyflake8-class-newline-1.6.0/requirements-dev.txt0000664000175000017500000000004613177122424021421 0ustar jriverojriveroflake8<3.4.0,>=3.3.0 tox<2.4.0,>=2.3.1