Merge branch 'origin/proposed/3.0' into master

This commit is contained in:
Ian Cordasco 2016-06-25 12:01:02 -05:00
commit cee691059f
No known key found for this signature in database
GPG key ID: 656D3395E4A9791A
167 changed files with 11120 additions and 3162 deletions

84
.bandit.yml Normal file
View file

@ -0,0 +1,84 @@
tests:
skips:
- B404 # Ignore warnings about importing subprocess
- B603 # Ignore warnings about calling subprocess.Popen without shell=True
- B607 # Ignore warnings about calling subprocess.Popen without a full path to executable
### (optional) plugin settings - some test plugins require configuration data
### that may be given here, per-plugin. All bandit test plugins have a built in
### set of sensible defaults and these will be used if no configuration is
### provided. It is not necessary to provide settings for every (or any) plugin
### if the defaults are acceptable.
any_other_function_with_shell_equals_true:
no_shell: [os.execl, os.execle, os.execlp, os.execlpe, os.execv, os.execve, os.execvp,
os.execvpe, os.spawnl, os.spawnle, os.spawnlp, os.spawnlpe, os.spawnv, os.spawnve,
os.spawnvp, os.spawnvpe, os.startfile]
shell: [os.system, os.popen, os.popen2, os.popen3, os.popen4, popen2.popen2, popen2.popen3,
popen2.popen4, popen2.Popen3, popen2.Popen4, commands.getoutput, commands.getstatusoutput]
subprocess: [subprocess.Popen, subprocess.call, subprocess.check_call, subprocess.check_output,
utils.execute, utils.execute_with_timeout]
execute_with_run_as_root_equals_true:
function_names: [ceilometer.utils.execute, cinder.utils.execute, neutron.agent.linux.utils.execute,
nova.utils.execute, nova.utils.trycmd]
hardcoded_tmp_directory:
tmp_dirs: [/tmp, /var/tmp, /dev/shm]
linux_commands_wildcard_injection:
no_shell: [os.execl, os.execle, os.execlp, os.execlpe, os.execv, os.execve, os.execvp,
os.execvpe, os.spawnl, os.spawnle, os.spawnlp, os.spawnlpe, os.spawnv, os.spawnve,
os.spawnvp, os.spawnvpe, os.startfile]
shell: [os.system, os.popen, os.popen2, os.popen3, os.popen4, popen2.popen2, popen2.popen3,
popen2.popen4, popen2.Popen3, popen2.Popen4, commands.getoutput, commands.getstatusoutput]
subprocess: [subprocess.Popen, subprocess.call, subprocess.check_call, subprocess.check_output,
utils.execute, utils.execute_with_timeout]
password_config_option_not_marked_secret:
function_names: [oslo.config.cfg.StrOpt, oslo_config.cfg.StrOpt]
ssl_with_bad_defaults:
bad_protocol_versions: [PROTOCOL_SSLv2, SSLv2_METHOD, SSLv23_METHOD, PROTOCOL_SSLv3,
PROTOCOL_TLSv1, SSLv3_METHOD, TLSv1_METHOD]
ssl_with_bad_version:
bad_protocol_versions: [PROTOCOL_SSLv2, SSLv2_METHOD, SSLv23_METHOD, PROTOCOL_SSLv3,
PROTOCOL_TLSv1, SSLv3_METHOD, TLSv1_METHOD]
start_process_with_a_shell:
no_shell: [os.execl, os.execle, os.execlp, os.execlpe, os.execv, os.execve, os.execvp,
os.execvpe, os.spawnl, os.spawnle, os.spawnlp, os.spawnlpe, os.spawnv, os.spawnve,
os.spawnvp, os.spawnvpe, os.startfile]
shell: [os.system, os.popen, os.popen2, os.popen3, os.popen4, popen2.popen2, popen2.popen3,
popen2.popen4, popen2.Popen3, popen2.Popen4, commands.getoutput, commands.getstatusoutput]
subprocess: [subprocess.Popen, subprocess.call, subprocess.check_call, subprocess.check_output,
utils.execute, utils.execute_with_timeout]
start_process_with_no_shell:
no_shell: [os.execl, os.execle, os.execlp, os.execlpe, os.execv, os.execve, os.execvp,
os.execvpe, os.spawnl, os.spawnle, os.spawnlp, os.spawnlpe, os.spawnv, os.spawnve,
os.spawnvp, os.spawnvpe, os.startfile]
shell: [os.system, os.popen, os.popen2, os.popen3, os.popen4, popen2.popen2, popen2.popen3,
popen2.popen4, popen2.Popen3, popen2.Popen4, commands.getoutput, commands.getstatusoutput]
subprocess: [subprocess.Popen, subprocess.call, subprocess.check_call, subprocess.check_output,
utils.execute, utils.execute_with_timeout]
start_process_with_partial_path:
no_shell: [os.execl, os.execle, os.execlp, os.execlpe, os.execv, os.execve, os.execvp,
os.execvpe, os.spawnl, os.spawnle, os.spawnlp, os.spawnlpe, os.spawnv, os.spawnve,
os.spawnvp, os.spawnvpe, os.startfile]
shell: [os.system, os.popen, os.popen2, os.popen3, os.popen4, popen2.popen2, popen2.popen3,
popen2.popen4, popen2.Popen3, popen2.Popen4, commands.getoutput, commands.getstatusoutput]
subprocess: [subprocess.Popen, subprocess.call, subprocess.check_call, subprocess.check_output,
utils.execute, utils.execute_with_timeout]
subprocess_popen_with_shell_equals_true:
no_shell: [os.execl, os.execle, os.execlp, os.execlpe, os.execv, os.execve, os.execvp,
os.execvpe, os.spawnl, os.spawnle, os.spawnlp, os.spawnlpe, os.spawnv, os.spawnve,
os.spawnvp, os.spawnvpe, os.startfile]
shell: [os.system, os.popen, os.popen2, os.popen3, os.popen4, popen2.popen2, popen2.popen3,
popen2.popen4, popen2.Popen3, popen2.Popen4, commands.getoutput, commands.getstatusoutput]
subprocess: [subprocess.Popen, subprocess.call, subprocess.check_call, subprocess.check_output,
utils.execute, utils.execute_with_timeout]
subprocess_without_shell_equals_true:
no_shell: [os.execl, os.execle, os.execlp, os.execlpe, os.execv, os.execve, os.execvp,
os.execvpe, os.spawnl, os.spawnle, os.spawnlp, os.spawnlpe, os.spawnv, os.spawnve,
os.spawnvp, os.spawnvpe, os.startfile]
shell: [os.system, os.popen, os.popen2, os.popen3, os.popen4, popen2.popen2, popen2.popen3,
popen2.popen4, popen2.Popen3, popen2.Popen4, commands.getoutput, commands.getstatusoutput]
subprocess: [subprocess.Popen, subprocess.call, subprocess.check_call, subprocess.check_output,
utils.execute, utils.execute_with_timeout]
try_except_continue: {check_typed_exception: false}
try_except_pass: {check_typed_exception: false}

5
.gitignore vendored
View file

