'\" t
.\" Man page generated from reStructuredText.
.
.
.nr rst2man-indent-level 0
.
.de1 rstReportMargin
\\$1 \\n[an-margin]
level \\n[rst2man-indent-level]
level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
-
\\n[rst2man-indent0]
\\n[rst2man-indent1]
\\n[rst2man-indent2]
..
.de1 INDENT
.\" .rstReportMargin pre:
. RS \\$1
. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
. nr rst2man-indent-level +1
.\" .rstReportMargin post:
..
.de UNINDENT
. RE
.\" indent \\n[an-margin]
.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
.nr rst2man-indent-level -1
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "FLASK-WTF" "1" "Dec 24, 2024" "1.2.x" "Flask-WTF"
.SH NAME
flask-wtf \- Flask-WTF 1.2.1
[image: Flask-WTF]
[image]
.sp
Simple integration of \X'tty: link https://www.palletsprojects.com/p/flask'\fI\%Flask\fP\X'tty: link' and \X'tty: link https://wtforms.readthedocs.io/'\fI\%WTForms\fP\X'tty: link', including CSRF, file upload,
and reCAPTCHA.
.SH FEATURES
.INDENT 0.0
.IP \(bu 2
Integration with WTForms.
.IP \(bu 2
Secure Form with CSRF token.
.IP \(bu 2
Global CSRF protection.
.IP \(bu 2
reCAPTCHA support.
.IP \(bu 2
File upload that works with Flask\-Uploads.
.IP \(bu 2
Internationalization using Flask\-Babel.
.UNINDENT
.SH USER'S GUIDE
.sp
This part of the documentation, which is mostly prose, begins with some
background information about Flask\-WTF, then focuses on step\-by\-step
instructions for getting the most out of Flask\-WTF.
.SS Installation
.sp
The \X'tty: link https://packaging.python.org/current/'\fI\%Python Packaging Guide\fP\X'tty: link' contains general information about how to manage
your project and dependencies.
.SS Released version
.sp
Install or upgrade using pip.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
pip install \-U Flask\-WTF
.EE
.UNINDENT
.UNINDENT
.SS Development
.sp
The latest code is available from \X'tty: link https://github.com/wtforms/flask-wtf'\fI\%GitHub\fP\X'tty: link'\&. Clone the repository then install
using pip.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
git clone https://github.com/wtforms/flask\-wtf
pip install \-e ./flask\-wtf
.EE
.UNINDENT
.UNINDENT
.sp
Or install the latest build from an \X'tty: link https://github.com/wtforms/flask-wtf/archive/main.tar.gz'\fI\%archive\fP\X'tty: link'\&.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
pip install \-U https://github.com/wtforms/flask\-wtf/archive/main.tar.gz
.EE
.UNINDENT
.UNINDENT
.SS Quickstart
.sp
Eager to get started? This page gives a good introduction to Flask\-WTF.
It assumes you already have Flask\-WTF installed. If you do not, head over
to the \fI\%Installation\fP section.
.SS Creating Forms
.sp
Flask\-WTF provides your Flask application integration with WTForms. For example:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
from flask_wtf import FlaskForm
from wtforms import StringField
from wtforms.validators import DataRequired
class MyForm(FlaskForm):
name = StringField(\(aqname\(aq, validators=[DataRequired()])
.EE
.UNINDENT
.UNINDENT
.sp
\fBNOTE:\fP
.INDENT 0.0
.INDENT 3.5
From version 0.9.0, Flask\-WTF will not import anything from wtforms,
you need to import fields from wtforms.
.UNINDENT
.UNINDENT
.sp
In addition, a CSRF token hidden field is created automatically. You can
render this in your template:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
.EE
.UNINDENT
.UNINDENT
.sp
If your form has multiple hidden fields, you can render them in one
block using \fBhidden_tag()\fP\&.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
.EE
.UNINDENT
.UNINDENT
.SS Validating Forms
.sp
Validating the request in your view handlers:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
@app.route(\(aq/submit\(aq, methods=[\(aqGET\(aq, \(aqPOST\(aq])
def submit():
form = MyForm()
if form.validate_on_submit():
return redirect(\(aq/success\(aq)
return render_template(\(aqsubmit.html\(aq, form=form)
.EE
.UNINDENT
.UNINDENT
.sp
Note that you don\(aqt have to pass \fBrequest.form\fP to Flask\-WTF; it will
load automatically. And the convenient \fBvalidate_on_submit\fP will check
if it is a POST request and if it is valid.
.sp
If your forms include validation, you\(aqll need to add to your template to display
any error messages. Using the \fBform.name\fP field from the example above, that
would look like this:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
{% if form.name.errors %}
{% for error in form.name.errors %}
- {{ error }}
{% endfor %}
{% endif %}
.EE
.UNINDENT
.UNINDENT
.sp
Heading over to \fI\%Creating Forms\fP to learn more skills.
.SS Creating Forms
.SS Secure Form
.sp
Without any configuration, the \fBFlaskForm\fP will be a session secure
form with csrf protection. We encourage you not to change this.
.sp
But if you want to disable the csrf protection, you can pass:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
form = FlaskForm(meta={\(aqcsrf\(aq: False})
.EE
.UNINDENT
.UNINDENT
.sp
You can disable it globally—though you really shouldn\(aqt—with the
configuration:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
WTF_CSRF_ENABLED = False
.EE
.UNINDENT
.UNINDENT
.sp
In order to generate the csrf token, you must have a secret key, this
is usually the same as your Flask app secret key. If you want to use
another secret key, config it:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
WTF_CSRF_SECRET_KEY = \(aqa random string\(aq
.EE
.UNINDENT
.UNINDENT
.SS File Uploads
.sp
The \fBFileField\fP provided by Flask\-WTF differs from the WTForms\-provided
field. It will check that the file is a non\-empty instance of
\fBFileStorage\fP, otherwise \fBdata\fP will be
\fBNone\fP\&.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
from flask_wtf import FlaskForm
from flask_wtf.file import FileField, FileRequired
from werkzeug.utils import secure_filename
class PhotoForm(FlaskForm):
photo = FileField(validators=[FileRequired()])
@app.route(\(aq/upload\(aq, methods=[\(aqGET\(aq, \(aqPOST\(aq])
def upload():
form = PhotoForm()
if form.validate_on_submit():
f = form.photo.data
filename = secure_filename(f.filename)
f.save(os.path.join(
app.instance_path, \(aqphotos\(aq, filename
))
return redirect(url_for(\(aqindex\(aq))
return render_template(\(aqupload.html\(aq, form=form)
.EE
.UNINDENT
.UNINDENT
.sp
Similarly, you can use the \fBMultipleFileField\fP provided by Flask\-WTF
to handle multiple files. It will check that the files is a list of non\-empty instance of
\fBFileStorage\fP, otherwise \fBdata\fP will be
\fBNone\fP\&.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
from flask_wtf import FlaskForm
from flask_wtf.file import MultipleFileField, FileRequired
from werkzeug.utils import secure_filename
class PhotoForm(FlaskForm):
photos = MultipleFileField(validators=[FileRequired()])
@app.route(\(aq/upload\(aq, methods=[\(aqGET\(aq, \(aqPOST\(aq])
def upload():
form = PhotoForm()
if form.validate_on_submit():
for f in form.photo.data: # form.photo.data return a list of FileStorage object
filename = secure_filename(f.filename)
f.save(os.path.join(
app.instance_path, \(aqphotos\(aq, filename
))
return redirect(url_for(\(aqindex\(aq))
return render_template(\(aqupload.html\(aq, form=form)
.EE
.UNINDENT
.UNINDENT
.sp
Remember to set the \fBenctype\fP of the HTML form to
\fBmultipart/form\-data\fP, otherwise \fBrequest.files\fP will be empty.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
.EE
.UNINDENT
.UNINDENT
.sp
Flask\-WTF handles passing form data to the form for you.
If you pass in the data explicitly, remember that \fBrequest.form\fP must
be combined with \fBrequest.files\fP for the form to see the file data.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
form = PhotoForm()
# is equivalent to:
from flask import request
from werkzeug.datastructures import CombinedMultiDict
form = PhotoForm(CombinedMultiDict((request.files, request.form)))
.EE
.UNINDENT
.UNINDENT
.SS Validation
.sp
Flask\-WTF supports validating file uploads with
\fBFileRequired\fP, \fBFileAllowed\fP, and \fBFileSize\fP\&. They
can be used with both Flask\-WTF\(aqs and WTForms\(aqs \fBFileField\fP and
\fBMultipleFileField\fP classes.
.sp
\fBFileAllowed\fP works well with Flask\-Uploads.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
from flask_uploads import UploadSet, IMAGES
from flask_wtf import FlaskForm
from flask_wtf.file import FileField, FileAllowed, FileRequired
images = UploadSet(\(aqimages\(aq, IMAGES)
class UploadForm(FlaskForm):
upload = FileField(\(aqimage\(aq, validators=[
FileRequired(),
FileAllowed(images, \(aqImages only!\(aq)
])
.EE
.UNINDENT
.UNINDENT
.sp
It can be used without Flask\-Uploads by passing the extensions directly.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
class UploadForm(FlaskForm):
upload = FileField(\(aqimage\(aq, validators=[
FileRequired(),
FileAllowed([\(aqjpg\(aq, \(aqpng\(aq], \(aqImages only!\(aq)
])
.EE
.UNINDENT
.UNINDENT
.SS Recaptcha
.sp
Flask\-WTF also provides Recaptcha support through a \fBRecaptchaField\fP:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
from flask_wtf import FlaskForm, RecaptchaField
from wtforms import TextField
class SignupForm(FlaskForm):
username = TextField(\(aqUsername\(aq)
recaptcha = RecaptchaField()
.EE
.UNINDENT
.UNINDENT
.sp
This comes with a number of configuration variables, some of which you have to configure.
.TS
box center;
l|l.
T{
RECAPTCHA_PUBLIC_KEY
T} T{
\fBrequired\fP A public key.
T}
_
T{
RECAPTCHA_PRIVATE_KEY
T} T{
\fBrequired\fP A private key.
T}
_
T{
RECAPTCHA_API_SERVER
T} T{
\fBoptional\fP Specify your Recaptcha API server.
T}
_
T{
RECAPTCHA_PARAMETERS
T} T{
\fBoptional\fP A dict of JavaScript (api.js) parameters.
T}
_
T{
RECAPTCHA_DATA_ATTRS
T} T{
\fBoptional\fP A dict of data attributes options.
\X'tty: link https://developers.google.com/recaptcha/docs/display#javascript_resource_apijs_parameters'\fI\%https://developers.google.com/recaptcha/docs/display#javascript_resource_apijs_parameters\fP\X'tty: link'
T}
.TE
.sp
Example of RECAPTCHA_PARAMETERS, and RECAPTCHA_DATA_ATTRS:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
RECAPTCHA_PARAMETERS = {\(aqhl\(aq: \(aqzh\(aq, \(aqrender\(aq: \(aqexplicit\(aq}
RECAPTCHA_DATA_ATTRS = {\(aqtheme\(aq: \(aqdark\(aq}
.EE
.UNINDENT
.UNINDENT
.sp
For your convenience, when testing your application, if \fBapp.testing\fP is \fBTrue\fP, the recaptcha
field will always be valid.
.sp
And it can be easily setup in the templates:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
.EE
.UNINDENT
.UNINDENT
.sp
We have an example for you: \X'tty: link https://github.com/wtforms/flask-wtf/tree/main/examples/recaptcha'\fI\%recaptcha@github\fP\X'tty: link'\&.
.SS CSRF Protection
.sp
Any view using \fBFlaskForm\fP to process the request is already
getting CSRF protection. If you have views that don\(aqt use \fBFlaskForm\fP or make
AJAX requests, use the provided CSRF extension to protect those requests as
well.
.SS Setup
.sp
To enable CSRF protection globally for a Flask app, register the
\fBCSRFProtect\fP extension.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
from flask_wtf.csrf import CSRFProtect
csrf = CSRFProtect(app)
.EE
.UNINDENT
.UNINDENT
.sp
Like other Flask extensions, you can apply it lazily:
.INDENT 0.0
.INDENT 3.5
.sp
.EX
csrf = CSRFProtect()
def create_app():
app = Flask(__name__)
csrf.init_app(app)
.EE
.UNINDENT
.UNINDENT
.sp
\fBNOTE:\fP
.INDENT 0.0
.INDENT 3.5
CSRF protection requires a secret key to securely sign the token. By default
this will use the Flask app\(aqs \fBSECRET_KEY\fP\&. If you\(aqd like to use a
separate token you can set \fBWTF_CSRF_SECRET_KEY\fP\&.
.UNINDENT
.UNINDENT
.SS HTML Forms
.sp
When using a \fBFlaskForm\fP, render the form\(aqs CSRF field like normal.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
.EE
.UNINDENT
.UNINDENT
.sp
If the template doesn\(aqt use a \fBFlaskForm\fP, render a hidden input with the
token in the form.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
.EE
.UNINDENT
.UNINDENT
.SS JavaScript Requests
.sp
When sending an AJAX request, add the \fBX\-CSRFToken\fP header to it.
For example, in jQuery you can configure all requests to send the token.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
.EE
.UNINDENT
.UNINDENT
.sp
In Axios you can set the header for all requests with \fBaxios.defaults.headers.common\fP\&.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
.EE
.UNINDENT
.UNINDENT
.SS Customize the error response
.sp
When CSRF validation fails, it will raise a \fBCSRFError\fP\&.
By default this returns a response with the failure reason and a 400 code.
You can customize the error response using Flask\(aqs
\X'tty: link https://flask.palletsprojects.com/en/stable/api/#flask.Flask.errorhandler'\fI\%errorhandler()\fP\X'tty: link'\&.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
from flask_wtf.csrf import CSRFError
@app.errorhandler(CSRFError)
def handle_csrf_error(e):
return render_template(\(aqcsrf_error.html\(aq, reason=e.description), 400
.EE
.UNINDENT
.UNINDENT
.SS Exclude views from protection
.sp
We strongly suggest that you protect all your views with CSRF. But if
needed, you can exclude some views using a decorator.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
@app.route(\(aq/foo\(aq, methods=(\(aqGET\(aq, \(aqPOST\(aq))
@csrf.exempt
def my_handler():
# ...
return \(aqok\(aq
.EE
.UNINDENT
.UNINDENT
.sp
You can exclude all the views of a blueprint.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
csrf.exempt(account_blueprint)
.EE
.UNINDENT
.UNINDENT
.sp
You can disable CSRF protection in all views by default, by setting
\fBWTF_CSRF_CHECK_DEFAULT\fP to \fBFalse\fP, and selectively call
\fBprotect()\fP only when you need. This also enables you to do some
pre\-processing on the requests before checking for the CSRF token.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
@app.before_request
def check_csrf():
if not is_oauth(request):
csrf.protect()
.EE
.UNINDENT
.UNINDENT
.SS Configuration
.TS
box center;
l|l.
T{
\fBWTF_CSRF_ENABLED\fP
T} T{
Set to \fBFalse\fP to disable all CSRF protection.
Default is \fBTrue\fP\&.
T}
_
T{
\fBWTF_CSRF_CHECK_DEFAULT\fP
T} T{
When using the CSRF protection extension, this
controls whether every view is protected by default.
Default is \fBTrue\fP\&.
T}
_
T{
\fBWTF_CSRF_SECRET_KEY\fP
T} T{
Random data for generating secure tokens. If this is
not set then \fBSECRET_KEY\fP is used.
T}
_
T{
\fBWTF_CSRF_METHODS\fP
T} T{
HTTP methods to protect from CSRF. Default is
\fB{\(aqPOST\(aq, \(aqPUT\(aq, \(aqPATCH\(aq, \(aqDELETE\(aq}\fP\&.
T}
_
T{
\fBWTF_CSRF_FIELD_NAME\fP
T} T{
Name of the form field and session key that holds the
CSRF token. Default is \fBcsrf_token\fP\&.
T}
_
T{
\fBWTF_CSRF_HEADERS\fP
T} T{
HTTP headers to search for CSRF token when it is not
provided in the form. Default is
\fB[\(aqX\-CSRFToken\(aq, \(aqX\-CSRF\-Token\(aq]\fP\&.
T}
_
T{
\fBWTF_CSRF_TIME_LIMIT\fP
T} T{
Max age in seconds for CSRF tokens. Default is
\fB3600\fP\&. If set to \fBNone\fP, the CSRF token is valid
for the life of the session.
T}
_
T{
\fBWTF_CSRF_SSL_STRICT\fP
T} T{
Whether to enforce the same origin policy by checking
that the referrer matches the host. Only applies to
HTTPS requests. Default is \fBTrue\fP\&.
T}
_
T{
\fBWTF_I18N_ENABLED\fP
T} T{
Set to \fBFalse\fP to disable Flask\-Babel I18N support.
Also set to \fBFalse\fP if you want to use WTForms\(aqs
built\-in messages directly, see more info \X'tty: link https://wtforms.readthedocs.io/en/stable/i18n.html#using-the-built-in-translations-provider'\fI\%here\fP\X'tty: link'\&.
Default is \fBTrue\fP\&.
T}
.TE
.SS Recaptcha
.TS
box center;
l|l.
T{
\fBRECAPTCHA_PUBLIC_KEY\fP
T} T{
\fBrequired\fP A public key.
T}
_
T{
\fBRECAPTCHA_PRIVATE_KEY\fP
T} T{
\fBrequired\fP A private key.
\X'tty: link https://www.google.com/recaptcha/admin'\fI\%https://www.google.com/recaptcha/admin\fP\X'tty: link'
T}
_
T{
\fBRECAPTCHA_PARAMETERS\fP
T} T{
\fBoptional\fP A dict of configuration options.
T}
_
T{
\fBRECAPTCHA_HTML\fP
T} T{
\fBoptional\fP Override default HTML template
for Recaptcha.
T}
_
T{
\fBRECAPTCHA_DATA_ATTRS\fP
T} T{
\fBoptional\fP A dict of \fBdata\-\fP attrs to use
for Recaptcha div
T}
_
T{
\fBRECAPTCHA_SCRIPT\fP
T} T{
\fBoptional\fP Override the default captcha
script URI in case an alternative service to
reCAPtCHA, e.g. hCaptcha is used. Default is
\fB\(aqhttps://www.google.com/recaptcha/api.js\(aq\fP
T}
_
T{
\fBRECAPTCHA_DIV_CLASS\fP
T} T{
\fBoptional\fP Override the default class of the
captcha div in case an alternative captcha
service is used. Default is
\fB\(aqg\-recaptcha\(aq\fP
T}
_
T{
\fBRECAPTCHA_VERIFY_SERVER\fP
T} T{
\fBoptional\fP Override the default verification
server in case an alternative service is used.
Default is
\fB\(aqhttps://www.google.com/recaptcha/api/siteverify\(aq\fP
T}
.TE
.SS Logging
.sp
CSRF errors are logged at the \fBINFO\fP level to the \fBflask_wtf.csrf\fP logger.
You still need to configure logging in your application in order to see these
messages.
.SH API DOCUMENTATION
.sp
If you are looking for information on a specific function, class or method,
this part of the documentation is for you.
.SS Developer Interface
.SS Forms and Fields
.SS CSRF Protection
.SH ADDITIONAL NOTES
.sp
Legal information and changelog are here.
.SS BSD\-3\-Clause License
.sp
Copyright 2010 WTForms
.sp
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
.INDENT 0.0
.IP 1. 3
Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
.IP 2. 3
Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
.IP 3. 3
Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
.UNINDENT
.sp
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
\(dqAS IS\(dq AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.SS Changes
.SS Version 1.2.1
.sp
Released 2023\-10\-02
.INDENT 0.0
.IP \(bu 2
Fix a bug introduced with \X'tty: link https://github.com/wtforms/flask-wtf/pull/556'\fI\%#556\fP\X'tty: link' where file validators were editing
the file fields content. \X'tty: link https://github.com/wtforms/flask-wtf/pull/578'\fI\%#578\fP\X'tty: link'
.UNINDENT
.SS Version 1.2.0
.sp
Released 2023\-10\-01
.INDENT 0.0
.IP \(bu 2
Add field \fBMultipleFileField\fP\&. \fBFileRequired\fP, \fBFileAllowed\fP, \fBFileSize\fP
now can be used to validate multiple files \X'tty: link https://github.com/wtforms/flask-wtf/pull/556'\fI\%#556\fP\X'tty: link' \X'tty: link https://github.com/wtforms/flask-wtf/issues/338'\fI\%#338\fP\X'tty: link'
.UNINDENT
.SS Version 1.1.2
.sp
Released 2023\-09\-29
.INDENT 0.0
.IP \(bu 2
Fixed Flask 2.3 deprecations of \fBwerkzeug.urls.url_encode\fP and
\fBflask.Markup\fP \X'tty: link https://github.com/wtforms/flask-wtf/pull/565'\fI\%#565\fP\X'tty: link' \X'tty: link https://github.com/wtforms/flask-wtf/issues/561'\fI\%#561\fP\X'tty: link'
.IP \(bu 2
Stop support for python 3.7 \X'tty: link https://github.com/wtforms/flask-wtf/pull/574'\fI\%#574\fP\X'tty: link'
.IP \(bu 2
Use \fIpyproject.toml\fP instead of \fIsetup.cfg\fP \X'tty: link https://github.com/wtforms/flask-wtf/pull/576'\fI\%#576\fP\X'tty: link'
.IP \(bu 2
Fixed nested blueprint CSRF exemption \X'tty: link https://github.com/wtforms/flask-wtf/pull/572'\fI\%#572\fP\X'tty: link'
.UNINDENT
.SS Version 1.1.1
.sp
Released 2023\-01\-17
.INDENT 0.0
.IP \(bu 2
Fixed \fIvalidate\fP \fIextra_validators\fP parameter. \X'tty: link https://github.com/wtforms/flask-wtf/pull/548'\fI\%#548\fP\X'tty: link'
.UNINDENT
.SS Version 1.1.0
.sp
Released 2023\-01\-15
.INDENT 0.0
.IP \(bu 2
Drop support for Python 3.6.
.IP \(bu 2
\fBvalidate_on_submit\fP takes a \fBextra_validators\fP parameters \X'tty: link https://github.com/wtforms/flask-wtf/pull/479'\fI\%#479\fP\X'tty: link'
.IP \(bu 2
Stop supporting Flask\-Babelex \X'tty: link https://github.com/wtforms/flask-wtf/pull/540'\fI\%#540\fP\X'tty: link'
.IP \(bu 2
Support for python 3.11 \X'tty: link https://github.com/wtforms/flask-wtf/pull/542'\fI\%#542\fP\X'tty: link'
.IP \(bu 2
Remove unused call to \fIJSONEncoder\fP \X'tty: link https://github.com/wtforms/flask-wtf/pull/536'\fI\%#536\fP\X'tty: link'
.UNINDENT
.SS Version 1.0.1
.sp
Released 2022\-03\-31
.INDENT 0.0
.IP \(bu 2
Update compatibility with the latest Werkzeug release. \X'tty: link https://github.com/wtforms/flask-wtf/issues/511'\fI\%#511\fP\X'tty: link'
.UNINDENT
.SS Version 1.0.0
.sp
Released 2021\-11\-07
.INDENT 0.0
.IP \(bu 2
Deprecated items removal \X'tty: link https://github.com/wtforms/flask-wtf/pull/484'\fI\%#484\fP\X'tty: link'
.IP \(bu 2
Support for alternatives captcha services \X'tty: link https://github.com/wtforms/flask-wtf/pull/425'\fI\%#425\fP\X'tty: link' \X'tty: link https://github.com/wtforms/flask-wtf/pull/342'\fI\%#342\fP\X'tty: link'
\X'tty: link https://github.com/wtforms/flask-wtf/pull/387'\fI\%#387\fP\X'tty: link' \X'tty: link https://github.com/wtforms/flask-wtf/issues/384'\fI\%#384\fP\X'tty: link'
.UNINDENT
.SS Version 0.15.1
.sp
Released 2021\-05\-25
.INDENT 0.0
.IP \(bu 2
Add \fBpython_requires\fP metadata to avoid installing on unsupported
Python versions. \X'tty: link https://github.com/wtforms/flask-wtf/pull/442'\fI\%#442\fP\X'tty: link'
.UNINDENT
.SS Version 0.15.0
.sp
Released 2021\-05\-24
.INDENT 0.0
.IP \(bu 2
Drop support for Python < 3.6. \X'tty: link https://github.com/wtforms/flask-wtf/pull/416'\fI\%#416\fP\X'tty: link'
.IP \(bu 2
\fBFileSize\fP validator. \X'tty: link https://github.com/wtforms/flask-wtf/pull/307'\fI\%#307\fP\X'tty: link'\X'tty: link https://github.com/wtforms/flask-wtf/pull/365'\fI\%#365\fP\X'tty: link'
.IP \(bu 2
Extra requirement \fBemail\fP installs the \fBemail_validator\fP
package. \X'tty: link https://github.com/wtforms/flask-wtf/pull/423'\fI\%#423\fP\X'tty: link'
.IP \(bu 2
Fixed Flask 2.0 warnings. \X'tty: link https://github.com/wtforms/flask-wtf/pull/434'\fI\%#434\fP\X'tty: link'
.IP \(bu 2
Various documentation fixes. \X'tty: link https://github.com/wtforms/flask-wtf/pull/315'\fI\%#315\fP\X'tty: link'\X'tty: link https://github.com/wtforms/flask-wtf/pull/321'\fI\%#321\fP\X'tty: link'\X'tty: link https://github.com/wtforms/flask-wtf/pull/335'\fI\%#335\fP\X'tty: link'\X'tty: link https://github.com/wtforms/flask-wtf/pull/344'\fI\%#344\fP\X'tty: link'\X'tty: link https://github.com/wtforms/flask-wtf/pull/386'\fI\%#386\fP\X'tty: link'\X'tty: link https://github.com/wtforms/flask-wtf/pull/400'\fI\%#400\fP\X'tty: link',
\X'tty: link https://github.com/wtforms/flask-wtf/pull/404'\fI\%#404\fP\X'tty: link'\X'tty: link https://github.com/wtforms/flask-wtf/pull/420'\fI\%#420\fP\X'tty: link'\X'tty: link https://github.com/wtforms/flask-wtf/pull/437'\fI\%#437\fP\X'tty: link'
.IP \(bu 2
Various CI fixes. \X'tty: link https://github.com/wtforms/flask-wtf/pull/405'\fI\%#405\fP\X'tty: link'\X'tty: link https://github.com/wtforms/flask-wtf/pull/438'\fI\%#438\fP\X'tty: link'
.UNINDENT
.SS Version 0.14.3
.sp
Released 2020\-02\-06
.INDENT 0.0
.IP \(bu 2
Fix deprecated imports from \fBwerkzeug\fP and \fBcollections\fP\&.
.UNINDENT
.SS Version 0.14.2
.sp
Released 2017\-01\-10
.INDENT 0.0
.IP \(bu 2
Fix bug where \fBFlaskForm\fP assumed \fBmeta\fP argument was not
\fBNone\fP if it was passed. \X'tty: link https://github.com/wtforms/flask-wtf/issues/278'\fI\%#278\fP\X'tty: link'
.UNINDENT
.SS Version 0.14.1
.sp
Released 2017\-01\-10
.INDENT 0.0
.IP \(bu 2
Fix bug where the file validators would incorrectly identify an
empty file as valid data. \X'tty: link https://github.com/wtforms/flask-wtf/issues/276'\fI\%#276\fP\X'tty: link', \X'tty: link https://github.com/wtforms/flask-wtf/pull/277'\fI\%#277\fP\X'tty: link'
.INDENT 2.0
.IP \(bu 2
\fBFileField\fP is no longer deprecated. The data is checked
during processing and only set if it\(aqs a valid file.
.IP \(bu 2
\fBhas_file\fP \fIis\fP deprecated; it\(aqs now equivalent to
\fBbool(field.data)\fP\&.
.IP \(bu 2
\fBFileRequired\fP and \fBFileAllowed\fP work with both the
Flask\-WTF and WTForms \fBFileField\fP classes.
.IP \(bu 2
The \fBOptional\fP validator now works with \fBFileField\fP\&.
.UNINDENT
.UNINDENT
.SS Version 0.14
.sp
Released 2017\-01\-06
.INDENT 0.0
.IP \(bu 2
Use ItsDangerous to sign CSRF tokens and check expiration instead of
doing it ourselves. \X'tty: link https://github.com/wtforms/flask-wtf/issues/264'\fI\%#264\fP\X'tty: link'
.INDENT 2.0
.IP \(bu 2
All tokens are URL safe, removing the \fBurl_safe\fP parameter
from \fBgenerate_csrf\fP\&. \X'tty: link https://github.com/wtforms/flask-wtf/issues/206'\fI\%#206\fP\X'tty: link'
.IP \(bu 2
All tokens store a timestamp, which is checked in
\fBvalidate_csrf\fP\&. The \fBtime_limit\fP parameter of
\fBgenerate_csrf\fP is removed.
.UNINDENT
.IP \(bu 2
Remove the \fBapp\fP attribute from \fBCsrfProtect\fP, use
\fBcurrent_app\fP\&. \X'tty: link https://github.com/wtforms/flask-wtf/issues/264'\fI\%#264\fP\X'tty: link'
.IP \(bu 2
\fBCsrfProtect\fP protects the \fBDELETE\fP method by default.
\X'tty: link https://github.com/wtforms/flask-wtf/issues/264'\fI\%#264\fP\X'tty: link'
.IP \(bu 2
The same CSRF token is generated for the lifetime of a request. It
is exposed as \fBg.csrf_token\fP for use during testing.
\X'tty: link https://github.com/wtforms/flask-wtf/issues/227'\fI\%#227\fP\X'tty: link'\X'tty: link https://github.com/wtforms/flask-wtf/issues/264'\fI\%#264\fP\X'tty: link'
.IP \(bu 2
\fBCsrfProtect.error_handler\fP is deprecated. \X'tty: link https://github.com/wtforms/flask-wtf/issues/264'\fI\%#264\fP\X'tty: link'
.INDENT 2.0
.IP \(bu 2
Handlers that return a response work in addition to those that
raise an error. The behavior was not clear in previous docs.
.IP \(bu 2
\X'tty: link https://github.com/wtforms/flask-wtf/issues/200'\fI\%#200\fP\X'tty: link'\X'tty: link https://github.com/wtforms/flask-wtf/issues/209'\fI\%#209\fP\X'tty: link'\X'tty: link https://github.com/wtforms/flask-wtf/issues/243'\fI\%#243\fP\X'tty: link'\X'tty: link https://github.com/wtforms/flask-wtf/issues/252'\fI\%#252\fP\X'tty: link'
.UNINDENT
.IP \(bu 2
Use \fBForm.Meta\fP instead of deprecated \fBSecureForm\fP for CSRF (and
everything else). \X'tty: link https://github.com/wtforms/flask-wtf/issues/216'\fI\%#216\fP\X'tty: link'\X'tty: link https://github.com/wtforms/flask-wtf/issues/271'\fI\%#271\fP\X'tty: link'
.INDENT 2.0
.IP \(bu 2
\fBcsrf_enabled\fP parameter is still recognized but deprecated.
All other attributes and methods from \fBSecureForm\fP are
removed. \X'tty: link https://github.com/wtforms/flask-wtf/issues/271'\fI\%#271\fP\X'tty: link'
.UNINDENT
.IP \(bu 2
Provide \fBWTF_CSRF_FIELD_NAME\fP to configure the name of the CSRF
token. \X'tty: link https://github.com/wtforms/flask-wtf/issues/271'\fI\%#271\fP\X'tty: link'
.IP \(bu 2
\fBvalidate_csrf\fP raises \fBwtforms.ValidationError\fP with specific
messages instead of returning \fBTrue\fP or \fBFalse\fP\&. This breaks
anything that was calling the method directly. \X'tty: link https://github.com/wtforms/flask-wtf/issues/239'\fI\%#239\fP\X'tty: link'\X'tty: link https://github.com/wtforms/flask-wtf/issues/271'\fI\%#271\fP\X'tty: link'
.INDENT 2.0
.IP \(bu 2
CSRF errors are logged as well as raised. \X'tty: link https://github.com/wtforms/flask-wtf/issues/239'\fI\%#239\fP\X'tty: link'
.UNINDENT
.IP \(bu 2
\fBCsrfProtect\fP is renamed to \fBCSRFProtect\fP\&. A deprecation warning
is issued when using the old name. \fBCsrfError\fP is renamed to
\fBCSRFError\fP without deprecation. \X'tty: link https://github.com/wtforms/flask-wtf/issues/271'\fI\%#271\fP\X'tty: link'
.IP \(bu 2
\fBFileField\fP is deprecated because it no longer provides
functionality over the provided validators. Use
\fBwtforms.FileField\fP directly. \X'tty: link https://github.com/wtforms/flask-wtf/issues/272'\fI\%#272\fP\X'tty: link'
.UNINDENT
.SS Version 0.13.1
.sp
Released 2016\-10\-6
.INDENT 0.0
.IP \(bu 2
Deprecation warning for \fBForm\fP is shown during \fB__init__\fP
instead of immediately when subclassing. \X'tty: link https://github.com/wtforms/flask-wtf/issues/262'\fI\%#262\fP\X'tty: link'
.IP \(bu 2
Don\(aqt use \fBpkg_resources\fP to get version, for compatibility with
GAE. \X'tty: link https://github.com/wtforms/flask-wtf/issues/261'\fI\%#261\fP\X'tty: link'
.UNINDENT
.SS Version 0.13
.sp
Released 2016\-09\-29
.INDENT 0.0
.IP \(bu 2
\fBForm\fP is renamed to \fBFlaskForm\fP in order to avoid name
collision with WTForms\(aqs base class. Using \fBForm\fP will show a
deprecation warning. \X'tty: link https://github.com/wtforms/flask-wtf/issues/250'\fI\%#250\fP\X'tty: link'
.IP \(bu 2
\fBhidden_tag\fP no longer wraps the hidden inputs in a hidden div.
This is valid HTML5 and any modern HTML parser will behave
correctly. \X'tty: link https://github.com/wtforms/flask-wtf/issues/193'\fI\%#193\fP\X'tty: link'\X'tty: link https://github.com/wtforms/flask-wtf/issues/217'\fI\%#217\fP\X'tty: link'
.IP \(bu 2
\fBflask_wtf.html5\fP is deprecated. Import directly from
\fBwtforms.fields.html5\fP\&. \X'tty: link https://github.com/wtforms/flask-wtf/issues/251'\fI\%#251\fP\X'tty: link'
.IP \(bu 2
\fBis_submitted\fP is true for \fBPATCH\fP and \fBDELETE\fP in addition to
\fBPOST\fP and \fBPUT\fP\&. \X'tty: link https://github.com/wtforms/flask-wtf/issues/187'\fI\%#187\fP\X'tty: link'
.IP \(bu 2
\fBgenerate_csrf\fP takes a \fBtoken_key\fP parameter to specify the key
stored in the session. \X'tty: link https://github.com/wtforms/flask-wtf/issues/206'\fI\%#206\fP\X'tty: link'
.IP \(bu 2
\fBgenerate_csrf\fP takes a \fBurl_safe\fP parameter to allow the token
to be used in URLs. \X'tty: link https://github.com/wtforms/flask-wtf/issues/206'\fI\%#206\fP\X'tty: link'
.IP \(bu 2
\fBform.data\fP can be accessed multiple times without raising an
exception. \X'tty: link https://github.com/wtforms/flask-wtf/issues/248'\fI\%#248\fP\X'tty: link'
.IP \(bu 2
File extension with multiple parts (\fB\&.tar.gz\fP) can be used in the
\fBFileAllowed\fP validator. \X'tty: link https://github.com/wtforms/flask-wtf/issues/201'\fI\%#201\fP\X'tty: link'
.UNINDENT
.SS Version 0.12
.sp
Released 2015\-07\-09
.INDENT 0.0
.IP \(bu 2
Abstract \fBprotect_csrf()\fP into a separate method.
.IP \(bu 2
Update reCAPTCHA configuration.
.IP \(bu 2
Fix reCAPTCHA error handle.
.UNINDENT
.SS Version 0.11
.sp
Released 2015\-01\-21
.INDENT 0.0
.IP \(bu 2
Use the new reCAPTCHA API. \X'tty: link https://github.com/wtforms/flask-wtf/pull/164'\fI\%#164\fP\X'tty: link'
.UNINDENT
.SS Version 0.10.3
.sp
Released 2014\-11\-16
.INDENT 0.0
.IP \(bu 2
Add configuration: \fBWTF_CSRF_HEADERS\fP\&. \X'tty: link https://github.com/wtforms/flask-wtf/pull/159'\fI\%#159\fP\X'tty: link'
.IP \(bu 2
Support customize hidden tags. \X'tty: link https://github.com/wtforms/flask-wtf/pull/150'\fI\%#150\fP\X'tty: link'
.IP \(bu 2
And many more bug fixes.
.UNINDENT
.SS Version 0.10.2
.sp
Released 2014\-09\-03
.INDENT 0.0
.IP \(bu 2
Update translation for reCaptcha. \X'tty: link https://github.com/wtforms/flask-wtf/pull/146'\fI\%#146\fP\X'tty: link'
.UNINDENT
.SS Version 0.10.1
.sp
Released 2014\-08\-26
.INDENT 0.0
.IP \(bu 2
Update \fBRECAPTCHA_API_SERVER_URL\fP\&. \X'tty: link https://github.com/wtforms/flask-wtf/pull/145'\fI\%#145\fP\X'tty: link'
.IP \(bu 2
Update requirement Werkzeug >= 0.9.5.
.IP \(bu 2
Fix \fBCsrfProtect\fP exempt for blueprints. \X'tty: link https://github.com/wtforms/flask-wtf/pull/143'\fI\%#143\fP\X'tty: link'
.UNINDENT
.SS Version 0.10.0
.sp
Released 2014\-07\-16
.INDENT 0.0
.IP \(bu 2
Add configuration: \fBWTF_CSRF_METHODS\fP\&.
.IP \(bu 2
Support WTForms 2.0 now.
.IP \(bu 2
Fix CSRF validation without time limit (\fBtime_limit=False\fP).
.IP \(bu 2
\fBcsrf_exempt\fP supports blueprint. \X'tty: link https://github.com/wtforms/flask-wtf/issues/111'\fI\%#111\fP\X'tty: link'
.UNINDENT
.SS Version 0.9.5
.sp
Released 2014\-03\-21
.INDENT 0.0
.IP \(bu 2
\fBcsrf_token\fP for all template types. \X'tty: link https://github.com/wtforms/flask-wtf/pull/112'\fI\%#112\fP\X'tty: link'
.IP \(bu 2
Make \fBFileRequired\fP a subclass of \fBInputRequired\fP\&. \X'tty: link https://github.com/wtforms/flask-wtf/pull/108'\fI\%#108\fP\X'tty: link'
.UNINDENT
.SS Version 0.9.4
.sp
Released 2013\-12\-20
.INDENT 0.0
.IP \(bu 2
Bugfix for \fBcsrf\fP module when form has a prefix.
.IP \(bu 2
Compatible support for WTForms 2.
.IP \(bu 2
Remove file API for \fBFileField\fP
.UNINDENT
.SS Version 0.9.3
.sp
Released 2013\-10\-02
.INDENT 0.0
.IP \(bu 2
Fix validation of recaptcha when app in testing mode. \X'tty: link https://github.com/wtforms/flask-wtf/pull/89'\fI\%#89\fP\X'tty: link'
.IP \(bu 2
Bugfix for \fBcsrf\fP module. \X'tty: link https://github.com/wtforms/flask-wtf/pull/91'\fI\%#91\fP\X'tty: link'
.UNINDENT
.SS Version 0.9.2
.sp
Released 2013\-09\-11
.INDENT 0.0
.IP \(bu 2
Upgrade WTForms to 1.0.5.
.IP \(bu 2
No lazy string for i18n. \X'tty: link https://github.com/wtforms/flask-wtf/issues/77'\fI\%#77\fP\X'tty: link'
.IP \(bu 2
No \fBDateInput\fP widget in HTML5. \X'tty: link https://github.com/wtforms/flask-wtf/issues/81'\fI\%#81\fP\X'tty: link'
.IP \(bu 2
\fBPUT\fP and \fBPATCH\fP for CSRF. \X'tty: link https://github.com/wtforms/flask-wtf/issues/86'\fI\%#86\fP\X'tty: link'
.UNINDENT
.SS Version 0.9.1
.sp
Released 2013\-08\-21
.INDENT 0.0
.IP \(bu 2
Compatibility with Flask < 0.10. \X'tty: link https://github.com/wtforms/flask-wtf/issues/82'\fI\%#82\fP\X'tty: link'
.UNINDENT
.SS Version 0.9.0
.sp
Released 2013\-08\-15
.INDENT 0.0
.IP \(bu 2
Add i18n support. \X'tty: link https://github.com/wtforms/flask-wtf/issues/65'\fI\%#65\fP\X'tty: link'
.IP \(bu 2
Use default HTML5 widgets and fields provided by WTForms.
.IP \(bu 2
Python 3.3+ support.
.IP \(bu 2
Redesign form, replace \fBSessionSecureForm\fP\&.
.IP \(bu 2
CSRF protection solution.
.IP \(bu 2
Drop WTForms imports.
.IP \(bu 2
Fix recaptcha i18n support.
.IP \(bu 2
Fix recaptcha validator for Python 3.
.IP \(bu 2
More test cases, it\(aqs 90%+ coverage now.
.IP \(bu 2
Redesign documentation.
.UNINDENT
.SS Version 0.8.4
.sp
Released 2013\-03\-28
.INDENT 0.0
.IP \(bu 2
Recaptcha Validator now returns provided message. \X'tty: link https://github.com/wtforms/flask-wtf/issues/66'\fI\%#66\fP\X'tty: link'
.IP \(bu 2
Minor doc fixes.
.IP \(bu 2
Fixed issue with tests barking because of nose/multiprocessing
issue.
.UNINDENT
.SS Version 0.8.3
.sp
Released 2013\-03\-13
.INDENT 0.0
.IP \(bu 2
Update documentation to indicate pending deprecation of WTForms
namespace facade.
.IP \(bu 2
PEP8 fixes. \X'tty: link https://github.com/wtforms/flask-wtf/issues/64'\fI\%#64\fP\X'tty: link'
.IP \(bu 2
Fix Recaptcha widget. \X'tty: link https://github.com/wtforms/flask-wtf/issues/49'\fI\%#49\fP\X'tty: link'
.UNINDENT
.SS Version 0.8.2 and prior
.sp
Initial development by Dan Jacob and Ron Duplain.
.SS How to contribute to Flask\-WTF
.sp
Thank you for considering contributing to Flask\-WTF!
.SS Support questions
.sp
Please don\(aqt use the issue tracker for this. The issue tracker is a
tool to address bugs and feature requests in Flask\-WTF itself. Use one of
the following resources for questions about using Flask\-WTF or issues
with your own code:
.INDENT 0.0
.IP \(bu 2
The \fB#get\-help\fP channel on our Discord chat:
\X'tty: link https://discord.gg/pallets'\fI\%https://discord.gg/pallets\fP\X'tty: link'
.IP \(bu 2
The mailing list \X'tty: link mailto:flask@python.org'\fI\%flask@python.org\fP\X'tty: link' for long term discussion or larger
issues.
.IP \(bu 2
Ask on \X'tty: link https://stackoverflow.com/questions/tagged/flask-wtf?tab=Frequent'\fI\%Stack Overflow\fP\X'tty: link'\&. Search with Google first using:
\fBsite:stackoverflow.com flask\-wtf {search term, exception message, etc.}\fP
.UNINDENT
.SS Reporting issues
.sp
Include the following information in your post:
.INDENT 0.0
.IP \(bu 2
Describe what you expected to happen.
.IP \(bu 2
If possible, include a \X'tty: link https://stackoverflow.com/help/minimal-reproducible-example'\fI\%minimal reproducible example\fP\X'tty: link' to help us
identify the issue. This also helps check that the issue is not with
your own code.
.IP \(bu 2
Describe what actually happened. Include the full traceback if there
was an exception.
.IP \(bu 2
List your Python, Flask\-WTF, and WTForms versions. If possible, check if this
issue is already fixed in the latest releases or the latest code in
the repository.
.UNINDENT
.SS Submitting patches
.sp
If there is not an open issue for what you want to submit, prefer
opening one for discussion before working on a PR. You can work on any
issue that doesn\(aqt have an open PR linked to it or a maintainer assigned
to it. These show up in the sidebar. No need to ask if you can work on
an issue that interests you.
.sp
Include the following in your patch:
.INDENT 0.0
.IP \(bu 2
Use \X'tty: link https://black.readthedocs.io'\fI\%Black\fP\X'tty: link' to format your code. This and other tools will run
automatically if you install \X'tty: link https://pre-commit.com'\fI\%pre\-commit\fP\X'tty: link' using the instructions
below.
.IP \(bu 2
Include tests if your patch adds or changes code. Make sure the test
fails without your patch.
.IP \(bu 2
Update any relevant docs pages and docstrings. Docs pages and
docstrings should be wrapped at 72 characters.
.IP \(bu 2
Add an entry in \fBCHANGES.rst\fP\&. Use the same style as other
entries. Also include \fB\&.. versionchanged::\fP inline changelogs in
relevant docstrings.
.UNINDENT
.SS First time setup
.INDENT 0.0
.IP \(bu 2
Download and install the \X'tty: link https://git-scm.com/downloads'\fI\%latest version of git\fP\X'tty: link'\&.
.IP \(bu 2
Configure git with your \X'tty: link https://docs.github.com/en/github/using-git/setting-your-username-in-git'\fI\%username\fP\X'tty: link' and \X'tty: link https://docs.github.com/en/github/setting-up-and-managing-your-github-user-account/setting-your-commit-email-address'\fI\%email\fP\X'tty: link'\&.
.INDENT 2.0
.INDENT 3.5
.sp
.EX
$ git config \-\-global user.name \(aqyour name\(aq
$ git config \-\-global user.email \(aqyour email\(aq
.EE
.UNINDENT
.UNINDENT
.IP \(bu 2
Make sure you have a \X'tty: link https://github.com/join'\fI\%GitHub account\fP\X'tty: link'\&.
.IP \(bu 2
Fork Flask\-WTF to your GitHub account by clicking the \X'tty: link https://github.com/wtforms/flask-wtf/fork'\fI\%Fork\fP\X'tty: link' button.
.IP \(bu 2
\X'tty: link https://docs.github.com/en/github/getting-started-with-github/fork-a-repo#step-2-create-a-local-clone-of-your-fork'\fI\%Clone\fP\X'tty: link' the main repository locally.
.INDENT 2.0
.INDENT 3.5
.sp
.EX
$ git clone https://github.com/wtforms/flask\-wtf
$ cd flask\-wtf
.EE
.UNINDENT
.UNINDENT
.IP \(bu 2
Add your fork as a remote to push your work to. Replace
\fB{username}\fP with your username. This names the remote \(dqfork\(dq, the
default WTForms remote is \(dqorigin\(dq.
.INDENT 2.0
.INDENT 3.5
.sp
.EX
$ git remote add fork https://github.com/{username}/flask\-wtf
.EE
.UNINDENT
.UNINDENT
.IP \(bu 2
Create a virtualenv.
.INDENT 2.0
.INDENT 3.5
.sp
.EX
$ python3 \-m venv env
$ . env/bin/activate
.EE
.UNINDENT
.UNINDENT
.sp
On Windows, activating is different.
.INDENT 2.0
.INDENT 3.5
.sp
.EX
> env\eScripts\eactivate
.EE
.UNINDENT
.UNINDENT
.IP \(bu 2
Upgrade pip and setuptools.
.INDENT 2.0
.INDENT 3.5
.sp
.EX
$ python \-m pip install \-\-upgrade pip setuptools
.EE
.UNINDENT
.UNINDENT
.IP \(bu 2
Install the development dependencies, then install Flask\-WTF in
editable mode.
.INDENT 2.0
.INDENT 3.5
.sp
.EX
$ pip install \-r requirements/dev.txt && pip install \-e .
.EE
.UNINDENT
.UNINDENT
.IP \(bu 2
Install the pre\-commit hooks.
.INDENT 2.0
.INDENT 3.5
.sp
.EX
$ pre\-commit install
.EE
.UNINDENT
.UNINDENT
.UNINDENT
.SS Start coding
.INDENT 0.0
.IP \(bu 2
Create a branch to identify the issue you would like to work on. If
you\(aqre submitting a bug or documentation fix, branch off of the
latest \(dq.x\(dq branch.
.INDENT 2.0
.INDENT 3.5
.sp
.EX
$ git fetch origin
$ git checkout \-b your\-branch\-name origin/1.0.x
.EE
.UNINDENT
.UNINDENT
.sp
If you\(aqre submitting a feature addition or change, branch off of the
\(dqmain\(dq branch.
.INDENT 2.0
.INDENT 3.5
.sp
.EX
$ git fetch origin
$ git checkout \-b your\-branch\-name origin/main
.EE
.UNINDENT
.UNINDENT
.IP \(bu 2
Using your favorite editor, make your changes,
\X'tty: link https://dont-be-afraid-to-commit.readthedocs.io/en/latest/git/commandlinegit.html#commit-your-changes'\fI\%committing as you go\fP\X'tty: link'\&.
.IP \(bu 2
Include tests that cover any code changes you make. Make sure the
test fails without your patch. Run the tests as described below.
.IP \(bu 2
Push your commits to your fork on GitHub and
\X'tty: link https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/creating-a-pull-request'\fI\%create a pull request\fP\X'tty: link'\&. Link to the issue being addressed with
\fBfixes #123\fP in the pull request.
.INDENT 2.0
.INDENT 3.5
.sp
.EX
$ git push \-\-set\-upstream fork your\-branch\-name
.EE
.UNINDENT
.UNINDENT
.UNINDENT
.SS Running the tests
.sp
Run the basic test suite with pytest.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
$ pytest
.EE
.UNINDENT
.UNINDENT
.sp
This runs the tests for the current environment, which is usually
sufficient. CI will run the full suite when you submit your pull
request. You can run the full test suite with tox if you don\(aqt want to
wait.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
$ tox
.EE
.UNINDENT
.UNINDENT
.SS Running test coverage
.sp
Generating a report of lines that do not have test coverage can indicate
where to start contributing. Run \fBpytest\fP using \fBcoverage\fP and
generate a report.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
$ pip install coverage
$ coverage run \-m pytest
$ coverage html
.EE
.UNINDENT
.UNINDENT
.sp
Open \fBhtmlcov/index.html\fP in your browser to explore the report.
.sp
Read more about \X'tty: link https://coverage.readthedocs.io'\fI\%coverage\fP\X'tty: link'\&.
.SS Building the docs
.sp
Build the docs in the \fBdocs\fP directory using Sphinx.
.INDENT 0.0
.INDENT 3.5
.sp
.EX
$ cd docs
$ make html
.EE
.UNINDENT
.UNINDENT
.sp
Open \fB_build/html/index.html\fP in your browser to view the docs.
.sp
Read more about \X'tty: link https://www.sphinx-doc.org/en/stable/'\fI\%Sphinx\fP\X'tty: link'\&.
.SH AUTHOR
WTForms
.SH COPYRIGHT
2010 WTForms
.\" Generated by docutils manpage writer.
.