'\" 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
{{ form.csrf_token }} {{ form.name.label }} {{ form.name(size=20) }}
.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
{{ form.hidden_tag() }} {{ form.name.label }} {{ form.name(size=20) }}
.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 %} {% 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
{{ form.username }} {{ form.recaptcha }}
.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
{{ form.csrf_token }}
.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. .