@ -1,7 +1,12 @@
*.pyc
.tox
.eggs
*.egg
*.egg-info
build
dist
*.zip
.cache
*.sw*
*.log
docs/build/html/*

378
.pylintrc Normal file
View file

@ -0,0 +1,378 @@
[MASTER]
# Specify a configuration file.
#rcfile=
# Python code to execute, usually for sys.path manipulation such as
# pygtk.require().
#init-hook=
# Add files or directories to the blacklist. They should be base names, not
# paths.
ignore=CVS,.git,flake8.egg-info
# Pickle collected data for later comparisons.
persistent=yes
# List of plugins (as comma separated values of python modules names) to load,
# usually to register additional checkers.
load-plugins=
# Use multiple processes to speed up Pylint.
jobs=4
# Allow loading of arbitrary C extensions. Extensions are imported into the
# active Python interpreter and may run arbitrary code.
unsafe-load-any-extension=no
# A comma-separated list of package or module names from where C extensions may
# be loaded. Extensions are loading into the active Python interpreter and may
# run arbitrary code
extension-pkg-whitelist=
# Allow optimization of some AST trees. This will activate a peephole AST
# optimizer, which will apply various small optimizations. For instance, it can
# be used to obtain the result of joining multiple strings with the addition
# operator. Joining a lot of strings can lead to a maximum recursion error in
# Pylint and this flag can prevent that. It has one side effect, the resulting
# AST will be different than the one from reality.
optimize-ast=no
[MESSAGES CONTROL]
# Only show warnings with the listed confidence levels. Leave empty to show
# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED
confidence=INFERENCE_FAILURE
# Enable the message, report, category or checker with the given id(s). You can
# either give multiple identifier separated by comma (,) or put this option
# multiple time. See also the "--disable" option for examples.
#enable=
# Disable the message, report, category or checker with the given id(s). You
# can either give multiple identifiers separated by comma (,) or put this
# option multiple times (only on the command line, not in the configuration
# file where it should appear only once).You can also use "--disable=all" to
# disable everything first and then reenable specific checks. For example, if
# you want to run only the similarities checker, you can use "--disable=all
# --enable=similarities". If you want to run only the classes checker, but have
# no Warning level messages displayed, use"--disable=all --enable=classes
# --disable=W"
disable=intern-builtin,nonzero-method,parameter-unpacking,backtick,raw_input-builtin,dict-view-method,filter-builtin-not-iterating,long-builtin,unichr-builtin,input-builtin,unicode-builtin,file-builtin,map-builtin-not-iterating,delslice-method,apply-builtin,cmp-method,setslice-method,coerce-method,long-suffix,raising-string,import-star-module-level,buffer-builtin,reload-builtin,unpacking-in-except,print-statement,hex-method,old-octal-literal,metaclass-assignment,dict-iter-method,range-builtin-not-iterating,using-cmp-argument,indexing-exception,no-absolute-import,coerce-builtin,getslice-method,suppressed-message,execfile-builtin,round-builtin,useless-suppression,reduce-builtin,old-raise-syntax,zip-builtin-not-iterating,cmp-builtin,xrange-builtin,standarderror-builtin,old-division,oct-method,next-method-called,old-ne-operator,basestring-builtin
[REPORTS]
# Set the output format. Available formats are text, parseable, colorized, msvs
# (visual studio) and html. You can also give a reporter class, eg
# mypackage.mymodule.MyReporterClass.
output-format=text
# Put messages in a separate file for each module / package specified on the
# command line instead of printing them on stdout. Reports (if any) will be
# written in a file name "pylint_global.[txt|html]".
files-output=no
# Tells whether to display a full report or only the messages
reports=no
# Python expression which should return a note less than 10 (10 is the highest
# note). You have access to the variables errors warning, statement which
# respectively contain the number of errors / warnings messages and the total
# number of statements analyzed. This is used by the global evaluation report
# (RP0004).
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
# Template used to display messages. This is a python new-style format string
# used to format the message information. See doc for all details
#msg-template=
[BASIC]
# List of builtins function names that should not be used, separated by a comma
bad-functions=map,filter
# Good variable names which should always be accepted, separated by a comma
good-names=i,j,k,ex,Run,_
# Bad variable names which should always be refused, separated by a comma
bad-names=foo,bar,baz,toto,tutu,tata
# Colon-delimited sets of names that determine each other's naming style when
# the name regexes allow several styles.
name-group=
# Include a hint for the correct naming format with invalid-name
include-naming-hint=yes
# Regular expression matching correct argument names
argument-rgx=[a-z_][a-z0-9_]{2,30}$
# Naming hint for argument names
argument-name-hint=[a-z_][a-z0-9_]{2,30}$
# Regular expression matching correct attribute names
attr-rgx=[a-z_][a-z0-9_]{2,30}$
# Naming hint for attribute names
attr-name-hint=[a-z_][a-z0-9_]{2,30}$
# Regular expression matching correct constant names
const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$
# Naming hint for constant names
const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$
# Regular expression matching correct class names
class-rgx=[A-Z_][a-zA-Z0-9]+$
# Naming hint for class names
class-name-hint=[A-Z_][a-zA-Z0-9]+$
# Regular expression matching correct inline iteration names
inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
# Naming hint for inline iteration names
inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$
# Regular expression matching correct class attribute names
class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
# Naming hint for class attribute names
class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
# Regular expression matching correct function names
function-rgx=[a-z_][a-z0-9_]{2,30}$
# Naming hint for function names
function-name-hint=[a-z_][a-z0-9_]{2,30}$
# Regular expression matching correct module names
module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
# Naming hint for module names
module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
# Regular expression matching correct method names
method-rgx=[a-z_][a-z0-9_]{2,30}$
# Naming hint for method names
method-name-hint=[a-z_][a-z0-9_]{2,30}$
# Regular expression matching correct variable names
variable-rgx=[a-z_][a-z0-9_]{2,30}$
# Naming hint for variable names
variable-name-hint=[a-z_][a-z0-9_]{2,30}$
# Regular expression which should only match function or class names that do
# not require a docstring.
no-docstring-rgx=^_
# Minimum line length for functions/classes that require docstrings, shorter
# ones are exempt.
docstring-min-length=-1
[ELIF]
# Maximum number of nested blocks for function / method body
max-nested-blocks=5
[FORMAT]
# Maximum number of characters on a single line.
max-line-length=100
# Regexp for a line that is allowed to be longer than the limit.
ignore-long-lines=^\s*(# )?<?https?://\S+>?$
# Allow the body of an if to be on the same line as the test if there is no
# else.
single-line-if-stmt=no
# List of optional constructs for which whitespace checking is disabled. `dict-
# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}.
# `trailing-comma` allows a space between comma and closing bracket: (a, ).
# `empty-line` allows space-only lines.
no-space-check=trailing-comma,dict-separator
# Maximum number of lines in a module
max-module-lines=1000
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
# tab).
indent-string=' '
# Number of spaces of indent required inside a hanging or continued line.
indent-after-paren=4
# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
expected-line-ending-format=
[LOGGING]
# Logging modules to check that the string format arguments are in logging
# function parameter format
logging-modules=logging
[MISCELLANEOUS]
# List of note tags to take in consideration, separated by a comma.
notes=FIXME,XXX,TODO
[SIMILARITIES]
# Minimum lines number of a similarity.
min-similarity-lines=4
# Ignore comments when computing similarities.
ignore-comments=yes
# Ignore docstrings when computing similarities.
ignore-docstrings=yes
# Ignore imports when computing similarities.
ignore-imports=no
[SPELLING]
# Spelling dictionary name. Available dictionaries: none. To make it working
# install python-enchant package.
spelling-dict=
# List of comma separated words that should not be checked.
spelling-ignore-words=
# A path to a file that contains private dictionary; one word per line.
spelling-private-dict-file=
# Tells whether to store unknown words to indicated private dictionary in
# --spelling-private-dict-file option instead of raising a message.
spelling-store-unknown-words=no
[TYPECHECK]
# Tells whether missing members accessed in mixin class should be ignored. A
# mixin class is detected if its name ends with "mixin" (case insensitive).
ignore-mixin-members=yes
# List of module names for which member attributes should not be checked
# (useful for modules/projects where namespaces are manipulated during runtime
# and thus existing member attributes cannot be deduced by static analysis. It
# supports qualified module names, as well as Unix pattern matching.
ignored-modules=
# List of classes names for which member attributes should not be checked
# (useful for classes with attributes dynamically set). This supports can work
# with qualified names.
ignored-classes=
# List of members which are set dynamically and missed by pylint inference
# system, and so shouldn't trigger E1101 when accessed. Python regular
# expressions are accepted.
generated-members=
[VARIABLES]
# Tells whether we should check for unused import in __init__ files.
init-import=no
# A regular expression matching the name of dummy variables (i.e. expectedly
# not used).
dummy-variables-rgx=_$|dummy
# List of additional names supposed to be defined in builtins. Remember that
# you should avoid to define new builtins when possible.
additional-builtins=
# List of strings which can identify a callback function by name. A callback
# name must start or end with one of those strings.
callbacks=cb_,_cb
[CLASSES]
# List of method names used to declare (i.e. assign) instance attributes.
defining-attr-methods=__init__,__new__,setUp
# List of valid names for the first argument in a class method.
valid-classmethod-first-arg=cls
# List of valid names for the first argument in a metaclass class method.
valid-metaclass-classmethod-first-arg=mcs
# List of member names, which should be excluded from the protected access
# warning.
exclude-protected=_asdict,_fields,_replace,_source,_make
[DESIGN]
# Maximum number of arguments for function / method
max-args=20
# Argument names that match this expression will be ignored. Default to name
# with leading underscore
ignored-argument-names=_.*
# Maximum number of locals for function / method body
max-locals=20
# Maximum number of return / yield for function / method body
max-returns=6
# Maximum number of branch for function / method body
max-branches=12
# Maximum number of statements in function / method body
max-statements=50
# Maximum number of parents for a class (see R0901).
max-parents=7
# Maximum number of attributes for a class (see R0902).
max-attributes=10
# Minimum number of public methods for a class (see R0903).
min-public-methods=2
# Maximum number of public methods for a class (see R0904).
max-public-methods=20
# Maximum number of boolean expressions in a if statement
max-bool-expr=5
[IMPORTS]
# Deprecated modules which should not be used, separated by a comma
deprecated-modules=optparse
# Create a graph of every (i.e. internal and external) dependencies in the
# given file (report RP0402 must not be disabled)
import-graph=
# Create a graph of external dependencies in the given file (report RP0402 must
# not be disabled)
ext-import-graph=
# Create a graph of internal dependencies in the given file (report RP0402 must
# not be disabled)
int-import-graph=
[EXCEPTIONS]
# Exceptions that will emit a warning when being caught. Defaults to
# "Exception"
overgeneral-exceptions=Exception

View file

@ -11,8 +11,6 @@ notifications:
matrix:
include:
- python: 2.6
env: TOXENV=py26
- python: 2.7
env: TOXENV=py27
- python: 3.3
@ -24,6 +22,14 @@ matrix:
- python: pypy
env: TOXENV=pypy
- python: 2.7
env: TOXENV=py27-flake8
env: TOXENV=readme
- python: 3.4
env: TOXENV=py34-flake8
env: TOXENV=flake8
- python: 3.4
env: TOXENV=pylint
- python: 3.4
env: TOXENV=doc8
- python: 3.4
env: TOXENV=bandit
- python: 3.4
env: TOXENV=docs

View file

@ -1,362 +0,0 @@
CHANGES
=======
2.6.1 - 2016-06-25
------------------
- **Bug** Update the config files to search for to include ``setup.cfg`` and
``tox.ini``. This was broken in 2.5.5 when we stopped passing
``config_file`` to our Style Guide
2.6.0 - 2016-06-15
------------------
- **Requirements Change** Switch to pycodestyle as all future pep8 releases
will use that package name
- **Improvement** Allow for Windows users on *select* versions of Python to
use ``--jobs`` and multiprocessing
- **Improvement** Update bounds on McCabe
- **Improvement** Update bounds on PyFlakes and blacklist known broken
versions
- **Improvement** Handle new PyFlakes warning with a new error code: F405
2.5.5 - 2016-06-14
------------------
- **Bug** Fix setuptools integration when parsing config files
- **Bug** Don't pass the user's config path as the config_file when creating a
StyleGuide
2.5.4 - 2016-02-11
------------------
- **Bug** Missed an attribute rename during the v2.5.3 release.
2.5.3 - 2016-02-11
------------------
- **Bug** Actually parse ``output_file`` and ``enable_extensions`` from config
files
2.5.2 - 2016-01-30
------------------
- **Bug** Parse ``output_file`` and ``enable_extensions`` from config files
- **Improvement** Raise upper bound on mccabe plugin to allow for version
0.4.0
2.5.1 - 2015-12-08
------------------
- **Bug** Properly look for ``.flake8`` in current working directory
(`GitLab#103`_)
- **Bug** Monkey-patch ``pep8.stdin_get_value`` to cache the actual value in
stdin. This helps plugins relying on the function when run with
multiprocessing. (`GitLab#105`_, `GitLab#107`_)
.. _GitLab#103: https://gitlab.com/pycqa/flake8/issues/103
.. _GitLab#105: https://gitlab.com/pycqa/flake8/issues/105
.. _GitLab#107: https://gitlab.com/pycqa/flake8/issues/107
2.5.0 - 2015-10-26
------------------
- **Improvement** Raise cap on PyFlakes for Python 3.5 support
- **Improvement** Avoid deprecation warnings when loading extensions
(`GitLab#59`_, `GitLab#90`_)
- **Improvement** Separate logic to enable "off-by-default" extensions
(`GitLab#67`_)
- **Bug** Properly parse options to setuptools Flake8 command (`GitLab!41`_)
- **Bug** Fix exceptions when output on stdout is truncated before Flake8
finishes writing the output (`GitLab#69`_)
- **Bug** Fix error on OS X where Flake8 can no longer acquire or create new
semaphores (`GitLab#74`_)
.. _GitLab!41: https://gitlab.com/pycqa/flake8/merge_requests/41
.. _GitLab#59: https://gitlab.com/pycqa/flake8/issues/59
.. _GitLab#67: https://gitlab.com/pycqa/flake8/issues/67
.. _GitLab#69: https://gitlab.com/pycqa/flake8/issues/69
.. _GitLab#74: https://gitlab.com/pycqa/flake8/issues/74
.. _GitLab#90: https://gitlab.com/pycqa/flake8/issues/90
2.4.1 - 2015-05-18
------------------
- **Bug** Do not raise a ``SystemError`` unless there were errors in the
setuptools command. (`GitLab#39`_, `GitLab!23`_)
- **Bug** Do not verify dependencies of extensions loaded via entry-points.
- **Improvement** Blacklist versions of pep8 we know are broken
.. _GitLab#39: https://gitlab.com/pycqa/flake8/issues/39
.. _GitLab!23: https://gitlab.com/pycqa/flake8/merge_requests/23
2.4.0 - 2015-03-07
------------------
- **Bug** Print filenames when using multiprocessing and ``-q`` option.
(`GitLab#31`_)
- **Bug** Put upper cap on dependencies. The caps for 2.4.0 are:
- ``pep8 < 1.6`` (Related to `GitLab#35`_)
- ``mccabe < 0.4``
- ``pyflakes < 0.9``
See also `GitLab#32`_
- **Bug** Files excluded in a config file were not being excluded when flake8
was run from a git hook. (`GitHub#2`_)
- **Improvement** Print warnings for users who are providing mutually
exclusive options to flake8. (`GitLab#8`_, `GitLab!18`_)
- **Feature** Allow git hook configuration to live in ``.git/config``.
See the updated `VCS hooks docs`_ for more details. (`GitLab!20`_)
.. _GitHub#2: https://github.com/pycqa/flake8/pull/2
.. _GitLab#8: https://gitlab.com/pycqa/flake8/issues/8
.. _GitLab#31: https://gitlab.com/pycqa/flake8/issues/31
.. _GitLab#32: https://gitlab.com/pycqa/flake8/issues/32
.. _GitLab#35: https://gitlab.com/pycqa/flake8/issues/35
.. _GitLab!18: https://gitlab.com/pycqa/flake8/merge_requests/18
.. _GitLab!20: https://gitlab.com/pycqa/flake8/merge_requests/20
.. _VCS hooks docs: https://flake8.readthedocs.io/en/latest/vcs.html
2.3.0 - 2015-01-04
------------------
- **Feature**: Add ``--output-file`` option to specify a file to write to
instead of ``stdout``.
- **Bug** Fix interleaving of output while using multiprocessing
(`GitLab#17`_)
.. _GitLab#17: https://gitlab.com/pycqa/flake8/issues/17
2.2.5 - 2014-10-19
------------------
- Flush standard out when using multiprocessing
- Make the check for "# flake8: noqa" more strict
2.2.4 - 2014-10-09
------------------
- Fix bugs triggered by turning multiprocessing on by default (again)
Multiprocessing is forcibly disabled in the following cases:
- Passing something in via stdin
- Analyzing a diff
- Using windows
- Fix --install-hook when there are no config files present for pep8 or
flake8.
- Fix how the setuptools command parses excludes in config files
- Fix how the git hook determines which files to analyze (Thanks Chris
Buccella!)
2.2.3 - 2014-08-25
------------------
- Actually turn multiprocessing on by default
2.2.2 - 2014-07-04
------------------
- Re-enable multiprocessing by default while fixing the issue Windows users
were seeing.
2.2.1 - 2014-06-30
------------------
- Turn off multiple jobs by default. To enable automatic use of all CPUs, use
``--jobs=auto``. Fixes #155 and #154.
2.2.0 - 2014-06-22
------------------
- New option ``doctests`` to run Pyflakes checks on doctests too
- New option ``jobs`` to launch multiple jobs in parallel
- Turn on using multiple jobs by default using the CPU count
- Add support for ``python -m flake8`` on Python 2.7 and Python 3
- Fix Git and Mercurial hooks: issues #88, #133, #148 and #149
- Fix crashes with Python 3.4 by upgrading dependencies
- Fix traceback when running tests with Python 2.6
- Fix the setuptools command ``python setup.py flake8`` to read
the project configuration
2.1.0 - 2013-10-26
------------------
- Add FLAKE8_LAZY and FLAKE8_IGNORE environment variable support to git and
mercurial hooks
- Force git and mercurial hooks to repsect configuration in setup.cfg
- Only check staged files if that is specified
- Fix hook file permissions
- Fix the git hook on python 3
- Ignore non-python files when running the git hook
- Ignore .tox directories by default
- Flake8 now reports the column number for PyFlakes messages
2.0.0 - 2013-02-23
------------------
- Pyflakes errors are prefixed by an ``F`` instead of an ``E``
- McCabe complexity warnings are prefixed by a ``C`` instead of a ``W``
- Flake8 supports extensions through entry points
- Due to the above support, we **require** setuptools
- We publish the `documentation <https://flake8.readthedocs.io/>`_
- Fixes #13: pep8, pyflakes and mccabe become external dependencies
- Split run.py into main.py, engine.py and hooks.py for better logic
- Expose our parser for our users
- New feature: Install git and hg hooks automagically
- By relying on pyflakes (0.6.1), we also fixed #45 and #35
1.7.0 - 2012-12-21
------------------
- Fixes part of #35: Exception for no WITHITEM being an attribute of Checker
for Python 3.3
- Support stdin
- Incorporate @phd's builtins pull request
- Fix the git hook
- Update pep8.py to the latest version
1.6.2 - 2012-11-25
------------------
- fixed the NameError: global name 'message' is not defined (#46)
1.6.1 - 2012-11-24
------------------
- fixed the mercurial hook, a change from a previous patch was not properly
applied
- fixed an assumption about warnings/error messages that caused an exception
to be thrown when McCabe is used
1.6 - 2012-11-16
----------------
- changed the signatures of the ``check_file`` function in flake8/run.py,
``skip_warning`` in flake8/util.py and the ``check``, ``checkPath``
functions in flake8/pyflakes.py.
- fix ``--exclude`` and ``--ignore`` command flags (#14, #19)
- fix the git hook that wasn't catching files not already added to the index
(#29)
- pre-emptively includes the addition to pep8 to ignore certain lines.
Add ``# nopep8`` to the end of a line to ignore it. (#37)
- ``check_file`` can now be used without any special prior setup (#21)
- unpacking exceptions will no longer cause an exception (#20)
- fixed crash on non-existent file (#38)
1.5 - 2012-10-13
----------------
- fixed the stdin
- make sure mccabe catches the syntax errors as warnings
- pep8 upgrade
- added max_line_length default value
- added Flake8Command and entry points if setuptools is around
- using the setuptools console wrapper when available
1.4 - 2012-07-12
----------------
- git_hook: Only check staged changes for compliance
- use pep8 1.2
1.3.1 - 2012-05-19
------------------
- fixed support for Python 2.5
1.3 - 2012-03-12
----------------
- fixed false W402 warning on exception blocks.
1.2 - 2012-02-12
----------------
- added a git hook
- now Python 3 compatible
- mccabe and pyflakes have warning codes like pep8 now
1.1 - 2012-02-14
----------------
- fixed the value returned by --version
- allow the flake8: header to be more generic
- fixed the "hg hook raises 'physical lines'" bug
- allow three argument form of raise
- now uses setuptools if available, for 'develop' command
1.0 - 2011-11-29
----------------
- Deactivates by default the complexity checker
- Introduces the complexity option in the HG hook and the command line.
0.9 - 2011-11-09
----------------
- update pep8 version to 0.6.1
- mccabe check: gracefully handle compile failure
0.8 - 2011-02-27
----------------
- fixed hg hook
- discard unexisting files on hook check
0.7 - 2010-02-18
----------------
- Fix pep8 initialization when run through Hg
- Make pep8 short options work when run through the command line
- Skip duplicates when controlling files via Hg
0.6 - 2010-02-15
----------------
- Fix the McCabe metric on some loops

1
CONTRIBUTING.rst Symbolic link
View file

@ -0,0 +1 @@
docs/source/internal/contributing.rst

View file

@ -1,7 +1,7 @@
== Flake8 License (MIT) ==
Copyright (C) 2011-2013 Tarek Ziade <tarek@ziade.org>
Copyright (C) 2012-2013 Ian Cordasco <graffatcolmingov@gmail.com>
Copyright (C) 2012-2016 Ian Cordasco <graffatcolmingov@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in

View file

@ -1,4 +1,6 @@
include *.rst
include CONTRIBUTORS.txt
include LICENSE
recursive-include flake8 *
recursive-include docs *
recursive-include tests *
recursive-include src *

View file

@ -1,99 +0,0 @@
#!/usr/bin/env python
"""\
Git patch to HG changeset patch converter.
USAGE: git-patch-to-hg-export.py < git.patch > hg.patch
"""
from email.utils import parsedate_tz, mktime_tz
import re
import os
import sys
def git_patch_to_hg(fin, fout):
fout.write('# HG changeset patch\n')
subject_re = re.compile(r'^(RE:)?\s*(\[[^]]*\])?\s*', re.I)
# headers
for line in fin:
if line.startswith('From: '):
fout.write('# User %s' % line[6:])
elif line.startswith('Date: '):
t = parsedate_tz(line[6:])
timestamp = mktime_tz(t)
timezone = -t[-1]
fout.write('# Date %d %d\n' % (timestamp, timezone))
elif line.startswith('Subject: '):
subject = subject_re.sub('', line[9:])
fout.write(subject + '\n')
elif line == '\n' or line == '\r\n':
break
# commit message
for line in fin:
if line == '---\n':
break
fout.write(line)
# skip over the diffstat
for line in fin:
if line.startswith('diff --git'):
fout.write('\n' + line)
break
# diff
# NOTE: there will still be an index line after each diff --git, but it
# will be ignored
for line in fin:
fout.write(line.encode('utf-8'))
# NOTE: the --/version will still be at the end, but it will be ignored
def open_file():
if len(sys.argv) > 1:
if re.match('https?://', sys.argv[1]):
import requests
import io
resp = requests.get(sys.argv[1])
if resp.ok:
return io.StringIO(resp.content.decode('utf-8'))
else:
return io.StringIO('')
elif os.path.exists(sys.argv[1]):
return open(sys.argv[1])
return sys.stdin
if __name__ == "__main__":
patch_fd = open_file()
git_patch_to_hg(patch_fd, sys.stdout)
__author__ = "Mark Lodato <lodatom@gmail.com>"
__license__ = """
This is the MIT license: http://www.opensource.org/licenses/mit-license.php
Copyright (c) 2009 Mark Lodato
Permission 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.
"""

View file

@ -1,5 +1 @@
pycodestyle
pyflakes
mccabe
mock
nose
tox

View file

@ -1,130 +0,0 @@
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = _build
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
clean:
-rm -rf $(BUILDDIR)/*
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Raclette.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Raclette.qhc"
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/Raclette"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Raclette"
@echo "# devhelp"
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
make -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."

View file

@ -1,38 +0,0 @@
==========
Flake8 API
==========
.. module:: flake8
flake8.engine
=============
.. autofunction:: flake8.engine.get_parser
.. autofunction:: flake8.engine.get_style_guide
flake8.hooks
============
.. autofunction:: flake8.hooks.git_hook
.. autofunction:: flake8.hooks.hg_hook
flake8.main
===========
.. autofunction:: flake8.main.main
.. autofunction:: flake8.main.check_file
.. autofunction:: flake8.main.check_code
.. autoclass:: flake8.main.Flake8Command
flake8.util
===========
For AST checkers, this module has the ``iter_child_nodes`` function and
handles compatibility for all versions of Python between 2.5 and 3.3. The
function was added to the ``ast`` module in Python 2.6 but is redefined in the
case where the user is running Python 2.5

0
docs/build/.keep vendored Normal file
View file

View file

@ -1,17 +0,0 @@
Buildout integration
=====================
In order to use Flake8 inside a buildout, edit your buildout.cfg and add this::
[buildout]
parts +=
...
flake8
[flake8]
recipe = zc.recipe.egg
eggs = flake8
${buildout:eggs}
entry-points =
flake8=flake8.main:main

View file

@ -1,5 +0,0 @@
Changes
=======
.. include:: ../CHANGES.rst
:start-line: 3

View file

@ -1,68 +0,0 @@
Configuration
=============
Configuration settings are applied in three ways: user, project, and the
``--config`` CLI argument. The user (global) configuration is read first. Next
the project configuration is loaded, and overrides any settings found in both
the user (global) and project configurations. Finally, if the ``--config``
argument is used on the command line, the specified file is loaded and
overrides any settings that overlap with the user (global) and project
configurations.
User (Global)
-------------
The user settings are read from the ``~/.config/flake8`` file (or the
``~/.flake8`` file on Windows).
Example::
[flake8]
ignore = E226,E302,E41
max-line-length = 160
exclude = tests/*
max-complexity = 10
Per-Project
-----------
At the project level, the ``tox.ini``, ``setup.cfg``, ``.pep8`` or ``.flake8``
files are read if present. Only the first file is considered. If this file
does not have a ``[flake8]`` section, no project specific configuration is
loaded.
Per Code Line
-------
To ignore one line of code add ``# NOQA`` as a line comment.
Default
-------
If the ``ignore`` option is not in the configuration and not in the arguments,
only the error codes ``E123/E133``, ``E226`` and ``E241/E242`` are ignored
(see the :ref:`warning and error codes <error-codes>`).
Settings
--------
This is a (likely incomplete) list of settings that can be used in your config
file. In general, any settings that ``pycodestyle`` supports we also support and
we add the ability to set ``max-complexity`` as well.
- ``exclude``: comma-separated filename and glob patterns
default: ``.svn,CVS,.bzr,.hg,.git,__pycache__``
- ``filename``: comma-separated filename and glob patterns
default: ``*.py``
- ``select``: select errors and warnings to enable which are off by default
- ``ignore``: skip errors or warnings
- ``max-line-length``: set maximum allowed line length
default: 79
- ``format``: set the error format
- ``max-complexity``: McCabe complexity threshold

View file

@ -1,149 +0,0 @@
Writing an Extension for Flake8
===============================
Since Flake8 is now adding support for extensions, we require ``setuptools``
so we can manage extensions through entry points. If you are making an
existing tool compatible with Flake8 but do not already require
``setuptools``, you should probably add it to your list of requirements. Next,
you'll need to edit your ``setup.py`` file so that upon installation, your
extension is registered. If you define a class called ``PackageEntryClass``
then this would look something like the following::
setup(
# ...
entry_points={
'flake8.extension': ['P10 = package.PackageEntryClass'],
}
# ...
)
If you intend to publish your extension, choose a unique code prefix
following the convention for :ref:`error codes <error-codes>`.
In addition, you can open a request in the `issue tracker
<https://bitbucket.org/tarek/flake8/issues>`_ to register the prefix in the
documentation.
.. TODO: describe the API required for the 3 kind of extensions:
* physical line checkers
* logical line checkers
* AST checkers
A real example: McCabe
----------------------
Below is an example from mccabe_ for how to write your ``setup.py`` file for
your Flake8 extension.
.. code-block:: python
# https://github.com/flintwork/mccabe/blob/0.2/setup.py#L38:L42
# -*- coding: utf-8 -*-
from setuptools import setup
# ...
setup(
name='mccabe',
# ...
install_requires=[
'setuptools',
],
entry_points={
'flake8.extension': [
'C90 = mccabe:McCabeChecker',
],
},
# ...
)
In ``mccabe.py`` you can see that extra options are added to the parser when
flake8 registers the extension:
.. code-block:: python
# https://github.com/flintwork/mccabe/blob/0.2/mccabe.py#L225:L254
class McCabeChecker(object):
"""McCabe cyclomatic complexity checker."""
name = 'mccabe'
version = __version__
_code = 'C901'
_error_tmpl = "C901 %r is too complex (%d)"
max_complexity = 0
def __init__(self, tree, filename):
self.tree = tree
@classmethod
def add_options(cls, parser):
parser.add_option('--max-complexity', default=-1, action='store',
type='int', help="McCabe complexity threshold")
parser.config_options.append('max-complexity')
@classmethod
def parse_options(cls, options):
cls.max_complexity = options.max_complexity
def run(self):
if self.max_complexity < 0:
return
visitor = PathGraphingAstVisitor()
visitor.preorder(self.tree, visitor)
for graph in visitor.graphs.values():
if graph.complexity() >= self.max_complexity:
text = self._error_tmpl % (graph.entity, graph.complexity())
yield graph.lineno, 0, text, type(self)
Since that is the defined entry point in the above ``setup.py``, flake8 finds
it and uses it to register the extension.
If we wanted the extension or a check to be optional, you can add
``off_by_default = True`` to our entry point. For example, we could
update ``mccabe.py`` with this variable as shown below:
.. code-block:: python
# https://github.com/flintwork/mccabe/blob/0.2/mccabe.py#L225:L254
class McCabeChecker(object):
"""McCabe cyclomatic complexity checker."""
name = 'mccabe'
version = __version__
off_by_default = True
If we wanted to run the optional extension or check, we need to specify the
error and warnings via the ``--enable-extension`` command line argument. In our
case, we could run ``flake8 --enable-extension=C90`` which would enable our
off_by_default example version of the mccabe extension.
Existing Extensions
===================
This is not at all a comprehensive listing of existing extensions but simply a
listing of the ones we are aware of:
* `flake8-debugger <https://github.com/JBKahn/flake8-debugger>`_
* `flake8-immediate <https://github.com/schlamar/flake8-immediate>`_
* `flake8-print <https://github.com/JBKahn/flake8-print>`_
* `flake8-todo <https://github.com/schlamar/flake8-todo>`_
* `pep8-naming <https://github.com/flintwork/pep8-naming>`_
* `radon <https://github.com/rubik/radon>`_
* `flake8-import-order <https://github.com/public/flake8-import-order>`_
* `flake8-respect-noqa <https://pypi.python.org/pypi/flake8-respect-noqa>`_
.. links
.. _mccabe: https://github.com/flintwork/mccabe
.. _PyPI: https://pypi.python.org/pypi/

View file

@ -1,26 +0,0 @@
.. include:: ../README.rst
Documentation
=============
.. toctree::
config
warnings
vcs
buildout
setuptools
api
extensions
changes
Original Projects
=================
Flake8 is just a glue project, all the merits go to the creators and maintainers
of the original projects:
- pycodestyle: https://github.com/pycqa/pycodestyle
- PyFlakes: https://launchpad.net/pyflakes
- McCabe: http://nedbatchelder.com/blog/200803/python_code_complexity_microtool.html

View file

@ -1,25 +0,0 @@
Setuptools integration
======================
Upon installation, Flake8 enables a setuptools command that checks Python
files declared by your project.
Running ``python setup.py flake8`` on the command line will check the files
listed in your ``py_modules`` and ``packages``. If any warning is found,
the command will exit with an error code::
$ python setup.py flake8
Also, to allow users to be able to use the command without having to install
flake8 themselves, add flake8 to the setup_requires of your setup() like so::
setup(
name="project",
packages=["project"],
setup_requires=[
"flake8"
]
)

View file

@ -1,5 +1,8 @@
# -*- coding: utf-8 -*-
#
# flake8 documentation build configuration file, created by
# sphinx-quickstart on Tue Jan 19 07:14:10 2016.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
@ -12,29 +15,35 @@
import sys
import os
# This environment variable makes decorators not decorate functions, so their
# signatures in the generated documentation are still correct
os.environ['GENERATING_DOCUMENTATION'] = "flake8"
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
sys.path.insert(0, os.path.abspath('..'))
import flake8
#sys.path.insert(0, os.path.abspath('.'))
# -- General configuration ----------------------------------------------------
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
needs_sphinx = '1.3'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.autodoc']
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.doctest',
'sphinx.ext.intersphinx',
'sphinx.ext.todo',
'sphinx.ext.coverage',
'sphinx.ext.viewcode',
'sphinx-prompt',
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix of source filenames.
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'
# The encoding of source files.
@ -45,8 +54,10 @@ master_doc = 'index'
# General information about the project.
project = u'flake8'
copyright = u'2012-2013 - Tarek Ziade, Ian Cordasco, Florent Xicluna'
copyright = u'2016, Ian Cordasco'
author = u'Ian Cordasco'
import flake8
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
@ -54,11 +65,18 @@ copyright = u'2012-2013 - Tarek Ziade, Ian Cordasco, Florent Xicluna'
# The short X.Y version.
version = flake8.__version__
# The full version, including alpha/beta/rc tags.
release = version
release = flake8.__version__
rst_epilog = """
.. |Flake8| replace:: :program:`Flake8`
"""
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
@ -68,10 +86,10 @@ release = version
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']
exclude_patterns = []
# The reST default role (used for this markup: `text`) to use for
# all documents.
# The reST default role (used for this markup: `text`) to use for all
# documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
@ -86,17 +104,23 @@ exclude_patterns = ['_build']
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
# pygments_style = 'flask_theme_support.FlaskyStyle'
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# If true, keep warnings as "system message" paragraphs in the built documents.
#keep_warnings = False
# -- Options for HTML output --------------------------------------------------
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = True
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#html_theme = 'nature'
html_theme = 'sphinx_rtd_theme'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
@ -125,7 +149,12 @@ exclude_patterns = ['_build']
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
#html_static_path = ['_static']
# html_static_path = ['_static']
# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
# directly to the root of the documentation.
#html_extra_path = []
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
@ -152,10 +181,10 @@ exclude_patterns = ['_build']
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = False
#html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = False
#html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
@ -168,24 +197,45 @@ exclude_patterns = ['_build']
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# Language to be used for generating the HTML full-text search index.
# Sphinx supports the following languages:
# 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja'
# 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr'
#html_search_language = 'en'
# A dictionary with options for the search language support, empty by default.
# Now only 'ja' uses this config value
#html_search_options = {'type': 'default'}
# The name of a javascript file (relative to the configuration directory) that
# implements a search results scorer. If empty, the default will be used.
#html_search_scorer = 'scorer.js'
# Output file base name for HTML help builder.
htmlhelp_basename = 'flake8_doc'
htmlhelp_basename = 'flake8doc'
# -- Options for LaTeX output ---------------------------------------------
# -- Options for LaTeX output -------------------------------------------------
# The paper size ('letter' or 'a4').
#latex_paper_size = 'letter'
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#latex_font_size = '10pt'
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
# Latex figure (float) alignment
#'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto/manual]).
# author, documentclass [howto, manual, or own class]).
latex_documents = [
('index', 'flake8.tex', u'flake8 Documentation',
u'Tarek Ziade', 'manual'),
(master_doc, 'flake8.tex', u'flake8 Documentation',
u'Ian Cordasco', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
@ -202,9 +252,6 @@ latex_documents = [
# If true, show URL addresses after external links.
#latex_show_urls = False
# Additional stuff for the LaTeX preamble.
#latex_preamble = ''
# Documents to append as an appendix to all manuals.
#latex_appendices = []
@ -212,29 +259,42 @@ latex_documents = [
#latex_domain_indices = True
# -- Options for manual page output -------------------------------------------
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'flake8', u'flake8 Documentation',
[u'Tarek Ziade', u'Ian Cordasco', u'Florent Xicluna'], 1)
(master_doc, 'flake8', u'flake8 Documentation',
[author], 1)
]
# If true, show URL addresses after external links.
#man_show_urls = False
# -- Options for Texinfo output -----------------------------------------------
# -- Options for Texinfo output -------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
('index', 'flake8', u'flake8 Documentation', u'Tarek Ziade',
'flake8', 'Code checking using pycodestyle, pyflakes and mccabe',
('index', 'Flake8', u'Flake8 Documentation', u'Tarek Ziade',
'Flake8', 'Code checking using pycodestyle, pyflakes and mccabe',
'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.
texinfo_appendices = []
#texinfo_appendices = []
# If false, no module index is generated.
#texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'
# If true, do not generate a @detailmenu in the "Top" node's menu.
#texinfo_no_detailmenu = False
# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {'python': ('https://docs.python.org/3.4', None)}

56
docs/source/faq.rst Normal file
View file

@ -0,0 +1,56 @@
============================
Frequently Asked Questions
============================
When is Flake8 released?
========================
|Flake8| is released *as necessary*. Sometimes there are specific goals and
drives to get to a release. Usually, we release as users report and fix
bugs.
How can I help Flake8 release faster?
=====================================
Look at the next milestone. If there's work you can help us complete, that
will help us get to the next milestone. If there's a show-stopping bug that
needs to be released, let us know but please be kind. |Flake8| is developed
and released entirely on volunteer time.
What is the next version of Flake8?
===================================
In general we try to use milestones to indicate this. If the last release
on PyPI is 3.1.5 and you see a milestone for 3.2.0 in GitLab, there's a
good chance that 3.2.0 is the next release.
Why does Flake8 use ranges for its dependencies?
================================================
|Flake8| uses ranges for mccabe, pyflakes, and pycodestyle because each of
those projects tend to add *new* checks in minor releases. It has been an
implicit design goal of |Flake8|'s to make the list of error codes stable in
its own minor releases. That way if you install something from the 2.5
series today, you will not find new checks in the same series in a month
from now when you install it again.
|Flake8|'s dependencies tend to avoid new checks in patch versions which is
why |Flake8| expresses its dependencies roughly as::
pycodestyle >= 2.0.0, < 2.1.0
pyflakes >= 0.8.0, != 1.2.0, != 1.2.1, != 1.2.2, < 1.3.0
mccabe >= 0.5.0, < 0.6.0
This allows those projects to release patch versions that fix bugs and for
|Flake8| users to consume those fixes.
Should I file an issue when a new version of a dependency is available?
=======================================================================
**No.** The current Flake8 core team (of one person) is also
a core developer of pycodestyle, pyflakes, and mccabe. They are aware of
these releases.

56
docs/source/glossary.rst Normal file
View file

@ -0,0 +1,56 @@
.. _glossary:
================================================
Glossary of Terms Used in Flake8 Documentation
================================================
.. glossary::
:sorted:
formatter
A :term:`plugin` that augments the output of |Flake8| when passed
to :option:`flake8 --format`.
plugin
A package that is typically installed from PyPI to augment the
behaviour of |Flake8| either through adding one or more additional
:term:`check`\ s or providing additional :term:`formatter`\ s.
check
A piece of logic that corresponds to an error code. A check may
be a style check (e.g., check the length of a given line against
the user configured maximum) or a lint check (e.g., checking for
unused imports) or some other check as defined by a plugin.
error
error code
The symbol associated with a specific :term:`check`. For example,
pycodestyle implements :term:`check`\ s that look for whitespace
around binary operators and will either return an error code of
``W503`` or ``W504``.
warning
Typically the ``W`` class of :term:`error code`\ s from pycodestyle.
class
error class
A larger grouping of related :term:`error code`\ s. For example,
``W503`` and ``W504`` are two codes related to whitespace. ``W50``
would be the most specific class of codes relating to whitespace.
``W`` would be the warning class that subsumes all whitespace
errors.
pyflakes
The project |Flake8| depends on to lint files (check for unused
imports, variables, etc.). This uses the ``F`` :term:`class` of
:term:`error code`\ s reported by |Flake8|.
pycodestyle
The project |Flake8| depends on to provide style enforcement.
pycodestyle implements :term:`check`\ s for :pep:`8`. This uses the
``E`` and ``W`` :term:`class`\ es of :term:`error code`\ s.
mccabe
The project |Flake8| depends on to calculate the McCabe complexity
of a unit of code (e.g., a function). This uses the ``C``
:term:`class` of :term`error code`\ s.

131
docs/source/index.rst Normal file
View file

@ -0,0 +1,131 @@
.. flake8 documentation master file, created by
sphinx-quickstart on Tue Jan 19 07:14:10 2016.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
===============================================
Flake8: Your Tool For Style Guide Enforcement
===============================================
Quickstart
==========
.. _installation-guide:
Installation
------------
To install |Flake8|, open an interactive shell and run:
.. code::
python<version> -m pip install flake8
If you want |Flake8| to be installed for your default Python installation, you
can instead use:
.. code::
python -m pip install flake8
.. note::
It is **very** important to install |Flake8| on the *correct* version of
Python for your needs. If you want |Flake8| to properly parse new language
features in Python 3.5 (for example), you need it to be installed on 3.5
for |Flake8| to understand those features. In many ways, Flake8 is tied to
the version of Python on which it runs.
Using Flake8
------------
To start using |Flake8|, open an interactive shell and run:
.. code::
flake8 path/to/code/to/check.py
# or
flake8 path/to/code/
.. note::
If you have installed |Flake8| on a particular version of Python (or on
several versions), it may be best to instead run ``python<version> -m
flake8``.
If you only want to see the instances of a specific warning or error, you can
*select* that error like so:
.. code::
flake8 --select E123,W503 path/to/code/
Alternatively, if you want to *ignore* only one specific warning or error:
.. code::
flake8 --ignore E24,W504 path/to/code/
Please read our user guide for more information about how to use and configure
|Flake8|.
FAQ and Glossary
================
.. toctree::
:maxdepth: 2
faq
glossary
User Guide
==========
All users of |Flake8| should read this portion of the documentation. This
provides examples and documentation around |Flake8|'s assortment of options
and how to specify them on the command-line or in configuration files.
.. toctree::
:maxdepth: 2
user/index
Plugin Developer Guide
======================
If you're maintaining a plugin for |Flake8| or creating a new one, you should
read this section of the documentation. It explains how you can write your
plugins and distribute them to others.
.. toctree::
:maxdepth: 2
plugin-development/index
Contributor Guide
=================
If you are reading |Flake8|'s source code for fun or looking to contribute,
you should read this portion of the documentation. This is a mix of documenting
the internal-only interfaces |Flake8| and documenting reasoning for Flake8's
design.
.. toctree::
:maxdepth: 2
internal/index
Release Notes and History
=========================
.. toctree::
:maxdepth: 2
release-notes/index
General Indices
===============
* :ref:`genindex`
* :ref:`Index of Documented Public Modules <modindex>`
* :ref:`Glossary of terms <glossary>`

View file

View file

@ -0,0 +1,70 @@
====================
How Checks are Run
====================
In |Flake8| 2.x, |Flake8| delegated check running to pep8. In 3.0 |Flake8|
takes on that responsibility. This has allowed for simpler
handling of the ``--jobs`` parameter (using :mod:`multiprocessing`) and
simplified our fallback if something goes awry with concurency.
At the lowest level we have a |FileChecker|. Instances of |FileChecker| are
created for *each* file to be analyzed by |Flake8|. Each instance, has a copy
of all of the plugins registered with setuptools in the ``flake8.extension``
entry-point group.
The |FileChecker| instances are managed by an instance of |Manager|. The
|Manager| instance handles creating sub-processes with
:mod:`multiprocessing` module and falling back to running checks in serial if
an operating system level error arises. When creating |FileChecker| instances,
the |Manager| is responsible for determining if a particular file has been
excluded.
Processing Files
----------------
Unfortunately, since |Flake8| took over check running from pep8/pycodestyle,
it also had to take over parsing and processing files for the checkers
to use. Since it couldn't reuse pycodestyle's functionality (since it did not
separate cleanly the processing from check running) that function was isolated
into the :class:`~flake8.processor.FileProcessor` class. We moved
several helper functions into the :mod:`flake8.processor` module (see also
:ref:`Processor Utility Functions <processor_utility_functions>`).
API Reference
-------------
.. autoclass:: flake8.checker.FileChecker
:members:
.. autoclass:: flake8.checker.Manager
:members:
.. autoclass:: flake8.processor.FileProcessor
:members:
.. _processor_utility_functions:
Utility Functions
`````````````````
.. autofunction:: flake8.processor.count_parentheses
.. autofunction:: flake8.processor.expand_indent
.. autofunction:: flake8.processor.is_eol_token
.. autofunction:: flake8.processor.is_multiline_string
.. autofunction:: flake8.processor.log_token
.. autofunction:: flake8.processor.mutate_string
.. autofunction:: flake8.processor.token_is_comment
.. autofunction:: flake8.processor.token_is_newline
.. Substitutions
.. |FileChecker| replace:: :class:`~flake8.checker.FileChecker`
.. |Manager| replace:: :class:`~flake8.checker.Manager`

View file

@ -0,0 +1,26 @@
Command Line Interface
======================
The command line interface of |Flake8| is modeled as an application via
:class:`~flake8.main.cli.Application`. When a user runs ``flake8`` at their
command line, :func:`~flake8.main.cli.main` is run which handles
management of the application.
User input is parsed *twice* to accomodate logging and verbosity options
passed by the user as early as possible.
This is so as much logging can be produced as possible.
The default |Flake8| options are registered by
:func:`~flake8.main.options.register_default_options`. Trying to register
these options in plugins will result in errors.
API Documentation
-----------------
.. autofunction:: flake8.main.cli.main
.. autoclass:: flake8.main.application.Application
:members:
.. autofunction:: flake8.main.options.register_default_options

View file

@ -0,0 +1,202 @@
========================
Contributing to Flake8
========================
There are many ways to contriubte to |Flake8|, and we encourage them all:
- contributing bug reports and feature requests
- contributing documenation (and yes that includes this document)
- reviewing and triaging bugs and merge requests
Before you go any further, please allow me to reassure you that I do want
*your* contribution. If you think your contribution might not be valuable, I
reassure you that any help you can provide *is* valuable.
Code of Conduct
===============
|Flake8| adheres to the `Python Code Quality Authority's Code of Conduct`_.
Any violations of the Code of Conduct should be reported to Ian Cordasco
(graffatcolmingov [at] gmail [dot] com).
Setting Up A Development Environment
====================================
To contribute to |Flake8|'s development, you simply need:
- Python (one of the versions we support)
- `tox`_
We suggest installing this like:
.. prompt:: bash
pip install --user tox
Or
.. prompt:: bash
python<version> -m pip install --user tox
- your favorite editor
Filing a Bug
============
When filing a bug against |Flake8|, please fill out the issue template as it
is provided to you by `GitLab`_. If your bug is in reference to one of the
checks that |Flake8| reports by default, please do not report them to |Flake8|
unless |Flake8| is doing something to prevent the check from running or you
have some reason to believe |Flake8| is inhibiting the effectiveness of the
check.
**Please search for closed and open bug reports before opening new ones.**
All bug reports about checks should go to their respective projects:
- Error codes starting with ``E`` and ``W`` should be reported to
`pycodestyle`_.
- Error codes starting with ``F`` should be reported to `pyflakes`_
- Error codes starting with ``C`` should be reported to `mccabe`_
Requesting a New Feature
========================
When requesting a new feature in |Flake8|, please fill out the issue template.
Please also note if there are any existing alternatives to your new feature
either via plugins, or combining command-line options. Please provide example
use cases. For example, do not ask for a feature like this:
I need feature frobulate for my job.
Instead ask:
I need |Flake8| to frobulate these files because my team expects them to
frobulated but |Flake8| currently does not frobulate them. We tried using
``--filename`` but we could not create a pattern that worked.
The more you explain about *why* you need a feature, the more likely we are to
understand your needs and help you to the best of our ability.
Contributing Documentation
==========================
To contribute to |Flake8|'s documentation, you might want to first read a
little about reStructuredText or Sphinx. |Flake8| has a :ref:`guide of best
practices <docs-style>` when contributing to our documentation. For the most
part, you should be fine following the structure and style of the rest of
|Flake8|'s documentation.
All of |Flake8|'s documentation is written in reStructuredText and rendered by
Sphinx. The source (reStructuredText) lives in ``docs/source/``. To build
the documentation the way our Continuous Integration does, run:
.. prompt:: bash
tox -e docs
To view the documentation locally, you can also run:
.. prompt:: bash
tox -e serve-docs
You can run the latter in a separate terminal and continuously re-run the
documentation generation and refresh the documentation you're working on.
.. note::
We lint our documentation just like we lint our code.
You should also run:
.. prompt:: bash
tox -e linters
After making changes and before pushing them to ensure that they will
pass our CI tests.
Contributing Code
=================
|Flake8| development happens on `GitLab`_. Code contributions should be
submitted there.
Merge requests should:
- Fix one issue and fix it well
Fix the issue, but do not include extraneous refactoring or code
reformatting. In other words, keep the diff short, but only as short
as is necessary to fix the bug appropriately and add sufficient testing
around it. Long diffs are fine, so long as everything that it includes
is necessary to the purpose of the merge request.
- Have descriptive titles and descriptions
Searching old merge requests is made easier when a merge request is well
described.
- Have commits that follow this style:
.. code::
Create a short title that is 50 characters long
Ensure the title and commit message use the imperative voice. The
commit and you are doing something. Also, please ensure that the
body of the commit message does not exceed 72 characters.
The body may have multiple paragraphs as necessary.
The final line of the body references the issue appropriately.
Reviewing and Triaging Issues and Merge Requests
================================================
When reviewing other people's merge requests and issues, please be
**especially** mindful of how the words you choose can be read by someone
else. We strive for professional code reviews that do not insult the
contributor's intelligence or impugn their character. The code review
should be focused on the code, it's effectiveness, and whether it is
appropriate for |Flake8|.
If you have the ability to edit an issue or merge request's labels, please do
so to make search and prioritization easier.
|Flake8| uses milestones with both issues and merge requests. This provides
direction for other contributors about when an issue or merge request will be
delivered.
.. links
.. _Python Code Quality Authority's Code of Conduct:
http://meta.pycqa.org/en/latest/code-of-conduct.html
.. _tox:
https://tox.readthedocs.io/
.. _GitLab:
https://gitlab.com/pycqa/flake8
.. _pycodestyle:
https://github.com/pycqa/pycodestyle
.. _pyflakes:
https://github.com/pyflakes/pyflakes
.. _mccabe:
https://github.com/pycqa/mccabe

View file

@ -0,0 +1,47 @@
=====================
Built-in Formatters
=====================
By default |Flake8| has two formatters built-in, ``default`` and ``pylint``.
These correspond to two classes |DefaultFormatter| and |PylintFormatter|.
In |Flake8| 2.0, pep8 handled formatting of errors and also allowed users to
specify an arbitrary format string as a parameter to ``--format``. In order
to allow for this backwards compatibility, |Flake8| 3.0 made two choices:
#. To not limit a user's choices for ``--format`` to the format class names
#. To make the default formatter attempt to use the string provided by the
user if it cannot find a formatter with that name.
Default Formatter
=================
The |DefaultFormatter| continues to use the same default format string as
pep8: ``'%(path)s:%(row)d:%(col)d: %(code)s %(text)s'``.
To provide the default functionality it overrides two methods:
#. ``after_init``
#. ``format``
The former allows us to inspect the value provided to ``--format`` by the
user and alter our own format based on that value. The second simply uses
that format string to format the error.
.. autoclass:: flake8.formatting.default.Default
:members:
Pylint Formatter
================
The |PylintFormatter| simply defines the default Pylint format string from
pep8: ``'%(path)s:%(row)d: [%(code)s] %(text)s'``.
.. autoclass:: flake8.formatting.default.Pylint
:members:
.. |DefaultFormatter| replace:: :class:`~flake8.formatting.default.Default`
.. |PylintFormatter| replace:: :class:`~flake8.formatting.default.Pylint`

View file

@ -0,0 +1,26 @@
==============================
Exploring Flake8's Internals
==============================
While writing |Flake8| 3.0, the developers attempted to capture some reasoning
and decision information in internal documentation meant for future developers
and maintaners. Most of this information is unnecessary for users and plugin
developers. Some of it, however, is linked to from the plugin development
documentation.
Keep in mind that not everything will be here and you may need to help pull
information out of the developers' heads and into these documents. Please
pull gently.
.. toctree::
:maxdepth: 2
contributing
writing-documentation
releases
checker
cli
formatters
option_handling
plugin_handling
utils

View file

@ -0,0 +1,234 @@
Option and Configuration Handling
=================================
Option Management
-----------------
Command-line options are often also set in configuration files for |Flake8|.
While not all options are meant to be parsed from configuration files, many
default options are also parsed from configuration files as well as
most plugin options.
In |Flake8| 2, plugins received a :class:`optparse.OptionParser` instance and
called :meth:`optparse.OptionParser.add_option` to register options. If the
plugin author also wanted to have that option parsed from config files they
also had to do something like:
.. code-block:: python
parser.config_options.append('my_config_option')
parser.config_options.extend(['config_opt1', 'config_opt2'])
This was previously undocumented and led to a lot of confusion about why
registered options were not automatically parsed from configuration files.
Since |Flake8| 3 was rewritten from scratch, we decided to take a different
approach to configuration file parsing. Instead of needing to know about an
undocumented attribute that pep8 looks for, |Flake8| 3 now accepts a parameter
to ``add_option``, specifically ``parse_from_config`` which is a boolean
value.
|Flake8| does this by creating its own abstractions on top of :mod:`optparse`.
The first abstraction is the :class:`flake8.options.manager.Option` class. The
second is the :class:`flake8.options.manager.OptionManager`. In fact, we add
three new parameters:
- ``parse_from_config``
- ``comma_separated_list``
- ``normalize_paths``
The last two are not specifically for configuration file handling, but they
do improve that dramatically. We found that there were options that, when
specified in a configuration file, often necessitated being spit
multiple lines and those options were almost always comma-separated. For
example, let's consider a user's list of ignored error codes for a project:
.. code-block:: ini
[flake8]
ignore =
# Reasoning
E111,
# Reasoning
E711,
# Reasoning
E712,
# Reasoning
E121,
# Reasoning
E122,
# Reasoning
E123,
# Reasoning
E131,
# Reasoning
E251
It makes sense here to allow users to specify the value this way, but, the
standard libary's :class:`configparser.RawConfigParser` class does returns a
string that looks like
.. code-block:: python
"\nE111, \nE711, \nE712, \nE121, \nE122, \nE123, \nE131, \nE251 "
This means that a typical call to :meth:`str.split` with ``','`` will not be
sufficient here. Telling |Flake8| that something is a comma-separated list
(e.g., ``comma_separated_list=True``) will handle this for you. |Flake8| will
return:
.. code-block:: python
["E111", "E711", "E712", "E121", "E122", "E123", "E131", "E251"]
Next let's look at how users might like to specify their ``exclude`` list.
Presently OpenStack's Nova project has this line in their `tox.ini`_:
.. code-block:: ini
exclude = .venv,.git,.tox,dist,doc,*openstack/common/*,*lib/python*,*egg,build,tools/xenserver*,releasenotes
We think we can all agree that this would be easier to read like this:
.. code-block:: ini
exclude =
.venv,
.git,
.tox,
dist,
doc,
*openstack/common/*,
*lib/python*,
*egg,
build,
tools/xenserver*,
releasenotes
In this case, since these are actually intended to be paths, we would specify
both ``comma_separated_list=True`` and ``normalize_paths=True`` because we
want the paths to be provided to us with some consistency (either all absolute
paths or not).
Now let's look at how this will actually be used. Most plugin developers
will receive an instance of :class:`~flake8.options.manager.OptionManager` so
to ease the transition we kept the same API as the
:class:`optparse.OptionParser` object. The only difference is that
:meth:`~flake8.options.manager.OptionManager.add_option` accepts the three
extra arguments we highlighted above.
.. _tox.ini:
https://github.com/openstack/nova/blob/3eb190c4cfc0eefddac6c2cc1b94a699fb1687f8/tox.ini#L155
Configuration File Management
-----------------------------
In |Flake8| 2, configuration file discovery and management was handled by
pep8. In pep8's 1.6 release series, it drastically broke how discovery and
merging worked (as a result of trying to improve it). To avoid a dependency
breaking |Flake8| again in the future, we have created our own discovery and
management.
As part of managing this ourselves, we decided to change management/discovery
for 3.0.0. We have done the following:
- User files (files stored in a user's home directory or in the XDG directory
inside their home directory) are the first files read. For example, if the
user has a ``~/.flake8`` file, we will read that first.
- Project files (files stored in the current directory) are read next and
merged on top of the user file. In other words, configuration in project
files takes precedence over configuration in user files.
- **New in 3.0.0** The user can specify ``--append-config <path-to-file>``
repeatedly to include extra configuration files that should be read and
take precedence over user and project files.
- **New in 3.0.0** The user can specify ``--config <path-to-file>`` to so this
file is the only configuration file used. This is a change from |Flake8| 2
where pep8 would simply merge this configuration file into the configuration
generated by user and project files (where this takes precedence).
- **New in 3.0.0** The user can specify ``--isolated`` to disable
configuration via discovered configuration files.
To facilitate the configuration file management, we've taken a different
approach to discovery and management of files than pep8. In pep8 1.5, 1.6, and
1.7 configuration discovery and management was centralized in `66 lines of
very terse python`_ which was confusing and not very explicit. The terseness
of this function (|Flake8|'s authors believe) caused the confusion and
problems with pep8's 1.6 series. As such, |Flake8| has separated out
discovery, management, and merging into a module to make reasoning about each
of these pieces easier and more explicit (as well as easier to test).
Configuration file discovery is managed by the
:class:`~flake8.options.config.ConfigFileFinder` object. This object needs to
know information about the program's name, any extra arguments passed to it,
and any configuration files that should be appended to the list of discovered
files. It provides methods for finding the files and similiar methods for
parsing those fles. For example, it provides
:meth:`~flake8.options.config.ConfigFileFinder.local_config_files` to find
known local config files (and append the extra configuration files) and it
also provides :meth:`~flake8.options.config.ConfigFileFinder.local_configs`
to parse those configuration files.
.. note:: ``local_config_files`` also filters out non-existent files.
Configuration file merging and managemnt is controlled by the
:class:`~flake8.options.config.MergedConfigParser`. This requires the instance
of :class:`~flake8.options.manager.OptionManager` that the program is using,
the list of appended config files, and the list of extra arguments. This
object is currently the sole user of the
:class:`~flake8.options.config.ConfigFileFinder` object. It appropriately
initializes the object and uses it in each of
- :meth:`~flake8.options.config.MergedConfigParser.parse_cli_config`
- :meth:`~flake8.options.config.MergedConfigParser.parse_local_config`
- :meth:`~flake8.options.config.MergedConfigParser.parse_user_config`
Finally,
:meth:`~flake8.options.config.MergedConfigParser.merge_user_and_local_config`
takes the user and local configuration files that are parsed by
:meth:`~flake8.options.config.MergedConfigParser.parse_local_config` and
:meth:`~flake8.options.config.MergedConfigParser.parse_user_config`. The
main usage of the ``MergedConfigParser`` is in
:func:`~flake8.options.aggregator.aggregate_options`.
Aggregating Configuration File and Command Line Arguments
---------------------------------------------------------
:func:`~flake8.options.aggregator.aggregate_options` accepts an instance of
:class:`~flake8.options.maanger.OptionManager` and does the work to parse the
command-line arguments passed by the user necessary for creating an instance
of :class:`~flake8.options.config.MergedConfigParser`.
After parsing the configuration file, we determine the default ignore list. We
use the defaults from the OptionManager and update those with the parsed
configuration files. Finally we parse the user-provided options one last time
using the option defaults and configuration file values as defaults. The
parser merges on the command-line specified arguments for us so we have our
final, definitive, aggregated options.
.. _66 lines of very terse python:
https://github.com/PyCQA/pep8/blob/b8088a2b6bc5b76bece174efad877f764529bc74/pep8.py#L1981..L2047
API Documentation
-----------------
.. autofunction:: flake8.options.aggregator.aggregate_options
.. autoclass:: flake8.options.manager.Option
:members: __init__, normalize, to_optparse
.. autoclass:: flake8.options.manager.OptionManager
:members:
:special-members:
.. autoclass:: flake8.options.config.ConfigFileFinder
:members:
:special-members:
.. autoclass:: flake8.options.config.MergedConfigParser
:members:
:special-members:

View file

@ -0,0 +1,129 @@
Plugin Handling
===============
Plugin Management
-----------------
|Flake8| 3.0 added support for two other plugins besides those which define
new checks. It now supports:
- extra checks
- alternative report formatters
- listeners to auto-correct violations of checks
To facilitate this, |Flake8| needed a more mature way of managing plugins.
Thus, we developed the |PluginManager| which accepts a namespace and will load
the plugins for that namespace. A |PluginManager| creates and manages many
|Plugin| instances.
A |Plugin| lazily loads the underlying entry-point provided by setuptools.
The entry-point will be loaded either by calling
:meth:`~flake8.plugins.manager.Plugin.load_plugin` or accessing the ``plugin``
attribute. We also use this abstraction to retrieve options that the plugin
wishes to register and parse.
The only public method the |PluginManager| provides is
:meth:`~flake8.plugins.manager.PluginManager.map`. This will accept a function
(or other callable) and call it with each plugin as the first parameter.
We build atop the |PluginManager| with the |PTM|. It is expected that users of
the |PTM| will subclass it and specify the ``namespace``, e.g.,
.. code-block:: python
class ExamplePluginType(flake8.plugin.manager.PluginTypeManager):
namespace = 'example-plugins'
This provides a few extra methods via the |PluginManager|'s ``map`` method.
Finally, we create three classes of plugins:
- :class:`~flake8.plugins.manager.Checkers`
- :class:`~flake8.plugins.manager.Listeners`
- :class:`~flake8.plugins.manager.ReportFormatters`
These are used to interact with each of the types of plugins individually.
.. note::
Our inspiration for our plugin handling comes from the author's extensive
experience with ``stevedore``.
Notifying Listener Plugins
--------------------------
One of the interesting challenges with allowing plugins to be notified each
time an error or warning is emitted by a checker is finding listeners quickly
and efficiently. It makes sense to allow a listener to listen for a certain
class of warnings or just a specific warning. Hence, we need to allow all
plugins that listen to a specific warning or class to be notified. For
example, someone might register a listener for ``E1`` and another for ``E111``
if ``E111`` is triggered by the code, both listeners should be notified.
If ``E112`` is returned, then only ``E1`` (and any other listeners) would be
notified.
To implement this goal, we needed an object to store listeners in that would
allow for efficient look up - a Trie (or Prefix Tree). Given that none of the
existing packages on PyPI allowed for storing data on each node of the trie,
it was left up to write our own as :class:`~flake8.plugins._trie.Trie`. On
top of that we layer our :class:`~flake8.plugins.notifier.Notifier` class.
Now when |Flake8| receives an error or warning, we can easily call the
:meth:`~flake8.plugins.notifier.Notifier.notify` method and let plugins act on
that knowledge.
Default Plugins
---------------
Finally, |Flake8| has always provided its own plugin shim for Pyflakes. As
part of that we carry our own shim in-tree and now store that in
:mod:`flake8.plugins.pyflakes`.
|Flake8| also registers plugins for pep8. Each check in pep8 requires
different parameters and it cannot easily be shimmed together like Pyflakes
was. As such, plugins have a concept of a "group". If you look at our
:file:`setup.py` you will see that we register pep8 checks roughly like so:
.. code::
pep8.<check-name> = pep8:<check-name>
We do this to identify that ``<check-name>>`` is part of a group. This also
enables us to special-case how we handle reporting those checks. Instead of
reporting each check in the ``--version`` output, we report ``pep8`` and check
``pep8`` the module for a ``__version__`` attribute. We only report it once
to avoid confusing users.
API Documentation
-----------------
.. autoclass:: flake8.plugins.manager.PluginManager
:members:
:special-members: __init__, __contains__, __getitem__
.. autoclass:: flake8.plugins.manager.Plugin
:members:
:special-members: __init__
.. autoclass:: flake8.plugins.manager.PluginTypeManager
:members:
.. autoclass:: flake8.plugins.manager.Checkers
:members:
.. autoclass:: flake8.plugins.manager.Listeners
:members: build_notifier
.. autoclass:: flake8.plugins.manager.ReportFormatters
.. autoclass:: flake8.plugins.notifier.Notifier
.. autoclass:: flake8.plugins._trie.Trie
.. |PluginManager| replace:: :class:`~flake8.plugins.manager.PluginManager`
.. |Plugin| replace:: :class:`~flake8.plugins.manager.Plugin`
.. |PTM| replace:: :class:`~flake8.plugins.manager.PluginTypeManager`

View file

@ -0,0 +1,99 @@
==================
Releasing Flake8
==================
There is not much that is hard to find about how |Flake8| is released.
- We use **major** releases (e.g., 2.0.0, 3.0.0, etc.) for big, potentially
backwards incompatible, releases.
- We use **minor** releases (e.g., 2.1.0, 2.2.0, 3.1.0, 3.2.0, etc.) for
releases that contain features and dependency version changes.
- We use **patch** releases (e.g., 2.1.1, 2.1.2, 3.0.1, 3.0.10, etc.) for
releases that contain *only* bug fixes.
In this sense we follow semantic versioning. But we follow it as more of a set
of guidelines. We're also not perfect, so we may make mistakes, and that's
fine.
Major Releases
==============
Major releases are often associated with backwards incompatibility. |Flake8|
hopes to avoid those, but will occasionally need them.
Historically, |Flake8| has generated major releases for:
- Unvendoring dependencies (2.0)
- Large scale refactoring (2.0, 3.0)
- Subtly breaking CLI changes (3.0)
- Breaking changes to its plugin interface (3.0)
Major releases can also contain:
- Bug fixes (which may have backwards incompatible solutions)
- New features
- Dependency changes
Minor Releases
==============
Minor releases often have new features in them, which we define roughly as:
- New command-line flags
- New behaviour that does not break backwards compatibility
- New errors detected by dependencies, e.g., by raising the upper limit on
PyFlakes we introduce F405
- Bug fixes
Patch Releases
==============
Patch releases should only ever have bug fixes in them.
We do not update dependency constraints in patch releases. If you do not
install |Flake8| from PyPI, there is a chance that your packager is using
different requirements. Some downstream redistributors have been known to
force a new version of PyFlakes, pep8/PyCodestyle, or McCabe into place.
Occasionally this will cause breakage when using |Flake8|. There is little
we can do to help you in those cases.
Process
=======
To prepare a release, we create a file in :file:`docs/source/releases/` named:
``{{ release_number }}.rst`` (e.g., ``3.0.0.rst``). We note bug fixes,
improvements, and dependency version changes as well as other items of note
for users.
Before releasing, the following tox test environments must pass:
- Python 2.7 (a.k.a., ``tox -e py27``)
- Python 3.4 (a.k.a., ``tox -e py34``)
- Python 3.5 (a.k.a., ``tox -e py35``)
- PyPy (a.k.a., ``tox -e pypy``)
- Linters (a.k.a., ``tox -e linters``)
We tag the most recent commit that passes those items and contains our release
notes.
Finally, we run ``tox -e release`` to build source distributions (e.g.,
``flake8-3.0.0.tar.gz``), universal wheels, and upload them to PyPI with
Twine.

View file

@ -0,0 +1,127 @@
===================
Utility Functions
===================
|Flake8| has a few utility functions that it uses internally.
.. warning::
As should be implied by where these are documented, these are all
**internal** utility functions. Their signatures and return types
may change between releases without notice.
Bugs reported about these **internal** functions will be closed
immediately.
If functions are needed by plugin developers, they may be requested
in the bug tracker and after careful consideration they *may* be added
to the *documented* stable API.
.. autofunction:: flake8.utils.parse_comma_separated_list
:func:`~flake8.utils.parse_comma_separated_list` takes either a string like
.. code-block:: python
"E121,W123,F904"
"E121,\nW123,\nF804"
"E121,\n\tW123,\n\tF804"
Or it will take a list of strings (potentially with whitespace) such as
.. code-block:: python
[" E121\n", "\t\nW123 ", "\n\tF904\n "]
And converts it to a list that looks as follows
.. code-block:: python
["E121", "W123", "F904"]
This function helps normalize any kind of comma-separated input you or |Flake8|
might receive. This is most helpful when taking advantage of |Flake8|'s
additional parameters to :class:`~flake8.options.manager.Option`.
.. autofunction:: flake8.utils.normalize_path
This utility takes a string that represents a path and returns the absolute
path if the string has a ``/`` in it. It also removes trailing ``/``\ s.
.. autofunction:: flake8.utils.normalize_paths
This function utilizes :func:`~flake8.utils.parse_comma_separated_list` and
:func:`~flake8.utils.normalize_path` to normalize it's input to a list of
strings that should be paths.
.. autofunction:: flake8.utils.stdin_get_value
This function retrieves and caches the value provided on ``sys.stdin``. This
allows plugins to use this to retrieve ``stdin`` if necessary.
.. autofunction:: flake8.utils.is_windows
This provides a convenient and explicitly named function that checks if we are
currently running on a Windows (or ``nt``) operating system.
.. autofunction:: flake8.utils.can_run_multiprocessing_on_windows
This provides a separate and distinct check from
:func:`~flake8.utils.is_windows` that allows us to check if the version of
Python we're using can actually use multiprocessing on Windows.
.. autofunction:: flake8.utils.is_using_stdin
Another helpful function that is named only to be explicit given it is a very
trivial check, this checks if the user specified ``-`` in their arguments to
|Flake8| to indicate we should read from stdin.
.. autofunction:: flake8.utils.filenames_from
When provided an argument to |Flake8|, we need to be able to traverse
directories in a convenient manner. For example, if someone runs
.. code::
$ flake8 flake8/
Then they want us to check all of the files in the directory ``flake8/``. This
function will handle that while also handling the case where they specify a
file like:
.. code::
$ flake8 flake8/__init__.py
.. autofunction:: flake8.utils.fnmatch
The standard library's :func:`fnmatch.fnmatch` is excellent at deciding if a
filename matches a single pattern. In our use case, however, we typically have
a list of patterns and want to know if the filename matches any of them. This
function abstracts that logic away with a little extra logic.
.. autofunction:: flake8.utils.parameters_for
|Flake8| analyzes the parameters to plugins to determine what input they are
expecting. Plugins may expect one of the following:
- ``physical_line`` to receive the line as it appears in the file
- ``logical_line`` to receive the logical line (not as it appears in the file)
- ``tree`` to receive the abstract syntax tree (AST) for the file
We also analyze the rest of the parameters to provide more detail to the
plugin. This function will return the parameters in a consistent way across
versions of Python and will handle both classes and functions that are used as
plugins. Further, if the plugin is a class, it will strip the ``self``
argument so we can check the parameters of the plugin consistently.
.. autofunction:: flake8.utils.parse_unified_diff
To handle usage of :option:`flake8 --diff`, |Flake8| needs to be able
to parse the name of the files in the diff as well as the ranges indicated the
sections that have been changed. This function either accepts the diff as an
argument or reads the diff from standard-in. It then returns a dictionary with
filenames as the keys and sets of line numbers as the value.

View file

@ -0,0 +1,183 @@
.. _docs-style:
==================================
Writing Documentation for Flake8
==================================
The maintainers of |Flake8| believe strongly in benefit of style guides.
Hence, for all contributors who wish to work on our documentation, we've
put together a loose set of guidelines and best practices when adding to
our documentation.
View the docs locally before submitting
=======================================
You can and should generate the docs locally before you submit a pull request
with your changes. You can build the docs by running:
.. prompt:: bash
tox -e docs
From the directory containing the ``tox.ini`` file (which also contains the
``docs/`` directory that this file lives in).
.. note::
If the docs don't build locally, they will not build in our continuous
integration system. We will generally not merge any pull request that
fails continuous integration.
Run the docs linter tests before submitting
===========================================
You should run the ``doc8`` linter job before you're ready to commit and fix
any errors found.
Capitalize Flake8 in prose
==========================
We believe that by capitalizing |Flake8| in prose, we can help reduce
confusion between the command-line usage of ``flake8`` and the project.
We also have defined a global replacement ``|Flake8|`` that should be used
and will replace each instance with ``:program:`Flake8```.
Use the prompt directive for command-line examples
==================================================
When documenting something on the command-line, use the ``.. prompt::``
directive to make it easier for users to copy and paste into their terminal.
Example:
.. code-block:: restructuredtext
.. prompt:: bash
flake8 --select E123,W503 dir/
flake8 --ignore E24,W504 dir
Wrap lines around 79 characters
===============================
We use a maximum line-length in our documentation that is similar to the
default in |Flake8|. Please wrap lines at 79 characters (or less).
Use two new-lines before new sections
=====================================
After the final paragraph of a section and before the next section title,
use two new-lines to separate them. This makes reading the plain-text
document a little nicer. Sphinx ignores these when rendering so they have
no semantic meaning.
Example:
.. code-block:: restructuredtext
Section Header
==============
Paragraph.
Next Section Header
===================
Paragraph.
Surround document titles with equal symbols
===========================================
To indicate the title of a document, we place an equal number of ``=`` symbols
on the lines before and after the title. For example:
.. code-block:: restructuredtext
==================================
Writing Documentation for Flake8
==================================
Note also that we "center" the title by adding a leading space and having
extra ``=`` symbols at the end of those lines.
Use the option template for new options
=======================================
All of |Flake8|'s command-line options are documented in the User Guide. Each
option is documented individually using the ``.. option::`` directive provided
by Sphinx. At the top of the document, in a reStructuredText comment, is a
template that should be copied and pasted into place when documening new
options.
.. note::
The ordering of the options page is the order that options are printed
in the output of:
.. prompt:: bash
flake8 --help
Please insert your option documentation according to that order.
Use anchors for easy reference linking
======================================
Use link anchors to allow for other areas of the documentation to use the
``:ref:`` role for intralinking documentation. Example:
.. code-block:: restructuredtext
.. _use-anchors:
Use anchors for easy reference linking
======================================
.. code-block:: restructuredtext
Somewhere in this paragraph we will :ref:`reference anchors
<use-anchors>`.
.. note::
You do not need to provide custom text for the ``:ref:`` if the title of
the section has a title that is sufficient.
Keep your audience in mind
==========================
|Flake8|'s documentation has three distinct (but not separate) audiences:
#. Users
#. Plugin Developers
#. Flake8 Developers and Contributors
At the moment, you're one of the third group (because you're contributing
or thinking of contributing).
Consider that most Users aren't very interested in the internal working of
|Flake8|. When writing for Users, focus on how to do something or the
behaviour of a certain piece of configuration or invocation.
Plugin developers will only care about the internals of |Flake8| as much as
they will have to interact with that. Keep discussions of internal to the
mininmum required.
Finally, Flake8 Developers and Contributors need to know how everything fits
together. We don't need detail about every line of code, but cogent
explanations and design specifications will help future developers understand
the Hows and Whys of |Flake8|'s internal design.

View file

View file

@ -0,0 +1,150 @@
====================================
Writing Plugins For Flake8 2 and 3
====================================
Plugins have existed for |Flake8| 2.x for a few years. There are a number of
these on PyPI already. While it did not seem reasonable for |Flake8| to attempt
to provide a backwards compatible shim for them, we did decide to try to
document the easiest way to write a plugin that's compatible across both
versions.
.. note::
If your plugin does not register options, it *should* Just Work.
The **only** breaking change in |Flake8| 3.0 is the fact that we no longer
check the option parser for a list of strings to parse from a config file. On
|Flake8| 2.x, to have an option parsed from the configuration files that
|Flake8| finds and parses you would have to do something like:
.. code-block:: python
parser.add_option('-X', '--example-flag', type='string',
help='...')
parser.config_options.append('example-flag')
For |Flake8| 3.0, we have added *three* arguments to the
:meth:`~flake8.options.manager.OptionManager.add_option` method you will call
on the parser you receive:
- ``parse_from_config`` which expects ``True`` or ``False``
When ``True``, |Flake8| will parse the option from the config files |Flake8|
finds.
- ``comma_separated_list`` which expects ``True`` or ``False``
When ``True``, |Flake8| will split the string intelligently and handle
extra whitespace. The parsed value will be a list.
- ``normalize_paths`` which expects ``True`` or ``False``
When ``True``, |Flake8| will:
* remove trailing path separators (i.e., ``os.path.sep``)
* return the absolute path for values that have the separator in them
All three of these options can be combined or used separately.
Parsing Options from Configuration Files
========================================
The example from |Flake8| 2.x now looks like:
.. code-block:: python
parser.add_option('-X', '--example-flag', type='string',
parse_from_config=True,
help='...')
Parsing Comma-Separated Lists
=============================
Now let's imagine that the option we want to add is expecting a comma-separatd
list of values from the user (e.g., ``--select E123,W503,F405``). |Flake8| 2.x
often forced users to parse these lists themselves since pep8 special-cased
certain flags and left others on their own. |Flake8| 3.0 adds
``comma_separated_list`` so that the parsed option is already a list for
plugin authors. When combined with ``parse_from_config`` this means that users
can also do something like:
.. code-block:: ini
example-flag =
first,
second,
third,
fourth,
fifth
And |Flake8| will just return the list:
.. code-block:: python
["first", "second", "third", "fourth", "fifth"]
Normalizing Values that Are Paths
=================================
Finally, let's imagine that our new option wants a path or list of paths. To
ensure that these paths are semi-normalized (the way |Flake8| 2.x used to
work) we need only pass ``normalize_paths=True``. If you have specified
``comma_separated_list=True`` then this will parse the value as a list of
paths that have been normalized. Otherwise, this will parse the value
as a single path.
Option Handling on Flake8 2 and 3
=================================
So, in conclusion, we can now write our plugin that relies on registering
options with |Flake8| and have it work on |Flake8| 2.x and 3.x.
.. code-block:: python
option_args = ('-X', '--example-flag')
option_kwargs = {
'type': 'string',
'parse_from_config': True,
'help': '...',
}
try:
# Flake8 3.x registration
parser.add_option(*option_args, **option_kwargs)
except TypeError:
# Flake8 2.x registration
parse_from_config = option_kwargs.pop('parse_from_config', False)
parser.add_option(*option_args, **option_kwargs)
if parse_from_config:
parser.config_options.append(option_args[-1].lstrip('-'))
Or, you can write a tiny helper function:
.. code-block:: python
def register_opt(parser, *args, **kwargs):
try:
# Flake8 3.x registration
parser.add_option(*args, **kwargs)
except TypeError:
# Flake8 2.x registration
parse_from_config = kwargs.pop('parse_from_config', False)
parser.add_option(*args, **kwargs)
if parse_from_config:
parser.config_options.append(args[-1].lstrip('-'))
.. code-block:: python
@classmethod
def register_options(cls, parser):
register_opt(parser, '-X', '--example-flag', type='string',
parse_from_config=True, help='...')
The transition period is admittedly not fantastic, but we believe that this
is a worthwhile change for plugin developers going forward. We also hope to
help with the transition phase for as many plugins as we can manage.

View file

@ -0,0 +1,54 @@
.. _formatting-plugins:
===========================================
Developing a Formatting Plugin for Flake8
===========================================
|Flake8| allowed for custom formatting plugins in version
3.0.0. Let's write a plugin together:
.. code-block:: python
from flake8.formatting import base
class Example(base.BaseFormatter):
"""Flake8's example formatter."""
pass
We notice, as soon as we start, that we inherit from |Flake8|'s
:class:`~flake8.formatting.base.BaseFormatter` class. If we follow the
:ref:`instructions to register a plugin <register-a-plugin>` and try to use
our example formatter, e.g., ``flake8 --format=example`` then
|Flake8| will fail because we did not implement the ``format`` method.
Let's do that next.
.. code-block:: python
class Example(base.BaseFormatter):
"""Flake8's example formatter."""
def format(self, error):
return 'Example formatter: {0!r}'.format(error)
With that we're done. Obviously this isn't a very useful formatter, but it
should highlight the simplicitly of creating a formatter with Flake8. If we
wanted to instead create a formatter that aggregated the results and returned
XML, JSON, or subunit we could also do that. |Flake8| interacts with the
formatter in two ways:
#. It creates the formatter and provides it the options parsed from the
configuration files and command-line
#. It uses the instance of the formatter and calls ``handle`` with the error.
By default :meth:`flake8.formatting.base.BaseFormatter.handle` simply calls
the ``format`` method and then ``write``. Any extra handling you wish to do
for formatting purposes should override the ``handle`` method.
API Documentation
=================
.. autoclass:: flake8.formatting.base.BaseFormatter
:members:

View file

@ -0,0 +1,56 @@
============================
Writing Plugins for Flake8
============================
Since |Flake8| 2.0, the |Flake8| tool has allowed for extensions and custom
plugins. In |Flake8| 3.0, we're expanding that ability to customize and
extend **and** we're attempting to thoroughly document it. Some of the
documentation in this section may reference third-party documentation to
reduce duplication and to point you, the developer, towards the authoritative
documentation for those pieces.
Getting Started
===============
To get started writing a |Flake8| :term:`plugin` you first need:
- An idea for a plugin
- An available package name on PyPI
- One or more versions of Python installed
- A text editor or IDE of some kind
- An idea of what *kind* of plugin you want to build:
* Formatter
* Check
Once you've gathered these things, you can get started.
All plugins for |Flake8| must be registered via `entry points`_. In this
section we cover:
- How to register your plugin so |Flake8| can find it
- How to make |Flake8| provide your check plugin with information (via
command-line flags, function/class parameters, etc.)
- How to make a formatter plugin
- How to write your check plugin so that it works with |Flake8| 2.x and 3.x
.. toctree::
:caption: Plugin Developer Documentation
:maxdepth: 2
registering-plugins
plugin-parameters
formatters
cross-compatibility
.. _entry points:
https://setuptools.readthedocs.io/en/latest/pkg_resources.html#entry-points

View file

@ -0,0 +1,163 @@
.. _plugin-parameters:
==========================================
Receiving Information For A Check Plugin
==========================================
Plugins to |Flake8| have a great deal of information that they can request
from a :class:`~flake8.processor.FileProcessor` instance. Historically,
|Flake8| has supported two types of plugins:
#. classes that accept parsed abstract syntax trees (ASTs)
#. functions that accept a range of arguments
|Flake8| now does not distinguish between the two types of plugins. Any plugin
can accept either an AST or a range of arguments. Further, any plugin that has
certain callable attributes can also register options and receive parsed
options.
Indicating Desired Data
=======================
|Flake8| inspects the plugin's signature to determine what parameters it
expects using :func:`flake8.utils.parameters_for`.
:attr:`flake8.plugins.manager.Plugin.parameters` caches the values so that
each plugin makes that fairly expensive call once per plugin. When processing
a file, a plugin can ask for any of the following:
- :attr:`~flake8.processor.FileProcessor.blank_before`
- :attr:`~flake8.processor.FileProcessor.blank_lines`
- :attr:`~flake8.processor.FileProcessor.checker_state`
- :attr:`~flake8.processor.FileProcessor.indect_char`
- :attr:`~flake8.processor.FileProcessor.indent_level`
- :attr:`~flake8.processor.FileProcessor.line_number`
- :attr:`~flake8.processor.FileProcessor.logical_line`
- :attr:`~flake8.processor.FileProcessor.max_line_length`
- :attr:`~flake8.processor.FileProcessor.multiline`
- :attr:`~flake8.processor.FileProcessor.noqa`
- :attr:`~flake8.processor.FileProcessor.previous_indent_level`
- :attr:`~flake8.processor.FileProcessor.previous_logical`
- :attr:`~flake8.processor.FileProcessor.tokens`
- :attr:`~flake8.processor.FileProcessor.total_lines`
- :attr:`~flake8.processor.FileProcessor.verbose`
Alternatively, a plugin can accept ``tree`` and ``filename``.
``tree`` will be a parsed abstract syntax tree that will be used by plugins
like PyFlakes and McCabe.
Registering Options
===================
Any plugin that has callable attributes ``provide_options`` and
``register_options`` can parse option information and register new options.
Your ``register_options`` function should expect to receive an instance of
|OptionManager|. An |OptionManager| instance behaves very similarly to
:class:`optparse.OptionParser`. It, however, uses the layer that |Flake8| has
developed on top of :mod:`optparse` to also handle configuration file parsing.
:meth:`~flake8.options.manager.OptionManager.add_option` creates an |Option|
which accepts the same parameters as :mod:`optparse` as well as three extra
boolean parameters:
- ``parse_from_config``
The command-line option should also be parsed from config files discovered
by |Flake8|.
.. note::
This takes the place of appending strings to a list on the
:class:`optparse.OptionParser`.
- ``comma_separated_list``
The value provided to this option is a comma-separated list. After parsing
the value, it should be further broken up into a list. This also allows us
to handle values like:
.. code::
E123,E124,
E125,
E126
- ``normalize_paths``
The value provided to this option is a path. It should be normalized to be
an absolute path. This can be combined with ``comma_separated_list`` to
allow a comma-separated list of paths.
Each of these options works individually or can be combined. Let's look at a
couple examples from |Flake8|. In each example, we will have
``option_manager`` which is an instance of |OptionManager|.
.. code-block:: python
option_manager.add_option(
'--max-line-length', type='int', metavar='n',
default=defaults.MAX_LINE_LENGTH, parse_from_config=True,
help='Maximum allowed line length for the entirety of this run. '
'(Default: %default)',
)
Here we are adding the ``--max-line-length`` command-line option which is
always an integer and will be parsed from the configuration file. Since we
provide a default, we take advantage of :mod:`optparse`\ 's willingness to
display that in the help text with ``%default``.
.. code-block:: python
option_manager.add_option(
'--select', metavar='errors', default='',
parse_from_config=True, comma_separated_list=True,
help='Comma-separated list of errors and warnings to enable.'
' For example, ``--select=E4,E51,W234``. (Default: %default)',
)
In adding the ``--select`` command-line option, we're also indicating to the
|OptionManager| that we want the value parsed from the config files and parsed
as a comma-separated list.
.. code-block:: python
option_manager.add_option(
'--exclude', metavar='patterns', default=defaults.EXCLUDE,
comma_separated_list=True, parse_from_config=True,
normalize_paths=True,
help='Comma-separated list of files or directories to exclude.'
'(Default: %default)',
)
Finally, we show an option that uses all three extra flags. Values from
``--exclude`` will be parsed from the config, converted from a comma-separated
list, and then each item will be normalized.
For information about other parameters to
:meth:`~flake8.options.manager.OptionManager.add_option` refer to the
documentation of :mod:`optparse`.
Accessing Parsed Options
========================
When a plugin has a callable ``provide_options`` attribute, |Flake8| will call
it and attempt to provide the |OptionManager| instance, the parsed options
which will be an instance of :class:`optparse.Values`, and the extra arguments
that were not parsed by the |OptionManager|. If that fails, we will just pass
the :class:`optparse.Values`. In other words, your ``provide_options``
callable will have one of the following signatures:
.. code-block:: python
def provide_options(option_manager, options, args):
pass
# or
def provide_options(options):
pass
.. substitutions
.. |OptionManager| replace:: :class:`~flake8.options.manager.OptionManager`
.. |Option| replace:: :class:`~flake8.options.manager.Option`

View file

@ -0,0 +1,115 @@
.. _register-a-plugin:
==================================
Registering a Plugin with Flake8
==================================
To register any kind of plugin with |Flake8|, you need:
#. A way to install the plugin (whether it is packaged on its own or
as part of something else). In this section, we will use a ``setup.py``
written for an example plugin.
#. A name for your plugin that will (ideally) be unique.
#. A somewhat recent version of setuptools (newer than 0.7.0 but preferably as
recent as you can attain).
|Flake8| relies on functionality provided by setuptools called
`Entry Points`_. These allow any package to register a plugin with |Flake8|
via that package's ``setup.py`` file.
Let's presume that we already have our plugin written and it's in a module
called ``flake8_example``. We might have a ``setup.py`` that looks something
like:
.. code-block:: python
from __future__ import with_statement
import setuptools
requires = [
"flake8 > 3.0.0",
]
flake8_entry_point = # ...
setuptools.setup(
name="flake8_example",
license="MIT",
version="0.1.0",
description="our extension to flake8",
author="Me",
author_email="example@example.com",
url="https://gitlab.com/me/flake8_example",
packages=[
"flake8_example",
],
install_requires=requires,
entry_points={
flake8_entry_point: [
'X = flake8_example:ExamplePlugin',
],
},
classifiers=[
"Environment :: Console",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python",
"Programming Language :: Python :: 2",
"Programming Language :: Python :: 3",
"Topic :: Software Development :: Libraries :: Python Modules",
"Topic :: Software Development :: Quality Assurance",
],
)
Note specifically these lines:
.. code-block:: python
flake8_entry_point = # ...
setuptools.setup(
# snip ...
entry_points={
flake8_entry_point: [
'X = flake8_example:ExamplePlugin',
],
},
# snip ...
)
We tell setuptools to register our entry point "X" inside the specific
grouping of entry-points that flake8 should look in.
|Flake8| presently looks at three groups:
- ``flake8.extension``
- ``flake8.listen``
- ``flake8.report``
If your plugin is one that adds checks to |Flake8|, you will use
``flake8.extension``. If your plugin automatically fixes errors in code, you
will use ``flake8.listen``. Finally, if your plugin performs extra report
handling (formatting, filtering, etc.) it will use ``flake8.report``.
If our ``ExamplePlugin`` is something that adds checks, our code would look
like:
.. code-block:: python
setuptools.setup(
# snip ...
entry_points={
'flake8.extension': [
'X = flake8_example:ExamplePlugin',
],
},
# snip ...
)
.. _Entry Points:
https://pythonhosted.org/setuptools/pkg_resources.html#entry-points

View file

@ -0,0 +1,4 @@
0.6 - 2010-02-15
----------------
- Fix the McCabe metric on some loops

View file

@ -0,0 +1,6 @@
0.7 - 2010-02-18
----------------
- Fix pep8 initialization when run through Hg
- Make pep8 short options work when run through the command line
- Skip duplicates when controlling files via Hg

View file

@ -0,0 +1,5 @@
0.8 - 2011-02-27
----------------
- fixed hg hook
- discard unexisting files on hook check

View file

@ -0,0 +1,5 @@
0.9 - 2011-11-09
----------------
- update pep8 version to 0.6.1
- mccabe check: gracefully handle compile failure

View file

@ -0,0 +1,5 @@
1.0 - 2011-11-29
----------------
- Deactivates by default the complexity checker
- Introduces the complexity option in the HG hook and the command line.

View file

@ -0,0 +1,8 @@
1.1 - 2012-02-14
----------------
- fixed the value returned by --version
- allow the flake8: header to be more generic
- fixed the "hg hook raises 'physical lines'" bug
- allow three argument form of raise
- now uses setuptools if available, for 'develop' command

View file

@ -0,0 +1,6 @@
1.2 - 2012-02-12
----------------
- added a git hook
- now Python 3 compatible
- mccabe and pyflakes have warning codes like pep8 now

View file

@ -0,0 +1,4 @@
1.3 - 2012-03-12
----------------
- fixed false W402 warning on exception blocks.

View file

@ -0,0 +1,4 @@
1.3.1 - 2012-05-19
------------------
- fixed support for Python 2.5

View file

@ -0,0 +1,5 @@
1.4 - 2012-07-12
----------------
- git_hook: Only check staged changes for compliance
- use pep8 1.2

View file

@ -0,0 +1,9 @@
1.5 - 2012-10-13
----------------
- fixed the stdin
- make sure mccabe catches the syntax errors as warnings
- pep8 upgrade
- added max_line_length default value
- added Flake8Command and entry points if setuptools is around
- using the setuptools console wrapper when available

View file

@ -0,0 +1,14 @@
1.6 - 2012-11-16
----------------
- changed the signatures of the ``check_file`` function in flake8/run.py,
``skip_warning`` in flake8/util.py and the ``check``, ``checkPath``
functions in flake8/pyflakes.py.
- fix ``--exclude`` and ``--ignore`` command flags (#14, #19)
- fix the git hook that wasn't catching files not already added to the index
(#29)
- pre-emptively includes the addition to pep8 to ignore certain lines.
Add ``# nopep8`` to the end of a line to ignore it. (#37)
- ``check_file`` can now be used without any special prior setup (#21)
- unpacking exceptions will no longer cause an exception (#20)
- fixed crash on non-existent file (#38)

View file

@ -0,0 +1,7 @@
1.6.1 - 2012-11-24
------------------
- fixed the mercurial hook, a change from a previous patch was not properly
applied
- fixed an assumption about warnings/error messages that caused an exception
to be thrown when McCabe is used

View file

@ -0,0 +1,4 @@
1.6.2 - 2012-11-25
------------------
- fixed the NameError: global name 'message' is not defined (#46)

View file

@ -0,0 +1,9 @@
1.7.0 - 2012-12-21
------------------
- Fixes part of #35: Exception for no WITHITEM being an attribute of Checker
for Python 3.3
- Support stdin
- Incorporate @phd's builtins pull request
- Fix the git hook
- Update pep8.py to the latest version

View file

@ -0,0 +1,13 @@
2.0.0 - 2013-02-23
------------------
- Pyflakes errors are prefixed by an ``F`` instead of an ``E``
- McCabe complexity warnings are prefixed by a ``C`` instead of a ``W``
- Flake8 supports extensions through entry points
- Due to the above support, we **require** setuptools
- We publish the `documentation <https://flake8.readthedocs.org/>`_
- Fixes #13: pep8, pyflakes and mccabe become external dependencies
- Split run.py into main.py, engine.py and hooks.py for better logic
- Expose our parser for our users
- New feature: Install git and hg hooks automagically
- By relying on pyflakes (0.6.1), we also fixed #45 and #35

View file

@ -0,0 +1,12 @@
2.1.0 - 2013-10-26
------------------
- Add FLAKE8_LAZY and FLAKE8_IGNORE environment variable support to git and
mercurial hooks
- Force git and mercurial hooks to repsect configuration in setup.cfg
- Only check staged files if that is specified
- Fix hook file permissions
- Fix the git hook on python 3
- Ignore non-python files when running the git hook
- Ignore .tox directories by default
- Flake8 now reports the column number for PyFlakes messages

View file

@ -0,0 +1,12 @@
2.2.0 - 2014-06-22
------------------
- New option ``doctests`` to run Pyflakes checks on doctests too
- New option ``jobs`` to launch multiple jobs in parallel
- Turn on using multiple jobs by default using the CPU count
- Add support for ``python -m flake8`` on Python 2.7 and Python 3
- Fix Git and Mercurial hooks: issues #88, #133, #148 and #149
- Fix crashes with Python 3.4 by upgrading dependencies
- Fix traceback when running tests with Python 2.6
- Fix the setuptools command ``python setup.py flake8`` to read
the project configuration

View file

@ -0,0 +1,5 @@
2.2.1 - 2014-06-30
------------------
- Turn off multiple jobs by default. To enable automatic use of all CPUs, use
``--jobs=auto``. Fixes #155 and #154.

View file

@ -0,0 +1,5 @@
2.2.2 - 2014-07-04
------------------
- Re-enable multiprocessing by default while fixing the issue Windows users
were seeing.

View file

@ -0,0 +1,4 @@
2.2.3 - 2014-08-25
------------------
- Actually turn multiprocessing on by default

View file

@ -0,0 +1,20 @@
2.2.4 - 2014-10-09
------------------
- Fix bugs triggered by turning multiprocessing on by default (again)
Multiprocessing is forcibly disabled in the following cases:
- Passing something in via stdin
- Analyzing a diff
- Using windows
- Fix --install-hook when there are no config files present for pep8 or
flake8.
- Fix how the setuptools command parses excludes in config files
- Fix how the git hook determines which files to analyze (Thanks Chris
Buccella!)

View file

@ -0,0 +1,6 @@
2.2.5 - 2014-10-19
------------------
- Flush standard out when using multiprocessing
- Make the check for "# flake8: noqa" more strict

View file

@ -0,0 +1,10 @@
2.3.0 - 2015-01-04
------------------
- **Feature**: Add ``--output-file`` option to specify a file to write to
instead of ``stdout``.
- **Bug** Fix interleaving of output while using multiprocessing
(`GitLab#17`_)
.. _GitLab#17: https://gitlab.com/pycqa/flake8/issues/17

View file

@ -0,0 +1,33 @@
2.4.0 - 2015-03-07
------------------
- **Bug** Print filenames when using multiprocessing and ``-q`` option.
(`GitLab#31`_)
- **Bug** Put upper cap on dependencies. The caps for 2.4.0 are:
- ``pep8 < 1.6`` (Related to `GitLab#35`_)
- ``mccabe < 0.4``
- ``pyflakes < 0.9``
See also `GitLab#32`_
- **Bug** Files excluded in a config file were not being excluded when flake8
was run from a git hook. (`GitHub#2`_)
- **Improvement** Print warnings for users who are providing mutually
exclusive options to flake8. (`GitLab#8`_, `GitLab!18`_)
- **Feature** Allow git hook configuration to live in ``.git/config``.
See the updated `VCS hooks docs`_ for more details. (`GitLab!20`_)
.. _GitHub#2: https://github.com/pycqa/flake8/pull/2
.. _GitLab#8: https://gitlab.com/pycqa/flake8/issues/8
.. _GitLab#31: https://gitlab.com/pycqa/flake8/issues/31
.. _GitLab#32: https://gitlab.com/pycqa/flake8/issues/32
.. _GitLab#35: https://gitlab.com/pycqa/flake8/issues/35
.. _GitLab!18: https://gitlab.com/pycqa/flake8/merge_requests/18
.. _GitLab!20: https://gitlab.com/pycqa/flake8/merge_requests/20
.. _VCS hooks docs: https://flake8.readthedocs.org/en/latest/vcs.html

View file

@ -0,0 +1,12 @@
2.4.1 - 2015-05-18
------------------
- **Bug** Do not raise a ``SystemError`` unless there were errors in the
setuptools command. (`GitLab#39`_, `GitLab!23`_)
- **Bug** Do not verify dependencies of extensions loaded via entry-points.
- **Improvement** Blacklist versions of pep8 we know are broken
.. _GitLab#39: https://gitlab.com/pycqa/flake8/issues/39
.. _GitLab!23: https://gitlab.com/pycqa/flake8/merge_requests/23

View file

@ -0,0 +1,25 @@
2.5.0 - 2015-10-26
------------------
- **Improvement** Raise cap on PyFlakes for Python 3.5 support
- **Improvement** Avoid deprecation warnings when loading extensions
(`GitLab#59`_, `GitLab#90`_)
- **Improvement** Separate logic to enable "off-by-default" extensions
(`GitLab#67`_)
- **Bug** Properly parse options to setuptools Flake8 command (`GitLab!41`_)
- **Bug** Fix exceptions when output on stdout is truncated before Flake8
finishes writing the output (`GitLab#69`_)
- **Bug** Fix error on OS X where Flake8 can no longer acquire or create new
semaphores (`GitLab#74`_)
.. _GitLab!41: https://gitlab.com/pycqa/flake8/merge_requests/41
.. _GitLab#59: https://gitlab.com/pycqa/flake8/issues/59
.. _GitLab#67: https://gitlab.com/pycqa/flake8/issues/67
.. _GitLab#69: https://gitlab.com/pycqa/flake8/issues/69
.. _GitLab#74: https://gitlab.com/pycqa/flake8/issues/74
.. _GitLab#90: https://gitlab.com/pycqa/flake8/issues/90

View file

@ -0,0 +1,13 @@
2.5.1 - 2015-12-08
------------------
- **Bug** Properly look for ``.flake8`` in current working directory
(`GitLab#103`_)
- **Bug** Monkey-patch ``pep8.stdin_get_value`` to cache the actual value in
stdin. This helps plugins relying on the function when run with
multiprocessing. (`GitLab#105`_, `GitLab#107`_)
.. _GitLab#103: https://gitlab.com/pycqa/flake8/issues/103
.. _GitLab#105: https://gitlab.com/pycqa/flake8/issues/105
.. _GitLab#107: https://gitlab.com/pycqa/flake8/issues/107

View file

@ -0,0 +1,7 @@
2.5.2 - 2016-01-30
------------------
- **Bug** Parse ``output_file`` and ``enable_extensions`` from config files
- **Improvement** Raise upper bound on mccabe plugin to allow for version
0.4.0

View file

@ -0,0 +1,5 @@
2.5.3 - 2016-02-11
------------------
- **Bug** Actually parse ``output_file`` and ``enable_extensions`` from config
files

View file

@ -0,0 +1,4 @@
2.5.4 - 2016-02-11
------------------
- **Bug** Missed an attribute rename during the v2.5.3 release.

View file

@ -0,0 +1,7 @@
2.5.5 - 2016-06-14
------------------
- **Bug** Fix setuptools integration when parsing config files
- **Bug** Don't pass the user's config path as the config_file when creating a
StyleGuide

View file

@ -0,0 +1,6 @@
2.6.1 - 2016-06-25
------------------
- **Bug** Update the config files to search for to include ``setup.cfg`` and
``tox.ini``. This was broken in 2.5.5 when we stopped passing
``config_file`` to our Style Guide

View file

@ -0,0 +1,42 @@
3.0.0b1 -- 2016-06-25
---------------------
- Rewrite our documentation from scratch! (http://flake8.pycqa.org)
- Drop explicit support for Pythons 2.6, 3.2, and 3.3.
- Remove dependence on pep8/pycodestyle for file processing, plugin
dispatching, and more. We now control all of this while keeping backwards
compatibility.
- ``--select`` and ``--ignore`` can now both be specified and try to find the
most specific rule from each. For example, if you do ``--select E --ignore
E123`` then we will report everything that starts with ``E`` except for
``E123``. Previously, you would have had to do ``--ignore E123,F,W`` which
will also still work, but the former should be far more intuitive.
- Add support for in-line ``# noqa`` comments to specify **only** the error
codes to be ignored, e.g., ``# noqa: E123,W503``
- Add entry-point for formatters as well as a base class that new formatters
can inherit from. See the documentation for more details.
- Add detailed verbose output using the standard library logging module.
- Enhance our usage of optparse for plugin developers by adding new parameters
to the ``add_option`` that plugins use to register new options.
- Update ``--install-hook`` to require the name of version control system hook
you wish to install a Flake8.
- Stop checking sub-directories more than once via the setuptools command
- When passing a file on standard-in, allow the caller to specify
``--stdin-display-name`` so the output is properly formatted
- The Git hook now uses ``sys.executable`` to format the shebang line.
This allows Flake8 to install a hook script from a virtualenv that points to
that virtualenv's Flake8 as opposed to a global one (without the virtualenv
being sourced).
- When using ``--count``, the output is no longer written to stderr.

View file

@ -0,0 +1,41 @@
===========================
Release Notes and History
===========================
All of the release notes that have been recorded for Flake8 are organized here
with the newest releases first.
.. toctree::
3.0.0
2.5.5
2.5.4
2.5.3
2.5.2
2.5.1
2.5.0
2.4.1
2.4.0
2.3.0
2.2.5
2.2.4
2.2.3
2.2.2
2.2.1
2.2.0
2.1.0
2.0.0
1.7.0
1.6.2
1.6.1
1.6.0
1.5.0
1.4.0
1.3.1
1.3.0
1.2.0
1.1.0
1.0.0
0.9.0
0.8.0
0.7.0
0.6.0

View file

@ -0,0 +1,4 @@
sphinx>=1.3.0
sphinx_rtd_theme
sphinx-prompt
configparser

0
docs/source/user/.keep Normal file
View file

View file

@ -0,0 +1,227 @@
.. _configuration:
====================
Configuring Flake8
====================
Once you have learned how to :ref:`invoke <invocation>` |Flake8|, you will soon
want to learn how to configure it so you do not have to specify the same
options every time you use it.
This section will show you how to make
.. prompt:: bash
flake8
Remember that you want to specify certain options without writing
.. prompt:: bash
flake8 --select E123,W456 --enable-extensions H111
Configuration Locations
=======================
|Flake8| supports storing its configuration in the following places:
- Your top-level user directory
- In your project in one of ``setup.cfg``, ``tox.ini``, or ``.flake8``.
"User" Configuration
--------------------
|Flake8| allows a user to use "global" configuration file to store preferences.
The user configuration file is expected to be stored somewhere in the user's
"home" directory.
- On Windows the "home" directory will be something like
``C:\\Users\sigmavirus24``, a.k.a, ``~\``.
- On Linux and other Unix like systems (including OS X) we will look in
``~/``.
Note that |Flake8| looks for ``~\.flake8`` on Windows and ``~/.config/flake8``
on Linux and other Unix systems.
User configuration files use the same syntax as Project Configuration files.
Keep reading to see that syntax.
Project Configuration
---------------------
|Flake8| is written with the understanding that people organize projects into
sub-directories. Let's take for example |Flake8|'s own project structure
.. code::
flake8
├── docs
│   ├── build
│   └── source
│   ├── _static
│   ├── _templates
│   ├── dev
│   ├── internal
│   └── user
├── flake8
│   ├── formatting
│   ├── main
│   ├── options
│   └── plugins
└── tests
├── fixtures
│   └── config_files
├── integration
└── unit
In the top-level ``flake8`` directory (which contains ``docs``, ``flake8``,
and ``tests``) there's also ``tox.ini`` and ``setup.cfg`` files. In our case,
we keep our |Flake8| configuration in ``tox.ini``. Regardless of whether you
keep your config in ``.flake8``, ``setup.cfg``, or ``tox.ini`` we expect you
to use INI to configure |Flake8| (since each of these files already uses INI
as a format). This means that any |Flake8| configuration you wish to set needs
to be in the ``flake8`` section, which means it needs to start like so:
.. code-block:: ini
[flake8]
Each command-line option that you want to specify in your config file can
be named in either of two ways:
#. Using underscores (``_``) instead of hyphens (``-``)
#. Simply using hyphens (without the leading hyphens)
.. note::
Not every |Flake8| command-line option can be specified in the
configuration file. See :ref:`our list of options <options-list>` to
determine which options will be parsed from the configuration files.
Let's actually look at |Flake8|'s own configuration section:
.. code-block:: ini
[flake8]
ignore = D203
exclude = .git,__pycache__,docs/source/conf.py,old,build,dist
max-complexity = 10
This is equivalent to:
.. prompt:: bash
flake8 --ignore D203 \
--exclude .git,__pycache__,docs/source/conf.py,old,build,dist \
--max-complexity 10
In our case, if we wanted to, we could also do
.. code-block:: ini
[flake8]
ignore = D203
exclude =
.git,
__pycache__,
docs/source/conf.py,
old,
build,
dist
max-complexity = 10
This would allow us to add comments for why we're excluding items, e.g.,
.. code-block:: ini
[flake8]
ignore = D203
exclude =
# No need to traverse our git directory
.git,
# There's no value in checking cache directories
__pycache__,
# The conf file is mostly autogenerated, ignore it
docs/source/conf.py,
# The old directory contains Flake8 2.0
old,
# This contains our built documentation
build,
# This contains builds of flake8 that we don't want to check
dist
max-complexity = 10
.. note::
If you're using Python 2, you will notice that we download the
:mod:`configparser` backport from PyPI. That backport enables us to
support this behaviour on all supported versions of Python.
Please do **not** open issues about this dependency to |Flake8|.
.. note::
You can also specify ``--max-complexity`` as ``max_complexity = 10``.
This is also useful if you have a long list of error codes to ignore. Let's
look at a portion of OpenStack's Swift `project configuration`_:
.. code-block:: ini
[flake8]
# it's not a bug that we aren't using all of hacking, ignore:
# F812: list comprehension redefines ...
# H101: Use TODO(NAME)
# H202: assertRaises Exception too broad
# H233: Python 3.x incompatible use of print operator
# H301: one import per line
# H306: imports not in alphabetical order (time, os)
# H401: docstring should not start with a space
# H403: multi line docstrings should end on a new line
# H404: multi line docstring should start without a leading new line
# H405: multi line docstring summary not separated with an empty line
# H501: Do not use self.__dict__ for string formatting
ignore = F812,H101,H202,H233,H301,H306,H401,H403,H404,H405,H501
They use the comments to describe the check but they could also write this as:
.. code-block:: ini
[flake8]
# it's not a bug that we aren't using all of hacking
ignore =
# F812: list comprehension redefines ...
F812,
# H101: Use TODO(NAME)
H101,
# H202: assertRaises Exception too broad
H202,
# H233: Python 3.x incompatible use of print operator
H233,
# H301: one import per line
H301,
# H306: imports not in alphabetical order (time, os)
H306,
# H401: docstring should not start with a space
H401,
# H403: multi line docstrings should end on a new line
H403,
# H404: multi line docstring should start without a leading new line
H404,
# H405: multi line docstring summary not separated with an empty line
H405,
# H501: Do not use self.__dict__ for string formatting
H501
Or they could use each comment to describe **why** they've ignored the check.
|Flake8| knows how to parse these lists and will appropriatey handle
these situations.
.. _project configuration:
https://github.com/openstack/swift/blob/3944d820387f08372c1a29444f4af7d8e6090ae9/tox.ini#L66..L81

View file

@ -0,0 +1,90 @@
=============================
Ignoring Errors with Flake8
=============================
By default, |Flake8| has a list of error codes that it ignores. The list used
by a version of |Flake8| may be different than the list used by a different
version. To see the default list, :option:`flake8 --help` will
show the output with the current default list.
Changing the Ignore List
========================
If we want to change the list of ignored codes for a single run, we can use
:option:`flake8 --ignore` to specify a comma-separated list of codes for a
specific run on the command-line, e.g.,
.. prompt:: bash
flake8 --ignore=E1,E23,W503 path/to/files/ path/to/more/files/
This tells |Flake8| to ignore any error codes starting with ``E1``, ``E23``,
or ``W503`` while it is running.
.. note::
The documentation for :option:`flake8 --ignore` shows examples for how
to change the ignore list in the configuration file. See also
:ref:`configuration` as well for details about how to use configuration
files.
In-line Ignoring Errors
=======================
In some cases, we might not want to ignore an error code (or class of error
codes) for the entirety of our project. Instead, we might want to ignore the
specific error code on a specific line. Let's take for example a line like
.. code-block:: python
example = lambda: 'example'
Sometimes we genuinely need something this simple. We could instead define
a function like we normally would. Note, in some contexts this distracts from
what is actually happening. In those cases, we can also do:
.. code-block:: python
example = lambda: 'example' # noqa: E731
This will only ignore the error from pycodestyle that checks for lambda
assignments and generates an ``E731``. If there are other errors on the line
then those will be reported.
.. note::
If we ever want to disable |Flake8| respecting ``# noqa`` comments, we can
can refer to :option:`flake8 --disable-noqa`.
If we instead had more than one error that we wished to ignore, we could
list all of the errors with commas separating them:
.. code-block:: python
# noqa: E731,E123
Finally, if we have a particularly bad line of code, we can ignore every error
using simply ``# noqa`` with nothing after it.
Ignoring Entire Files
=====================
Imagine a situation where we are adding |Flake8| to a codebase. Let's further
imagine that with the exception of a few particularly bad files, we can add
|Flake8| easily and move on with our lives. There are two ways to ignore the
file:
#. By explicitly adding it to our list of excluded paths (see: :option:`flake8
--exclude`)
#. By adding ``# flake8: noqa`` to the file
The former is the **recommended** way of ignoring entire files. By using our
exclude list, we can include it in our configuration file and have one central
place to find what files aren't included in |Flake8| checks. The latter has the
benefit that when we run |Flake8| with :option:`flake8 --disable-noqa` all of
the errors in that file will show up without having to modify our
configuration. Both exist so we can choose which is better for us.

View file

@ -0,0 +1,33 @@
==============
Using Flake8
==============
|Flake8| can be used in many ways. A few:
- invoked on the command-line
- invoked via Python
- called by Git or Mercurial on or around committing
This guide will cover all of these and the nuances for using |Flake8|.
.. note::
This portion of |Flake8|'s documentation does not cover installation. See
the :ref:`installation-guide` section for how to install |Flake8|.
.. toctree::
:maxdepth: 2
invocation
configuration
options
ignoring-errors
using-plugins
python-api
.. config files
.. command-line tutorial
.. VCS usage
.. installing and using plugins

View file

@ -0,0 +1,144 @@
.. _invocation:
=================
Invoking Flake8
=================
Once you have :ref:`installed <installation-guide>` |Flake8|, you can begin
using it. Most of the time, you will be able to generically invoke |Flake8|
like so:
.. prompt:: bash
flake8 ...
Where you simply allow the shell running in your terminal to locate |Flake8|.
In some cases, though, you may have installed |Flake8| for multiple versions
of Python (e.g., Python 2.7 and Python 3.5) and you need to call a specific
version. In that case, you will have much better results using:
.. prompt:: bash
python2.7 -m flake8
Or
.. prompt:: bash
python3.5 -m flake8
Since that will tell the correct version of Python to run |Flake8|.
.. note::
Installing |Flake8| once will not install it on both Python 2.7 and
Python 3.5. It will only install it for the version of Python that
is running pip.
It is also possible to specify command-line options directly to |Flake8|:
.. prompt:: bash
flake8 --select E123
Or
.. prompt:: bash
python<version> -m flake8 --select E123
.. note::
This is the last time we will show both versions of an invocation.
From now on, we'll simply use ``flake8`` and assume that the user
knows they can instead use ``python<version> -m flake8`` instead.
It's also possible to narrow what |Flake8| will try to check by specifying
exactly the paths and directories you want it to check. Let's assume that
we have a directory with python files and sub-directories which have python
files (and may have more sub-directories) called ``my_project``. Then if
we only want errors from files found inside ``my_project`` we can do:
.. prompt:: bash
flake8 my_project
And if we only want certain errors (e.g., ``E123``) from files in that
directory we can also do:
.. prompt:: bash
flake8 --select E123 my_project
If you want to explore more options that can be passed on the command-line,
you can use the ``--help`` option:
.. prompt:: bash
flake8 --help
And you should see something like:
.. code::
Usage: flake8 [options] file file ...
Options:
--version show program's version number and exit
-h, --help show this help message and exit
-v, --verbose Print more information about what is happening in
flake8. This option is repeatable and will increase
verbosity each time it is repeated.
-q, --quiet Report only file names, or nothing. This option is
repeatable.
--count Print total number of errors and warnings to standard
error and set the exit code to 1 if total is not
empty.
--diff Report changes only within line number ranges in the
unified diff provided on standard in by the user.
--exclude=patterns Comma-separated list of files or directories to
exclude.(Default:
.svn,CVS,.bzr,.hg,.git,__pycache__,.tox)
--filename=patterns Only check for filenames matching the patterns in this
comma-separated list. (Default: *.py)
--format=format Format errors according to the chosen formatter.
--hang-closing Hang closing bracket instead of matching indentation
of opening bracket's line.
--ignore=errors Comma-separated list of errors and warnings to ignore
(or skip). For example, ``--ignore=E4,E51,W234``.
(Default: E121,E123,E126,E226,E24,E704)
--max-line-length=n Maximum allowed line length for the entirety of this
run. (Default: 79)
--select=errors Comma-separated list of errors and warnings to enable.
For example, ``--select=E4,E51,W234``. (Default: )
--disable-noqa Disable the effect of "# noqa". This will report
errors on lines with "# noqa" at the end.
--show-source Show the source generate each error or warning.
--statistics Count errors and warnings.
--enabled-extensions=ENABLED_EXTENSIONS
Enable plugins and extensions that are otherwise
disabled by default
--exit-zero Exit with status code "0" even if there are errors.
-j JOBS, --jobs=JOBS Number of subprocesses to use to run checks in
parallel. This is ignored on Windows. The default,
"auto", will auto-detect the number of processors
available to use. (Default: auto)
--output-file=OUTPUT_FILE
Redirect report to a file.
--append-config=APPEND_CONFIG
Provide extra config files to parse in addition to the
files found by Flake8 by default. These files are the
last ones read and so they take the highest precedence
when multiple files provide the same option.
--config=CONFIG Path to the config file that will be the authoritative
config source. This will cause Flake8 to ignore all
other configuration files.
--isolated Ignore all found configuration files.
--builtins=BUILTINS define more built-ins, comma separated
--doctests check syntax of the doctests
--include-in-doctest=INCLUDE_IN_DOCTEST
Run doctests only on these files
--exclude-from-doctest=EXCLUDE_FROM_DOCTEST
Skip these files when running doctests
Installed plugins: pyflakes: 1.0.0, pep8: 1.7.0

View file

@ -0,0 +1,730 @@
.. _options-list:
================================================
Full Listing of Options and Their Descriptions
================================================
..
NOTE(sigmavirus24): When adding new options here, please follow the
following _rough_ template:
.. option:: --<opt-name>[=<descriptive-name-of-parameter>]
Active description of option's purpose (note that each description
starts with an active verb)
Command-line usage:
.. prompt:: bash
flake8 --<opt-name>[=<example-parameter(s)>] [positional params]
This **can[ not]** be specified in config files.
(If it can be, an example using .. code-block:: ini)
Thank you for your contribution to Flake8's documentation.
.. program:: flake8
.. option:: --version
Show |Flake8|'s version as well as the versions of all plugins
installed.
Command-line usage:
.. prompt:: bash
flake8 --version
This **can not** be specified in config files.
.. option:: -h, --help
Show a description of how to use |Flake8| and its options.
Command-line usage:
.. prompt:: bash
flake8 --help
flake8 -h
This **can not** be specified in config files.
.. option:: -v, --verbose
Increase the verbosity of |Flake8|'s output. Each time you specify
it, it will print more and more information.
Command-line example:
.. prompt:: bash
flake8 -vv
This **can** be specified in config files.
Example config file usage:
.. code-block:: ini
verbose = 2
.. option:: -q, --quiet
Decrease the verbosity of |Flake8|'s output. Each time you specify it,
it will print less and less information.
Command-line example:
.. prompt:: bash
flake8 -q
This **can** be specified in config files.
Example config file usage:
.. code-block:: ini
quiet = 1
.. option:: --count
Print the total number of errors.
Command-line example:
.. prompt:: bash
flake8 --count dir/
This **can** be specified in config files.
Example config file usage:
.. code-block:: ini
count = True
.. option:: --diff
Use the unified diff provided on standard in to only check the modified
files and report errors included in the diff.
Command-line example:
.. prompt:: bash
git diff -u | flake8 --diff
This **can not** be specified in config files.
.. option:: --exclude=<patterns>
Provide a comma-separated list of glob patterns to exclude from checks.
This defaults to: ``.svn,CVS,.bzr,.hg,.git,__pycache__,.tox``
Example patterns:
- ``*.pyc`` will match any file that ends with ``.pyc``
- ``__pycache__`` will match any path that has ``__pycache__`` in it
- ``lib/python`` will look expand that using :func:`os.path.abspath` and
look for matching paths
Command-line example:
.. prompt:: bash
flake8 --exclude=*.pyc dir/
This **can** be specified in config files.
Example config file usage:
.. code-block:: ini
exclude =
.tox,
__pycache__
.. option:: --filename=<patterns>
Provide a comma-separate list of glob patterns to include for checks.
This defaults to: ``*.py``
Example patterns:
- ``*.py`` will match any file that ends with ``.py``
- ``__pycache__`` will match any path that has ``__pycache__`` in it
- ``lib/python`` will look expand that using :func:`os.path.abspath` and
look for matching paths
Command-line example:
.. prompt:: bash
flake8 --filename=*.py dir/
This **can** be specified in config files.
Example config file usage:
.. code-block:: ini
filename =
example.py,
another-example*.py
.. option:: --stdin-display-name=<display_name>
Provide the name to use to report warnings and errors from code on stdin.
Instead of reporting an error as something like:
.. code::
stdin:82:73 E501 line too long
You can specify this option to have it report whatever value you want
instead of stdin.
This defaults to: ``stdin``
Command-line example:
.. prompt:: bash
cat file.py | flake8 --stdin-display-name=file.py -
This **can not** be specified in config files.
.. option:: --format=<format>
Select the formatter used to display errors to the user.
This defaults to: ``default``
By default, there are two formatters available:
- default
- pylint
Other formatters can be installed. Refer to their documentation for the
name to use to select them. Further, users can specify their own format
string. The variables available are:
- code
- col
- path
- row
- text
The default formatter has a format string of:
.. code-block:: python
'%(path)s:%(row)d:%(col)d: %(code)s %(text)s'
Command-line example:
.. prompt:: bash
flake8 --format=pylint dir/
flake8 --format='%(path)s::%(row)d,%(col)d::%(code)s::%(text)s' dir/
This **can** be specified in config files.
Example config file usage:
.. code-block:: ini
format=pylint
format=%(path)s::%(row)d,%(col)d::%(code)s::%(text)s
.. option:: --hang-closing
Toggle whether pycodestyle should enforce matching the indentation of the
opening bracket's line. When you specify this, it will prefer that you
hang the closing bracket rather than match the indentation.
Command-line example:
.. prompt:: bash
flake8 --hang-closing dir/
This **can** be specified in config files.
Example config file usage:
.. code-block:: ini
hang_closing = True
hang-closing = True
.. option:: --ignore=<errors>
Specify a list of codes to ignore. The list is expected to be
comma-separated, and does not need to specify an error code exactly.
Since |Flake8| 3.0, this **can** be combined with :option:`--select`. See
:option:`--select` for more information.
For example, if you wish to only ignore ``W234``, then you can specify
that. But if you want to ignore all codes that start with ``W23`` you
need only specify ``W23`` to ignore them. This also works for ``W2`` and
``W`` (for example).
This defaults to: ``E121,E123,E126,E226,E24,E704``
Command-line example:
.. prompt:: bash
flake8 --ignore=E121,E123 dir/
flake8 --ignore=E24,E704 dir/
This **can** be specified in config files.
Example config file usage:
.. code-block:: ini
ignore =
E121,
E123
ignore = E121,E123
.. option:: --max-line-length=<n>
Set the maximum length that any line (with some exceptions) may be.
Exceptions include lines that are either strings or comments which are
entirely URLs. For example:
.. code-block:: python
# https://some-super-long-domain-name.com/with/some/very/long/path
url = (
'http://...'
)
This defaults to: 79
Command-line example:
.. prompt:: bash
flake8 --max-line-length 99 dir/
This **can** be specified in config files.
Example config file usage:
.. code-block:: ini
max-line-length = 79
.. option:: --select=<errors>
Specify the list of error codes you wish |Flake8| to report. Similarly to
:option:`--ignore`. You can specify a portion of an error code to get all
that start with that string. For example, you can use ``E``, ``E4``,
``E43``, and ``E431``.
This defaults to: E,F,W,C
Command-line example:
.. prompt:: bash
flake8 --select=E431,E5,W,F dir/
flake8 --select=E,W dir/
This can also be combined with :option:`--ignore`:
.. prompt:: bash
flake8 --select=E --ignore=E432 dir/
This will report all codes that start with ``E``, but ignore ``E432``
specifically. This is more flexibly than the |Flake8| 2.x and 1.x used
to be.
This **can** be specified in config files.
Example config file usage:
.. code-block:: ini
select =
E431,
W,
F
.. option:: --disable-noqa
Report all errors, even if it is on the same line as a ``# NOQA`` comment.
``# NOQA`` can be used to silence messages on specific lines. Sometimes,
users will want to see what errors are being silenced without editing the
file. This option allows you to see all the warnings, errors, etc.
reported.
Command-line example:
.. prompt:: bash
flake8 --disable-noqa dir/
This **can** be specified in config files.
Example config file usage:
.. code-block:: ini
disable_noqa = True
disable-noqa = True
.. option:: --show-source
Print the source code generating the error/warning in question.
Command-line example:
.. prompt:: bash
flake8 --show-source dir/
This **can** be specified in config files.
Example config file usage:
.. code-block:: ini
show_source = True
show-source = True
.. option:: --statistics
Count the number of occurrences of each error/warning code and
print a report.
Command-line example:
.. prompt:: bash
flake8 --statistics
This **can** be specified in config files.
Example config file usage:
.. code-block:: ini
statistics = True
.. option:: --enable-extensions=<errors>
Enable off-by-default extensions.
Plugins to |Flake8| have the option of registering themselves as
off-by-default. These plugins effectively add themselves to the
default ignore list.
Command-line example:
.. prompt:: bash
flake8 --enable-extensions=H111 dir/
This **can** be specified in config files.
Example config file usage:
.. code-block:: ini
enable-extensions =
H111,
G123
enable_extensions =
H111,
G123
.. option:: --exit-zero
Force |Flake8| to use the exit status code 0 even if there are errors.
By default |Flake8| will exit with a non-zero integer if there are errors.
Command-line example:
.. prompt:: bash
flake8 --exit-zero dir/
This **can not** be specified in config files.
.. option:: --install-hook=VERSION_CONTROL_SYSTEM
Install a hook for your version control system that is executed before
or during commit.
The available options are:
- git
- mercurial
Command-line usage:
.. prompt:: bash
flake8 --install-hook=git
flake8 --install-hook=mercurial
This **can not** be specified in config files.
.. option:: --jobs=<n>
Specify the number of subprocesses that |Flake8| will use to run checks in
parallel.
.. note::
This option is ignored on Windows because :mod:`multiprocessing` does
not support Windows across all supported versions of Python.
This defaults to: ``auto``
The default behaviour will use the number of CPUs on your machine as
reported by :func:`multiprocessing.cpu_count`.
Command-line example:
.. prompt:: bash
flake8 --jobs=8 dir/
This **can** be specified in config files.
Example config file usage:
.. code-block:: ini
jobs = 8
.. option:: --output-file=<path>
Redirect all output to the specified file.
Command-line example:
.. prompt:: bash
flake8 --output-file=output.txt dir/
flake8 -vv --output-file=output.txt dir/
This **can** be specified in config files.
Example config file usage:
.. code-block:: ini
output-file = output.txt
output_file = output.txt
.. option:: --append-config=<config>
Provide extra config files to parse in after and in addition to the files
that |Flake8| found on its own. Since these files are the last ones read
into the Configuration Parser, so it has the highest precedence if it
provides an option specified in another config file.
Command-line example:
.. prompt:: bash
flake8 --append-config=my-extra-config.ini dir/
This **can not** be specified in config files.
.. option:: --config=<config>
Provide a path to a config file that will be the only config file read and
used. This will cause |Flake8| to ignore all other config files that
exist.
Command-line example:
.. prompt:: bash
flake8 --config=my-only-config.ini dir/
This **can not** be specified in config files.
.. option:: --isolated
Ignore any config files and use |Flake8| as if there were no config files
found.
Command-line example:
.. prompt:: bash
flake8 --isolated dir/
This **can not** be specified in config files.
.. option:: --builtins=<builtins>
Provide a custom list of builtin functions, objects, names, etc.
This allows you to let pyflakes know about builtins that it may
not immediately recognize so it does not report warnings for using
an undefined name.
This is registered by the default PyFlakes plugin.
Command-line example:
.. prompt:: bash
flake8 --builtins=_,_LE,_LW dir/
This **can** be specified in config files.
Example config file usage:
.. code-block:: ini
builtins =
_,
_LE,
_LW
.. option:: --doctests
Enable PyFlakes syntax checking of doctests in docstrings.
This is registered by the default PyFlakes plugin.
Command-line example:
.. prompt:: bash
flake8 --doctests dir/
This **can** be specified in config files.
Example config file usage:
.. code-block:: ini
doctests = True
.. option:: --include-in-doctest=<paths>
Specify which files are checked by PyFlakes for doctest syntax.
This is registered by the default PyFlakes plugin.
Command-line example:
.. prompt:: bash
flake8 --include-in-doctest=dir/subdir/file.py,dir/other/file.py dir/
This **can** be specified in config files.
Example config file usage:
.. code-block:: ini
include-in-doctest =
dir/subdir/file.py,
dir/other/file.py
include_in_doctest =
dir/subdir/file.py,
dir/other/file.py
.. option:: --exclude-from-doctest=<paths>
Specify which files are not to be checked by PyFlakes for doctest syntax.
This is registered by the default PyFlakes plugin.
Command-line example:
.. prompt:: bash
flake8 --exclude-in-doctest=dir/subdir/file.py,dir/other/file.py dir/
This **can** be specified in config files.
Example config file usage:
.. code-block:: ini
exclude-in-doctest =
dir/subdir/file.py,
dir/other/file.py
exclude_in_doctest =
dir/subdir/file.py,
dir/other/file.py
.. option:: --benchmark
Collect and print benchmarks for this run of |Flake8|. This aggregates the
total number of:
- tokens
- physical lines
- logical lines
- files
and the number of elapsed seconds.
Command-line usage:
.. prompt:: bash
flake8 --benchmark dir/
This **can not** be specified in config files.

View file

@ -0,0 +1,11 @@
===================
Public Python API
===================
|Flake8| 3.0.0 presently does not have a public, stable Python API.
When it does it will be located in :mod:`flake8.api` and that will
be documented here.
.. automodule:: flake8.api
:members:

View file

@ -0,0 +1,66 @@
==================================
Using Plugins For Fun and Profit
==================================
|Flake8| is useful on its own but a lot of |Flake8|'s popularity is due to
its extensibility. Our community has developed :term:`plugin`\ s that augment
|Flake8|'s behaviour. Most of these plugins are uploaded to PyPI_. The
developers of these plugins often have some style they wish to enforce.
For example, `flake8-docstrings`_ adds a check for :pep:`257` style
conformance. Others attempt to enforce consistency, like `flake8-future`_.
.. note::
The accuracy or reliability of these plugins may vary wildly from plugin
to plugin and not all plugins are guaranteed to work with |Flake8| 3.0.
To install a third-party plugin, make sure that you know which version of
Python (or pip) you used to install |Flake8|. You can then use the most
appropriate of:
.. prompt:: bash
pip install <plugin-name>
pip3 install <plugin-name>
python -m pip install <plugin-name>
python2.7 -m pip install <plugin-name>
python3 -m pip install <plugin-name>
python3.4 -m pip install <plugin-name>
python3.5 -m pip install <plugin-name>
To install the plugin, where ``<plugin-name>`` is the package name on PyPI_.
To verify installation use:
.. prompt:: bash
flake8 --version
python<version> -m flake8 --version
To see the plugin's name and version in the output.
.. seealso:: :ref:`How to Invoke Flake8 <invocation>`
After installation, most plugins immediately start reporting :term:`error`\ s.
Check the plugin's documentation for which error codes it returns and if it
disables any by default.
.. note::
You can use both :option:`flake8 --select` and :option:`flake8 --ignore`
with plugins.
Some plugins register new options, so be sure to check :option:`flake8 --help`
for new flags and documentation. These plugins may also allow these flags to
be specified in your configuration file. Hopefully, the plugin authors have
documented this for you.
.. seealso:: :ref:`Configuring Flake8 <configuration>`
.. _PyPI:
https://pypi.io/
.. _flake8-docstrings:
https://pypi.io/project/flake8-docstrings/
.. _flake8-future:
https://pypi.io/project/flake8-future/

View file

@ -1,50 +0,0 @@
VCS Hooks
=========
flake8 can install hooks for Mercurial and Git so that flake8 is run
automatically before commits. The commit will fail if there are any
flake8 issues.
You can install the hook by issuing this command in the root of your
project::
$ flake8 --install-hook
In the case of Git, the hook won't be installed if a custom
``pre-commit`` hook file is already present in
the ``.git/hooks`` directory.
You can control the behavior of the pre-commit hook using configuration file
settings or environment variables:
``flake8.complexity`` or ``FLAKE8_COMPLEXITY``
Any value > 0 enables complexity checking with McCabe. (defaults
to 10)
``flake8.strict`` or ``FLAKE8_STRICT``
If True, this causes the commit to fail in case of any errors at
all. (defaults to False)
``flake8.ignore`` or ``FLAKE8_IGNORE``
Comma-separated list of errors and warnings to ignore. (defaults to
empty)
``flake8.lazy`` or ``FLAKE8_LAZY``
If True, also scans those files not added to the index before
commit. (defaults to False)
You can set these either through the git command line
.. code-block:: bash-session
$ git config flake8.complexity 10
$ git config flake8.strict true
Or by directly editing ``.git/config`` and adding a section like
.. code-block:: ini
[flake8]
complexity = 10
strict = true
lazy = false

View file

@ -1,53 +0,0 @@
.. _error-codes:
Warning / Error codes
=====================
The convention of Flake8 is to assign a code to each error or warning, like
the ``pycodestyle`` tool. These codes are used to configure the list of errors
which are selected or ignored.
Each code consists of an upper case ASCII letter followed by three digits.
The recommendation is to use a different prefix for each plugin. A list of the
known prefixes is published below:
- ``E***``/``W***``: `pycodestyle errors and warnings
<https://pycodestyle.readthedocs.io/en/latest/intro.html#error-codes>`_
- ``F***``: PyFlakes codes (see below)
- ``C9**``: McCabe complexity plugin `mccabe
<https://github.com/flintwork/mccabe>`_
- ``N8**``: Naming Conventions plugin `pep8-naming
<https://github.com/flintwork/pep8-naming>`_
The original PyFlakes does not provide error codes. Flake8 patches the
PyFlakes messages to add the following codes:
+------+--------------------------------------------------------------------+
| code | sample message |
+======+====================================================================+
| F401 | ``module`` imported but unused |
+------+--------------------------------------------------------------------+
| F402 | import ``module`` from line ``N`` shadowed by loop variable |
+------+--------------------------------------------------------------------+
| F403 | 'from ``module`` import \*' used; unable to detect undefined names |
+------+--------------------------------------------------------------------+
| F404 | future import(s) ``name`` after other statements |
+------+--------------------------------------------------------------------+
| F405 | ``name`` may be undefined, or defined from star imports: ``module``|
+------+--------------------------------------------------------------------+
+------+--------------------------------------------------------------------+
| F811 | redefinition of unused ``name`` from line ``N`` |
+------+--------------------------------------------------------------------+
| F812 | list comprehension redefines ``name`` from line ``N`` |
+------+--------------------------------------------------------------------+
| F821 | undefined name ``name`` |
+------+--------------------------------------------------------------------+
| F822 | undefined name ``name`` in __all__ |
+------+--------------------------------------------------------------------+
| F823 | local variable ``name`` ... referenced before assignment |
+------+--------------------------------------------------------------------+
| F831 | duplicate argument ``name`` in function definition |
+------+--------------------------------------------------------------------+
| F841 | local variable ``name`` is assigned to but never used |
+------+--------------------------------------------------------------------+

View file

@ -1 +0,0 @@
__version__ = '2.6.1'

View file

@ -1,4 +0,0 @@
from flake8.main import main
# python -m flake8 (with Python >= 2.7)
main()

View file

@ -1,27 +0,0 @@
import atexit
import sys
def install_vcs_hook(option, option_str, value, parser):
# For now, there's no way to affect a change in how pep8 processes
# options. If no args are provided and there's no config file present,
# it will error out because no input was provided. To get around this,
# when we're using --install-hook, we'll say that there were arguments so
# we can actually attempt to install the hook.
# See: https://gitlab.com/pycqa/flake8/issues/2 and
# https://github.com/jcrocholl/pep8/blob/4c5bf00cb613be617c7f48d3b2b82a1c7b895ac1/pep8.py#L1912
# for more context.
parser.values.install_hook = True
parser.rargs.append('.')
def restore_stdout(old_stdout):
sys.stdout.close()
sys.stdout = old_stdout
def redirect_stdout(option, option_str, value, parser):
fd = open(value, 'w')
old_stdout, sys.stdout = sys.stdout, fd
atexit.register(restore_stdout, old_stdout)

View file

@ -1,12 +0,0 @@
# -*- coding: utf-8 -*-
"""Compatibility shims for Flake8."""
import os.path
import sys
def relpath(path, start='.'):
"""Wallpaper over the differences between 2.6 and newer versions."""
if sys.version_info < (2, 7) and path.startswith(start):
return path[len(start):]
else:
return os.path.relpath(path, start=start)

View file

@ -1,316 +0,0 @@
# -*- coding: utf-8 -*-
import errno
import io
import platform
import re
import sys
import warnings
import pycodestyle as pep8
from flake8 import __version__
from flake8 import callbacks
from flake8.reporter import (multiprocessing, BaseQReport, FileQReport,
QueueReport)
from flake8 import util
_flake8_noqa = re.compile(r'\s*# flake8[:=]\s*noqa', re.I).search
EXTRA_EXCLUDE = ['.tox', '.eggs', '*.egg']
pep8.PROJECT_CONFIG = ('.flake8',) + pep8.PROJECT_CONFIG
def _load_entry_point(entry_point, verify_requirements):
"""Based on the version of setuptools load an entry-point correctly.
setuptools 11.3 deprecated `require=False` in the call to EntryPoint.load.
To load entry points correctly after that without requiring all
dependencies be present, the proper way is to call EntryPoint.resolve.
This function will provide backwards compatibility for older versions of
setuptools while also ensuring we do the right thing for the future.
"""
if hasattr(entry_point, 'resolve') and hasattr(entry_point, 'require'):
if verify_requirements:
entry_point.require()
plugin = entry_point.resolve()
else:
plugin = entry_point.load(require=verify_requirements)
return plugin
def _register_extensions():
"""Register all the extensions."""
extensions = util.OrderedSet()
extensions.add(('pycodestyle', pep8.__version__))
parser_hooks = []
options_hooks = []
ignored_hooks = []
try:
from pkg_resources import iter_entry_points
except ImportError:
pass
else:
for entry in iter_entry_points('flake8.extension'):
# Do not verify that the requirements versions are valid
checker = _load_entry_point(entry, verify_requirements=False)
pep8.register_check(checker, codes=[entry.name])
extensions.add((checker.name, checker.version))
if hasattr(checker, 'add_options'):
parser_hooks.append(checker.add_options)
if hasattr(checker, 'parse_options'):
options_hooks.append(checker.parse_options)
if getattr(checker, 'off_by_default', False) is True:
ignored_hooks.append(entry.name)
return extensions, parser_hooks, options_hooks, ignored_hooks
def get_parser():
"""This returns an instance of optparse.OptionParser with all the
extensions registered and options set. This wraps ``pep8.get_parser``.
"""
(extensions, parser_hooks, options_hooks, ignored) = _register_extensions()
details = ', '.join('%s: %s' % ext for ext in extensions)
python_version = get_python_version()
parser = pep8.get_parser('flake8', '%s (%s) %s' % (
__version__, details, python_version
))
for opt in ('--repeat', '--testsuite', '--doctest'):
try:
parser.remove_option(opt)
except ValueError:
pass
if multiprocessing:
parser.config_options.append('jobs')
parser.add_option('-j', '--jobs', type='string', default='auto',
help="number of jobs to run simultaneously, "
"or 'auto'. This is ignored on Windows.")
parser.add_option('--exit-zero', action='store_true',
help="exit with code 0 even if there are errors")
for parser_hook in parser_hooks:
parser_hook(parser)
# See comment above regarding why this has to be a callback.
parser.add_option('--install-hook', default=False, dest='install_hook',
help='Install the appropriate hook for this '
'repository.', action='callback',
callback=callbacks.install_vcs_hook)
parser.add_option('--output-file', default=None,
help='Redirect report to a file.',
type='string', nargs=1, action='callback',
callback=callbacks.redirect_stdout)
parser.add_option('--enable-extensions', default='',
dest='enable_extensions',
help='Enable plugins and extensions that are disabled '
'by default',
type='string')
parser.config_options.extend(['output-file', 'enable-extensions'])
parser.ignored_extensions = ignored
return parser, options_hooks
class NoQAStyleGuide(pep8.StyleGuide):
def input_file(self, filename, lines=None, expected=None, line_offset=0):
"""Run all checks on a Python source file."""
if self.options.verbose:
print('checking %s' % filename)
fchecker = self.checker_class(
filename, lines=lines, options=self.options)
# Any "flake8: noqa" comments to ignore the entire file?
if any(_flake8_noqa(line) for line in fchecker.lines):
return 0
return fchecker.check_all(expected=expected, line_offset=line_offset)
class StyleGuide(object):
"""A wrapper StyleGuide object for Flake8 usage.
This allows for OSErrors to be caught in the styleguide and special logic
to be used to handle those errors.
"""
# Reasoning for error numbers is in-line below
serial_retry_errors = set([
# ENOSPC: Added by sigmavirus24
# > On some operating systems (OSX), multiprocessing may cause an
# > ENOSPC error while trying to trying to create a Semaphore.
# > In those cases, we should replace the customized Queue Report
# > class with pep8's StandardReport class to ensure users don't run
# > into this problem.
# > (See also: https://gitlab.com/pycqa/flake8/issues/74)
errno.ENOSPC,
# NOTE(sigmavirus24): When adding to this list, include the reasoning
# on the lines before the error code and always append your error
# code. Further, please always add a trailing `,` to reduce the visual
# noise in diffs.
])
def __init__(self, **kwargs):
# This allows us to inject a mocked StyleGuide in the tests.
self._styleguide = kwargs.pop('styleguide', NoQAStyleGuide(**kwargs))
@property
def options(self):
return self._styleguide.options
@property
def paths(self):
return self._styleguide.paths
def _retry_serial(self, func, *args, **kwargs):
"""This will retry the passed function in serial if necessary.
In the event that we encounter an OSError with an errno in
:attr:`serial_retry_errors`, this function will retry this function
using pep8's default Report class which operates in serial.
"""
try:
return func(*args, **kwargs)
except OSError as oserr:
if oserr.errno in self.serial_retry_errors:
self.init_report(pep8.StandardReport)
else:
raise
return func(*args, **kwargs)
def check_files(self, paths=None):
return self._retry_serial(self._styleguide.check_files, paths=paths)
def excluded(self, filename, parent=None):
return self._styleguide.excluded(filename, parent=parent)
def init_report(self, reporter=None):
return self._styleguide.init_report(reporter)
def input_file(self, filename, lines=None, expected=None, line_offset=0):
return self._retry_serial(
self._styleguide.input_file,
filename=filename,
lines=lines,
expected=expected,
line_offset=line_offset,
)
def _parse_multi_options(options, split_token=','):
r"""Split and strip and discard empties.
Turns the following:
A,
B,
into ["A", "B"].
Credit: Kristian Glass as contributed to pep8
"""
if options:
return [o.strip() for o in options.split(split_token) if o.strip()]
else:
return options
def _disable_extensions(parser, options):
ignored_extensions = set(getattr(parser, 'ignored_extensions', []))
enabled = set(_parse_multi_options(options.enable_extensions))
# Remove any of the selected extensions from the extensions ignored by
# default.
ignored_extensions -= enabled
# Whatever is left afterwards should be unioned with options.ignore and
# options.ignore should be updated with that.
options.ignore = tuple(ignored_extensions.union(options.ignore))
def get_style_guide(**kwargs):
"""Parse the options and configure the checker. This returns a sub-class
of ``pep8.StyleGuide``."""
kwargs['parser'], options_hooks = get_parser()
styleguide = StyleGuide(**kwargs)
options = styleguide.options
_disable_extensions(kwargs['parser'], options)
if options.exclude and not isinstance(options.exclude, list):
options.exclude = pep8.normalize_paths(options.exclude)
elif not options.exclude:
options.exclude = []
# Add patterns in EXTRA_EXCLUDE to the list of excluded patterns
options.exclude.extend(pep8.normalize_paths(EXTRA_EXCLUDE))
for options_hook in options_hooks:
options_hook(options)
if util.warn_when_using_jobs(options):
if not multiprocessing:
warnings.warn("The multiprocessing module is not available. "
"Ignoring --jobs arguments.")
if util.is_windows():
warnings.warn("The --jobs option is not available on Windows. "
"Ignoring --jobs arguments.")
if util.is_using_stdin(styleguide.paths):
warnings.warn("The --jobs option is not compatible with supplying "
"input using - . Ignoring --jobs arguments.")
if options.diff:
warnings.warn("The --diff option was specified with --jobs but "
"they are not compatible. Ignoring --jobs arguments."
)
if options.diff:
options.jobs = None
force_disable_jobs = util.force_disable_jobs(styleguide)
if multiprocessing and options.jobs and not force_disable_jobs:
if options.jobs.isdigit():
n_jobs = int(options.jobs)
else:
try:
n_jobs = multiprocessing.cpu_count()
except NotImplementedError:
n_jobs = 1
if n_jobs > 1:
options.jobs = n_jobs
reporter = QueueReport
if options.quiet:
reporter = BaseQReport
if options.quiet == 1:
reporter = FileQReport
report = styleguide.init_report(reporter)
report.input_file = styleguide.input_file
styleguide.runner = report.task_queue.put
return styleguide
def get_python_version():
# The implementation isn't all that important.
try:
impl = platform.python_implementation() + " "
except AttributeError: # Python 2.5
impl = ''
return '%s%s on %s' % (impl, platform.python_version(), platform.system())
def make_stdin_get_value(original):
def stdin_get_value():
if not hasattr(stdin_get_value, 'cached_stdin'):
value = original()
if sys.version_info < (3, 0):
stdin = io.BytesIO(value)
else:
stdin = io.StringIO(value)
stdin_get_value.cached_stdin = stdin
else:
stdin = stdin_get_value.cached_stdin
return stdin.getvalue()
return stdin_get_value
pep8.stdin_get_value = make_stdin_get_value(pep8.stdin_get_value)

View file

@ -1,295 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import with_statement
import os
import pycodestyle as pep8
import sys
import stat
from subprocess import Popen, PIPE
import shutil
import tempfile
try:
from configparser import ConfigParser
except ImportError: # Python 2
from ConfigParser import ConfigParser
from flake8 import compat
from flake8.engine import get_parser, get_style_guide
def git_hook(complexity=-1, strict=False, ignore=None, lazy=False):
"""This is the function used by the git hook.
:param int complexity: (optional), any value > 0 enables complexity
checking with mccabe
:param bool strict: (optional), if True, this returns the total number of
errors which will cause the hook to fail
:param str ignore: (optional), a comma-separated list of errors and
warnings to ignore
:param bool lazy: (optional), allows for the instances where you don't add
the files to the index before running a commit, e.g., git commit -a
:returns: total number of errors if strict is True, otherwise 0
"""
gitcmd = "git diff-index --cached --name-only --diff-filter=ACMRTUXB HEAD"
if lazy:
# Catch all files, including those not added to the index
gitcmd = gitcmd.replace('--cached ', '')
if hasattr(ignore, 'split'):
ignore = ignore.split(',')
# Returns the exit code, list of files modified, list of error messages
_, files_modified, _ = run(gitcmd)
# We only want to pass ignore and max_complexity if they differ from the
# defaults so that we don't override a local configuration file
options = {}
if ignore:
options['ignore'] = ignore
if complexity > -1:
options['max_complexity'] = complexity
tmpdir = tempfile.mkdtemp()
flake8_style = get_style_guide(paths=['.'], **options)
filepatterns = flake8_style.options.filename
# Copy staged versions to temporary directory
files_to_check = []
try:
for file_ in files_modified:
# get the staged version of the file
gitcmd_getstaged = "git show :%s" % file_
_, out, _ = run(gitcmd_getstaged, raw_output=True, decode=False)
# write the staged version to temp dir with its full path to
# avoid overwriting files with the same name
dirname, filename = os.path.split(os.path.abspath(file_))
prefix = os.path.commonprefix([dirname, tmpdir])
dirname = compat.relpath(dirname, start=prefix)
dirname = os.path.join(tmpdir, dirname)
if not os.path.isdir(dirname):
os.makedirs(dirname)
# check_files() only does this check if passed a dir; so we do it
if ((pep8.filename_match(file_, filepatterns) and
not flake8_style.excluded(file_))):
filename = os.path.join(dirname, filename)
files_to_check.append(filename)
# write staged version of file to temporary directory
with open(filename, "wb") as fh:
fh.write(out)
# Run the checks
report = flake8_style.check_files(files_to_check)
# remove temporary directory
finally:
shutil.rmtree(tmpdir, ignore_errors=True)
if strict:
return report.total_errors
return 0
def hg_hook(ui, repo, **kwargs):
"""This is the function executed directly by Mercurial as part of the
hook. This is never called directly by the user, so the parameters are
undocumented. If you would like to learn more about them, please feel free
to read the official Mercurial documentation.
"""
complexity = ui.config('flake8', 'complexity', default=-1)
strict = ui.configbool('flake8', 'strict', default=True)
ignore = ui.config('flake8', 'ignore', default=None)
config = ui.config('flake8', 'config', default=None)
paths = _get_files(repo, **kwargs)
# We only want to pass ignore and max_complexity if they differ from the
# defaults so that we don't override a local configuration file
options = {}
if ignore:
options['ignore'] = ignore
if complexity > -1:
options['max_complexity'] = complexity
flake8_style = get_style_guide(config_file=config, paths=['.'],
**options)
report = flake8_style.check_files(paths)
if strict:
return report.total_errors
return 0
def run(command, raw_output=False, decode=True):
p = Popen(command.split(), stdout=PIPE, stderr=PIPE)
(stdout, stderr) = p.communicate()
# On python 3, subprocess.Popen returns bytes objects which expect
# endswith to be given a bytes object or a tuple of bytes but not native
# string objects. This is simply less mysterious than using b'.py' in the
# endswith method. That should work but might still fail horribly.
if decode:
if hasattr(stdout, 'decode'):
stdout = stdout.decode('utf-8')
if hasattr(stderr, 'decode'):
stderr = stderr.decode('utf-8')
if not raw_output:
stdout = [line.strip() for line in stdout.splitlines()]
stderr = [line.strip() for line in stderr.splitlines()]
return (p.returncode, stdout, stderr)
def _get_files(repo, **kwargs):
seen = set()
for rev in range(repo[kwargs['node']], len(repo)):
for file_ in repo[rev].files():
file_ = os.path.join(repo.root, file_)
if file_ in seen or not os.path.exists(file_):
continue
seen.add(file_)
if file_.endswith('.py'):
yield file_
def find_vcs():
try:
_, git_dir, _ = run('git rev-parse --git-dir')
except OSError:
pass
else:
if git_dir and os.path.isdir(git_dir[0]):
if not os.path.isdir(os.path.join(git_dir[0], 'hooks')):
os.mkdir(os.path.join(git_dir[0], 'hooks'))
return os.path.join(git_dir[0], 'hooks', 'pre-commit')
try:
_, hg_dir, _ = run('hg root')
except OSError:
pass
else:
if hg_dir and os.path.isdir(hg_dir[0]):
return os.path.join(hg_dir[0], '.hg', 'hgrc')
return ''
def get_git_config(option, opt_type='', convert_type=True):
# type can be --bool, --int or an empty string
_, git_cfg_value, _ = run('git config --get %s %s' % (opt_type, option),
raw_output=True)
git_cfg_value = git_cfg_value.strip()
if not convert_type:
return git_cfg_value
if opt_type == '--bool':
git_cfg_value = git_cfg_value.lower() == 'true'
elif git_cfg_value and opt_type == '--int':
git_cfg_value = int(git_cfg_value)
return git_cfg_value
_params = {
'FLAKE8_COMPLEXITY': '--int',
'FLAKE8_STRICT': '--bool',
'FLAKE8_IGNORE': '',
'FLAKE8_LAZY': '--bool',
}
def get_git_param(option, default=''):
global _params
opt_type = _params[option]
param_value = get_git_config(option.lower().replace('_', '.'),
opt_type=opt_type, convert_type=False)
if param_value == '':
param_value = os.environ.get(option, default)
if opt_type == '--bool' and not isinstance(param_value, bool):
param_value = param_value.lower() == 'true'
elif param_value and opt_type == '--int':
param_value = int(param_value)
return param_value
git_hook_file = """#!/usr/bin/env python
import sys
from flake8.hooks import git_hook, get_git_param
# `get_git_param` will retrieve configuration from your local git config and
# then fall back to using the environment variables that the hook has always
# supported.
# For example, to set the complexity, you'll need to do:
# git config flake8.complexity 10
COMPLEXITY = get_git_param('FLAKE8_COMPLEXITY', 10)
STRICT = get_git_param('FLAKE8_STRICT', False)
IGNORE = get_git_param('FLAKE8_IGNORE', None)
LAZY = get_git_param('FLAKE8_LAZY', False)
if __name__ == '__main__':
sys.exit(git_hook(
complexity=COMPLEXITY,
strict=STRICT,
ignore=IGNORE,
lazy=LAZY,
))
"""
def _install_hg_hook(path):
getenv = os.environ.get
if not os.path.isfile(path):
# Make the file so we can avoid IOError's
open(path, 'w').close()
c = ConfigParser()
c.readfp(open(path, 'r'))
if not c.has_section('hooks'):
c.add_section('hooks')
if not c.has_option('hooks', 'commit'):
c.set('hooks', 'commit', 'python:flake8.hooks.hg_hook')
if not c.has_option('hooks', 'qrefresh'):
c.set('hooks', 'qrefresh', 'python:flake8.hooks.hg_hook')
if not c.has_section('flake8'):
c.add_section('flake8')
if not c.has_option('flake8', 'complexity'):
c.set('flake8', 'complexity', str(getenv('FLAKE8_COMPLEXITY', 10)))
if not c.has_option('flake8', 'strict'):
c.set('flake8', 'strict', getenv('FLAKE8_STRICT', False))
if not c.has_option('flake8', 'ignore'):
c.set('flake8', 'ignore', getenv('FLAKE8_IGNORE', ''))
if not c.has_option('flake8', 'lazy'):
c.set('flake8', 'lazy', getenv('FLAKE8_LAZY', False))
with open(path, 'w') as fd:
c.write(fd)
def install_hook():
vcs = find_vcs()
if not vcs:
p = get_parser()[0]
sys.stderr.write('Error: could not find either a git or mercurial '
'directory. Please re-run this in a proper '
'repository.\n')
p.print_help()
sys.exit(1)
status = 0
if 'git' in vcs:
if os.path.exists(vcs):
sys.exit('Error: hook already exists (%s)' % vcs)
with open(vcs, 'w') as fd:
fd.write(git_hook_file)
# rwxr--r--
os.chmod(vcs, stat.S_IRWXU | stat.S_IRGRP | stat.S_IROTH)
elif 'hg' in vcs:
_install_hg_hook(vcs)
else:
status = 1
sys.exit(status)

View file

@ -1,141 +0,0 @@
# -*- coding: utf-8 -*-
import os
import re
import sys
import pycodestyle as pep8
import setuptools
from flake8.engine import get_parser, get_style_guide
from flake8.util import option_normalizer
if sys.platform.startswith('win'):
USER_CONFIG = os.path.expanduser(r'~\.flake8')
else:
USER_CONFIG = os.path.join(
os.getenv('XDG_CONFIG_HOME') or os.path.expanduser('~/.config'),
'flake8'
)
pep8.USER_CONFIG = USER_CONFIG
EXTRA_IGNORE = []
def main():
"""Parse options and run checks on Python source."""
# Prepare
flake8_style = get_style_guide(parse_argv=True)
options = flake8_style.options
if options.install_hook:
from flake8.hooks import install_hook
install_hook()
# Run the checkers
report = flake8_style.check_files()
exit_code = print_report(report, flake8_style)
if exit_code > 0:
raise SystemExit(exit_code > 0)
def print_report(report, flake8_style):
# Print the final report
options = flake8_style.options
if options.statistics:
report.print_statistics()
if options.benchmark:
report.print_benchmark()
if report.total_errors:
if options.count:
sys.stderr.write(str(report.total_errors) + '\n')
if not options.exit_zero:
return 1
return 0
def check_file(path, ignore=(), complexity=-1):
"""Checks a file using pep8 and pyflakes by default and mccabe
optionally.
:param str path: path to the file to be checked
:param tuple ignore: (optional), error and warning codes to be ignored
:param int complexity: (optional), enables the mccabe check for values > 0
"""
ignore = set(ignore).union(EXTRA_IGNORE)
flake8_style = get_style_guide(ignore=ignore, max_complexity=complexity)
return flake8_style.input_file(path)
def check_code(code, ignore=(), complexity=-1):
"""Checks code using pep8 and pyflakes by default and mccabe optionally.
:param str code: code to be checked
:param tuple ignore: (optional), error and warning codes to be ignored
:param int complexity: (optional), enables the mccabe check for values > 0
"""
ignore = set(ignore).union(EXTRA_IGNORE)
flake8_style = get_style_guide(ignore=ignore, max_complexity=complexity)
return flake8_style.input_file(None, lines=code.splitlines(True))
class Flake8Command(setuptools.Command):
"""The :class:`Flake8Command` class is used by setuptools to perform
checks on registered modules.
"""
description = "Run flake8 on modules registered in setuptools"
user_options = []
def initialize_options(self):
self.option_to_cmds = {}
parser = get_parser()[0]
for opt in parser.option_list:
cmd_name = opt._long_opts[0][2:]
option_name = cmd_name.replace('-', '_')
self.option_to_cmds[option_name] = opt
setattr(self, option_name, None)
def finalize_options(self):
self.options_dict = {}
for (option_name, opt) in self.option_to_cmds.items():
if option_name in ['help', 'verbose']:
continue
value = getattr(self, option_name)
if value is None:
continue
value = option_normalizer(value, opt, option_name)
# Check if there's any values that need to be fixed.
if option_name == "include" and isinstance(value, str):
value = re.findall('[^,;\s]+', value)
self.options_dict[option_name] = value
def distribution_files(self):
if self.distribution.packages:
package_dirs = self.distribution.package_dir or {}
for package in self.distribution.packages:
pkg_dir = package
if package in package_dirs:
pkg_dir = package_dirs[package]
elif '' in package_dirs:
pkg_dir = package_dirs[''] + os.path.sep + pkg_dir
yield pkg_dir.replace('.', os.path.sep)
if self.distribution.py_modules:
for filename in self.distribution.py_modules:
yield "%s.py" % filename
# Don't miss the setup.py file itself
yield "setup.py"
def run(self):
# Prepare
paths = list(self.distribution_files())
flake8_style = get_style_guide(paths=paths, **self.options_dict)
# Run the checkers
report = flake8_style.check_files()
exit_code = print_report(report, flake8_style)
if exit_code > 0:
raise SystemExit(exit_code > 0)

View file

@ -1,152 +0,0 @@
# -*- coding: utf-8 -*-
# Adapted from a contribution of Johan Dahlin
import collections
import errno
import re
import sys
try:
import multiprocessing
except ImportError: # Python 2.5
multiprocessing = None
import pycodestyle as pep8
__all__ = ['multiprocessing', 'BaseQReport', 'QueueReport']
class BaseQReport(pep8.BaseReport):
"""Base Queue Report."""
_loaded = False # Windows support
# Reasoning for ignored error numbers is in-line below
ignored_errors = set([
# EPIPE: Added by sigmavirus24
# > If output during processing is piped to something that may close
# > its own stdin before we've finished printing results, we need to
# > catch a Broken pipe error and continue on.
# > (See also: https://gitlab.com/pycqa/flake8/issues/69)
errno.EPIPE,
# NOTE(sigmavirus24): When adding to this list, include the reasoning
# on the lines before the error code and always append your error
# code. Further, please always add a trailing `,` to reduce the visual
# noise in diffs.
])
def __init__(self, options):
assert options.jobs > 0
super(BaseQReport, self).__init__(options)
self.counters = collections.defaultdict(int)
self.n_jobs = options.jobs
# init queues
self.task_queue = multiprocessing.Queue()
self.result_queue = multiprocessing.Queue()
if sys.platform == 'win32':
# Work around http://bugs.python.org/issue10845
sys.modules['__main__'].__file__ = __file__
def _cleanup_queue(self, queue):
while not queue.empty():
queue.get_nowait()
def _put_done(self):
# collect queues
for i in range(self.n_jobs):
self.task_queue.put('DONE')
self.update_state(self.result_queue.get())
def _process_main(self):
if not self._loaded:
# Windows needs to parse again the configuration
from flake8.main import get_style_guide
get_style_guide(parse_argv=True)
for filename in iter(self.task_queue.get, 'DONE'):
self.input_file(filename)
def start(self):
super(BaseQReport, self).start()
self.__class__._loaded = True
# spawn processes
for i in range(self.n_jobs):
p = multiprocessing.Process(target=self.process_main)
p.daemon = True
p.start()
def stop(self):
try:
self._put_done()
except KeyboardInterrupt:
pass
finally:
# cleanup queues to unlock threads
self._cleanup_queue(self.result_queue)
self._cleanup_queue(self.task_queue)
super(BaseQReport, self).stop()
def process_main(self):
try:
self._process_main()
except KeyboardInterrupt:
pass
except IOError as ioerr:
# If we happen across an IOError that we aren't certain can/should
# be ignored, we should re-raise the exception.
if ioerr.errno not in self.ignored_errors:
raise
finally:
# ensure all output is flushed before main process continues
sys.stdout.flush()
sys.stderr.flush()
self.result_queue.put(self.get_state())
def get_state(self):
return {'total_errors': self.total_errors,
'counters': self.counters,
'messages': self.messages}
def update_state(self, state):
self.total_errors += state['total_errors']
for key, value in state['counters'].items():
self.counters[key] += value
self.messages.update(state['messages'])
class FileQReport(BaseQReport):
"""File Queue Report."""
print_filename = True
class QueueReport(pep8.StandardReport, BaseQReport):
"""Standard Queue Report."""
def get_file_results(self):
"""Print the result and return the overall count for this file."""
self._deferred_print.sort()
for line_number, offset, code, text, doc in self._deferred_print:
print(self._fmt % {
'path': self.filename,
'row': self.line_offset + line_number, 'col': offset + 1,
'code': code, 'text': text,
})
# stdout is block buffered when not stdout.isatty().
# line can be broken where buffer boundary since other processes
# write to same file.
# flush() after print() to avoid buffer boundary.
# Typical buffer size is 8192. line written safely when
# len(line) < 8192.
sys.stdout.flush()
if self._show_source:
if line_number > len(self.lines):
line = ''
else:
line = self.lines[line_number - 1]
print(line.rstrip())
sys.stdout.flush()
print(re.sub(r'\S', ' ', line[:offset]) + '^')
sys.stdout.flush()
if self._show_pep8 and doc:
print(' ' + doc.strip())
sys.stdout.flush()
return self.file_errors

View file

@ -1,11 +0,0 @@
"""
Implementation of the command-line I{flake8} tool.
"""
from flake8.hooks import git_hook, hg_hook # noqa
from flake8.main import check_code, check_file, Flake8Command # noqa
from flake8.main import main
if __name__ == '__main__':
main()

View file

@ -1 +0,0 @@
#

View file

@ -1,309 +0,0 @@
"""
_test_warnings.py
Tests for the warnings that are emitted by flake8.
This module is named _test_warnings instead of test_warnings so that a
normal nosetests run does not collect it. The tests in this module pass
when they are run alone, but they fail when they are run along with other
tests (nosetests --with-isolation doesn't help).
In tox.ini, these tests are run separately.
"""
from __future__ import with_statement
import os
import warnings
import unittest
try:
from unittest import mock
except ImportError:
import mock # < PY33
from flake8 import engine
from flake8.util import is_windows
# The Problem
# ------------
#
# Some of the tests in this module pass when this module is run on its own, but
# they fail when this module is run as part of the whole test suite. These are
# the problematic tests:
#
# test_jobs_verbose
# test_stdin_jobs_warning
#
# On some platforms, the warnings.capture_warnings function doesn't work
# properly when run with the other flake8 tests. It drops some warnings, even
# though the warnings filter is set to 'always'. However, when run separately,
# these tests pass.
#
# This problem only occurs on Windows, with Python 3.3 and older. Maybe it's
# related to PEP 446 - Inheritable file descriptors?
#
#
#
#
# Things that didn't work
# ------------
#
# Nose --attr
# I tried using the nosetests --attr feature to run the tests separately. I
# put the following in setup.cfg
#
# [nosetests]
# atttr=!run_alone
#
# Then I added a tox section thst did this
#
# nosetests --attr=run_alone
#
# However, the command line --attr would not override the config file --attr,
# so the special tox section wound up runing all the tests, and failing.
#
#
#
# Nose --with-isolation
# The nosetests --with-isolation flag did not help.
#
#
#
# unittest.skipIf
# I tried decorating the problematic tests with the unittest.skipIf
# decorator.
#
# @unittest.skipIf(is_windows() and sys.version_info < (3, 4),
# "Fails on Windows with Python < 3.4 when run with other"
# " tests.")
#
# The idea is, skip the tests in the main test run, on affected platforms.
# Then, only on those platforms, come back in later and run the tests
# separately.
#
# I added a new stanza to tox.ini, to run the tests separately on the
# affected platforms.
#
# nosetests --no-skip
#
# I ran in to a bug in the nosetests skip plugin. It would report the test as
# having been run, but it would not actually run the test. So, when run with
# --no-skip, the following test would be reported as having run and passed!
#
# @unittest.skip("This passes o_o")
# def test_should_fail(self):
# assert 0
#
# This bug has been reported here:
# "--no-skip broken with Python 2.7"
# https://github.com/nose-devs/nose/issues/512
#
#
#
# py.test
#
# I tried using py.test, and its @pytest.mark.xfail decorator. I added some
# separate stanzas in tox, and useing the pytest --runxfail option to run the
# tests separately. This allows us to run all the tests together, on
# platforms that allow it. On platforms that don't allow us to run the tests
# all together, this still runs all the tests, but in two separate steps.
#
# This is the same solution as the nosetests --no-skip solution I described
# above, but --runxfail does not have the same bug as --no-skip.
#
# This has the advantage that all tests are discoverable by default, outside
# of tox. However, nose does not recognize the pytest.mark.xfail decorator.
# So, if a user runs nosetests, it still tries to run the problematic tests
# together with the rest of the test suite, causing them to fail.
#
#
#
#
#
#
# Solution
# ------------
# Move the problematic tests to _test_warnings.py, so nose.collector will not
# find them. Set up a separate section in tox.ini that runs this:
#
# nosetests flake8.tests._test_warnings
#
# This allows all tests to pass on all platforms, when run through tox.
# However, it means that, even on unaffected platforms, the problematic tests
# are not discovered and run outside of tox (if the user just runs nosetests
# manually, for example).
class IntegrationTestCaseWarnings(unittest.TestCase):
"""Integration style tests to check that warnings are issued properly for
different command line options."""
windows_warning_text = ("The --jobs option is not available on Windows."
" Ignoring --jobs arguments.")
stdin_warning_text = ("The --jobs option is not compatible with"
" supplying input using - . Ignoring --jobs"
" arguments.")
def this_file(self):
"""Return the real path of this file."""
this_file = os.path.realpath(__file__)
if this_file.endswith("pyc"):
this_file = this_file[:-1]
return this_file
@staticmethod
def get_style_guide_with_warnings(engine, *args, **kwargs):
"""
Return a style guide object (obtained by calling
engine.get_style_guide) and a list of the warnings that were raised in
the process.
Note: not threadsafe
"""
# Note
# https://docs.python.org/2/library/warnings.html
#
# The catch_warnings manager works by replacing and then later
# restoring the module's showwarning() function and internal list of
# filter specifications. This means the context manager is modifying
# global state and therefore is not thread-safe
with warnings.catch_warnings(record=True) as collected_warnings:
# Cause all warnings to always be triggered.
warnings.simplefilter("always")
# Get the style guide
style_guide = engine.get_style_guide(*args, **kwargs)
# Now that the warnings have been collected, return the style guide and
# the warnings.
return (style_guide, collected_warnings)
def verify_warnings(self, collected_warnings, expected_warnings):
"""
Verifies that collected_warnings is a sequence that contains user
warnings that match the sequence of string values passed in as
expected_warnings.
"""
if expected_warnings is None:
expected_warnings = []
collected_user_warnings = [w for w in collected_warnings
if issubclass(w.category, UserWarning)]
self.assertEqual(len(collected_user_warnings),
len(expected_warnings))
collected_warnings_set = set(str(warning.message)
for warning
in collected_user_warnings)
expected_warnings_set = set(expected_warnings)
self.assertEqual(collected_warnings_set, expected_warnings_set)
def check_files_collect_warnings(self,
arglist=[],
explicit_stdin=False,
count=0,
verbose=False):
"""Call check_files and collect any warnings that are issued."""
if verbose:
arglist.append('--verbose')
if explicit_stdin:
target_file = "-"
else:
target_file = self.this_file()
argv = ['flake8'] + arglist + [target_file]
with mock.patch("sys.argv", argv):
(style_guide,
collected_warnings,
) = self.get_style_guide_with_warnings(engine,
parse_argv=True)
report = style_guide.check_files()
self.assertEqual(report.total_errors, count)
return style_guide, report, collected_warnings
def check_files_no_warnings_allowed(self,
arglist=[],
explicit_stdin=False,
count=0,
verbose=False):
"""Call check_files, and assert that there were no warnings issued."""
(style_guide,
report,
collected_warnings,
) = self.check_files_collect_warnings(arglist=arglist,
explicit_stdin=explicit_stdin,
count=count,
verbose=verbose)
self.verify_warnings(collected_warnings, expected_warnings=None)
return style_guide, report
def _job_tester(self, jobs, verbose=False):
# mock stdout.flush so we can count the number of jobs created
with mock.patch('sys.stdout.flush') as mocked:
(guide,
report,
collected_warnings,
) = self.check_files_collect_warnings(
arglist=['--jobs=%s' % jobs],
verbose=verbose)
if is_windows():
# The code path where guide.options.jobs gets converted to an
# int is not run on windows. So, do the int conversion here.
self.assertEqual(int(guide.options.jobs), jobs)
# On windows, call count is always zero.
self.assertEqual(mocked.call_count, 0)
else:
self.assertEqual(guide.options.jobs, jobs)
self.assertEqual(mocked.call_count, jobs)
expected_warings = []
if verbose and is_windows():
expected_warings.append(self.windows_warning_text)
self.verify_warnings(collected_warnings, expected_warings)
def test_jobs(self, verbose=False):
self._job_tester(2, verbose=verbose)
self._job_tester(10, verbose=verbose)
def test_no_args_no_warnings(self, verbose=False):
self.check_files_no_warnings_allowed(verbose=verbose)
def test_stdin_jobs_warning(self, verbose=False):
self.count = 0
def fake_stdin():
self.count += 1
with open(self.this_file(), "r") as f:
return f.read()
with mock.patch("pycodestyle.stdin_get_value", fake_stdin):
(style_guide,
report,
collected_warnings,
) = self.check_files_collect_warnings(arglist=['--jobs=4'],
explicit_stdin=True,
verbose=verbose)
expected_warings = []
if verbose:
expected_warings.append(self.stdin_warning_text)
if is_windows():
expected_warings.append(self.windows_warning_text)
self.verify_warnings(collected_warnings, expected_warings)
self.assertEqual(self.count, 1)
def test_jobs_verbose(self):
self.test_jobs(verbose=True)
def test_no_args_no_warnings_verbose(self):
self.test_no_args_no_warnings(verbose=True)
def test_stdin_jobs_warning_verbose(self):
self.test_stdin_jobs_warning(verbose=True)
if __name__ == '__main__':
unittest.main()

View file

@ -1,236 +0,0 @@
from __future__ import with_statement
import errno
import unittest
try:
from unittest import mock
except ImportError:
import mock # < PY33
from flake8 import engine, util, __version__, reporter
import pycodestyle as pep8
class TestEngine(unittest.TestCase):
def setUp(self):
self.patches = {}
def tearDown(self):
assert len(self.patches.items()) == 0
def start_patch(self, patch):
self.patches[patch] = mock.patch(patch)
return self.patches[patch].start()
def stop_patches(self):
patches = self.patches.copy()
for k, v in patches.items():
v.stop()
del(self.patches[k])
def test_get_style_guide(self):
with mock.patch('flake8.engine._register_extensions') as reg_ext:
reg_ext.return_value = ([], [], [], [])
g = engine.get_style_guide()
self.assertTrue(isinstance(g, engine.StyleGuide))
reg_ext.assert_called_once_with()
def test_get_style_guide_kwargs(self):
m = mock.Mock()
with mock.patch('flake8.engine.StyleGuide') as StyleGuide:
with mock.patch('flake8.engine.get_parser') as get_parser:
m.ignored_extensions = []
StyleGuide.return_value.options.jobs = '42'
StyleGuide.return_value.options.diff = False
get_parser.return_value = (m, [])
engine.get_style_guide(foo='bar')
get_parser.assert_called_once_with()
StyleGuide.assert_called_once_with(**{'parser': m, 'foo': 'bar'})
def test_register_extensions(self):
with mock.patch('pycodestyle.register_check') as register_check:
registered_exts = engine._register_extensions()
self.assertTrue(isinstance(registered_exts[0], util.OrderedSet))
self.assertTrue(len(registered_exts[0]) > 0)
for i in registered_exts[1:]:
self.assertTrue(isinstance(i, list))
self.assertTrue(register_check.called)
def test_disable_extensions(self):
parser = mock.MagicMock()
options = mock.MagicMock()
parser.ignored_extensions = ['I123', 'I345', 'I678', 'I910']
options.enable_extensions = 'I345,\nI678,I910'
options.ignore = ('E121', 'E123')
engine._disable_extensions(parser, options)
self.assertEqual(set(options.ignore), set(['E121', 'E123', 'I123']))
def test_get_parser(self):
# setup
re = self.start_patch('flake8.engine._register_extensions')
gpv = self.start_patch('flake8.engine.get_python_version')
pgp = self.start_patch('pycodestyle.get_parser')
m = mock.Mock()
re.return_value = ([('pyflakes', '0.7'), ('mccabe', '0.2')], [], [],
[])
gpv.return_value = 'Python Version'
pgp.return_value = m
# actual call we're testing
parser, hooks = engine.get_parser()
# assertions
self.assertTrue(re.called)
self.assertTrue(gpv.called)
pgp.assert_called_once_with(
'flake8',
'%s (pyflakes: 0.7, mccabe: 0.2) Python Version' % __version__)
self.assertTrue(m.remove_option.called)
self.assertTrue(m.add_option.called)
self.assertEqual(parser, m)
self.assertEqual(hooks, [])
# clean-up
self.stop_patches()
def test_get_python_version(self):
self.assertTrue('on' in engine.get_python_version())
# Silly test but it will provide 100% test coverage
# Also we can never be sure (without reconstructing the string
# ourselves) what system we may be testing on.
def test_windows_disables_jobs(self):
with mock.patch('flake8.util.is_windows') as is_windows:
is_windows.return_value = True
guide = engine.get_style_guide()
assert isinstance(guide, reporter.BaseQReport) is False
def test_stdin_disables_jobs(self):
with mock.patch('flake8.util.is_using_stdin') as is_using_stdin:
is_using_stdin.return_value = True
guide = engine.get_style_guide()
assert isinstance(guide, reporter.BaseQReport) is False
def test_disables_extensions_that_are_not_selected(self):
with mock.patch('flake8.engine._register_extensions') as re:
re.return_value = ([('fake_ext', '0.1a1')], [], [], ['X'])
sg = engine.get_style_guide()
assert 'X' in sg.options.ignore
def test_enables_off_by_default_extensions(self):
with mock.patch('flake8.engine._register_extensions') as re:
re.return_value = ([('fake_ext', '0.1a1')], [], [], ['X'])
parser, options = engine.get_parser()
parser.parse_args(['--select=X'])
sg = engine.StyleGuide(parser=parser)
assert 'X' not in sg.options.ignore
def test_load_entry_point_verifies_requirements(self):
entry_point = mock.Mock(spec=['require', 'resolve', 'load'])
engine._load_entry_point(entry_point, verify_requirements=True)
entry_point.require.assert_called_once_with()
entry_point.resolve.assert_called_once_with()
def test_load_entry_point_does_not_verify_requirements(self):
entry_point = mock.Mock(spec=['require', 'resolve', 'load'])
engine._load_entry_point(entry_point, verify_requirements=False)
self.assertFalse(entry_point.require.called)
entry_point.resolve.assert_called_once_with()
def test_load_entry_point_passes_require_argument_to_load(self):
entry_point = mock.Mock(spec=['load'])
engine._load_entry_point(entry_point, verify_requirements=True)
entry_point.load.assert_called_once_with(require=True)
entry_point.reset_mock()
engine._load_entry_point(entry_point, verify_requirements=False)
entry_point.load.assert_called_once_with(require=False)
def oserror_generator(error_number, message='Ominous OSError message'):
def oserror_side_effect(*args, **kwargs):
if hasattr(oserror_side_effect, 'used'):
return
oserror_side_effect.used = True
raise OSError(error_number, message)
return oserror_side_effect
class TestStyleGuide(unittest.TestCase):
def setUp(self):
mocked_styleguide = mock.Mock(spec=engine.NoQAStyleGuide)
self.styleguide = engine.StyleGuide(styleguide=mocked_styleguide)
self.mocked_sg = mocked_styleguide
def test_proxies_excluded(self):
self.styleguide.excluded('file.py', parent='.')
self.mocked_sg.excluded.assert_called_once_with('file.py', parent='.')
def test_proxies_init_report(self):
reporter = object()
self.styleguide.init_report(reporter)
self.mocked_sg.init_report.assert_called_once_with(reporter)
def test_proxies_check_files(self):
self.styleguide.check_files(['foo', 'bar'])
self.mocked_sg.check_files.assert_called_once_with(
paths=['foo', 'bar']
)
def test_proxies_input_file(self):
self.styleguide.input_file('file.py',
lines=[9, 10],
expected='foo',
line_offset=20)
self.mocked_sg.input_file.assert_called_once_with(filename='file.py',
lines=[9, 10],
expected='foo',
line_offset=20)
def test_check_files_retries_on_specific_OSErrors(self):
self.mocked_sg.check_files.side_effect = oserror_generator(
errno.ENOSPC, 'No space left on device'
)
self.styleguide.check_files(['foo', 'bar'])
self.mocked_sg.init_report.assert_called_once_with(pep8.StandardReport)
def test_input_file_retries_on_specific_OSErrors(self):
self.mocked_sg.input_file.side_effect = oserror_generator(
errno.ENOSPC, 'No space left on device'
)
self.styleguide.input_file('file.py')
self.mocked_sg.init_report.assert_called_once_with(pep8.StandardReport)
def test_check_files_reraises_unknown_OSErrors(self):
self.mocked_sg.check_files.side_effect = oserror_generator(
errno.EADDRINUSE,
'lol why are we talking about binding to sockets'
)
self.assertRaises(OSError, self.styleguide.check_files,
['foo', 'bar'])
def test_input_file_reraises_unknown_OSErrors(self):
self.mocked_sg.input_file.side_effect = oserror_generator(
errno.EADDRINUSE,
'lol why are we talking about binding to sockets'
)
self.assertRaises(OSError, self.styleguide.input_file,
['foo', 'bar'])
if __name__ == '__main__':
unittest.main()

View file

@ -1,59 +0,0 @@
"""Module containing the tests for flake8.hooks."""
import os
import unittest
try:
from unittest import mock
except ImportError:
import mock
import flake8.hooks
from flake8.util import is_windows
def excluded(filename):
return filename.endswith('afile.py')
class TestGitHook(unittest.TestCase):
if is_windows:
# On Windows, absolute paths start with a drive letter, for example C:
# Here we build a fake absolute path starting with the current drive
# letter, for example C:\fake\temp
current_drive, ignore_tail = os.path.splitdrive(os.getcwd())
fake_abs_path = os.path.join(current_drive, os.path.sep, 'fake', 'tmp')
else:
fake_abs_path = os.path.join(os.path.sep, 'fake', 'tmp')
@mock.patch('os.makedirs')
@mock.patch('flake8.hooks.open', create=True)
@mock.patch('shutil.rmtree')
@mock.patch('tempfile.mkdtemp', return_value=fake_abs_path)
@mock.patch('flake8.hooks.run',
return_value=(None,
[os.path.join('foo', 'afile.py'),
os.path.join('foo', 'bfile.py')],
None))
@mock.patch('flake8.hooks.get_style_guide')
def test_prepends_tmp_directory_to_exclude(self, get_style_guide, run,
*args):
style_guide = get_style_guide.return_value = mock.Mock()
style_guide.options.exclude = [os.path.join('foo', 'afile.py')]
style_guide.options.filename = [os.path.join('foo', '*')]
style_guide.excluded = excluded
flake8.hooks.git_hook()
dirname, filename = os.path.split(
os.path.abspath(os.path.join('foo', 'bfile.py')))
if is_windows:
# In Windows, the absolute path in dirname will start with a drive
# letter. Here, we discad the drive letter.
ignore_drive, dirname = os.path.splitdrive(dirname)
tmpdir = os.path.join(self.fake_abs_path, dirname[1:])
tmpfile = os.path.join(tmpdir, 'bfile.py')
style_guide.check_files.assert_called_once_with([tmpfile])
if __name__ == '__main__':
unittest.main()

View file

@ -1,79 +0,0 @@
from __future__ import with_statement
import os
import unittest
try:
from unittest import mock
except ImportError:
import mock # < PY33
from flake8 import engine
from flake8.util import is_windows
class IntegrationTestCase(unittest.TestCase):
"""Integration style tests to exercise different command line options."""
def this_file(self):
"""Return the real path of this file."""
this_file = os.path.realpath(__file__)
if this_file.endswith("pyc"):
this_file = this_file[:-1]
return this_file
def check_files(self, arglist=[], explicit_stdin=False, count=0):
"""Call check_files."""
if explicit_stdin:
target_file = "-"
else:
target_file = self.this_file()
argv = ['flake8'] + arglist + [target_file]
with mock.patch("sys.argv", argv):
style_guide = engine.get_style_guide(parse_argv=True)
report = style_guide.check_files()
self.assertEqual(report.total_errors, count)
return style_guide, report
def test_no_args(self):
# assert there are no reported errors
self.check_files()
def _job_tester(self, jobs):
# mock stdout.flush so we can count the number of jobs created
with mock.patch('sys.stdout.flush') as mocked:
guide, report = self.check_files(arglist=['--jobs=%s' % jobs])
if is_windows():
# The code path where guide.options.jobs gets converted to an
# int is not run on windows. So, do the int conversion here.
self.assertEqual(int(guide.options.jobs), jobs)
# On windows, call count is always zero.
self.assertEqual(mocked.call_count, 0)
else:
self.assertEqual(guide.options.jobs, jobs)
self.assertEqual(mocked.call_count, jobs)
def test_jobs(self):
self._job_tester(2)
self._job_tester(10)
def test_stdin(self):
self.count = 0
def fake_stdin():
self.count += 1
with open(self.this_file(), "r") as f:
return f.read()
with mock.patch("pycodestyle.stdin_get_value", fake_stdin):
guide, report = self.check_files(arglist=['--jobs=4'],
explicit_stdin=True)
self.assertEqual(self.count, 1)
def test_stdin_fail(self):
def fake_stdin():
return "notathing\n"
with mock.patch("pycodestyle.stdin_get_value", fake_stdin):
# only assert needed is in check_files
guide, report = self.check_files(arglist=['--jobs=4'],
explicit_stdin=True,
count=1)

Some files were not shown because too many files have changed in this diff Show more