1. Project Overview & Quickstart (pallets/werkzeug)
File: README.md
Werkzeug
werkzeug German noun: "tool". Etymology: werk ("work"), zeug ("stuff")
Werkzeug is a comprehensive WSGI web application library. It began as
a simple collection of various utilities for WSGI applications and has
become one of the most advanced WSGI utility libraries.
It includes:
- An interactive debugger that allows inspecting stack traces and
source code in the browser with an interactive interpreter for any
frame in the stack. - A full-featured request object with objects to interact with
headers, query args, form data, files, and cookies. - A response object that can wrap other WSGI applications and handle
streaming data. - A routing system for matching URLs to endpoints and generating URLs
for endpoints, with an extensible system for capturing variables
from URLs. - HTTP utilities to handle entity tags, cache control, dates, user
agents, cookies, files, and more. - A threaded WSGI server for use while developing applications
locally. - A test client for simulating HTTP requests during testing without
requiring running a server.
Werkzeug doesn't enforce any dependencies. It is up to the developer to
choose a template engine, database adapter, and even how to handle
requests. It can be used to build all sorts of end user applications
such as blogs, wikis, or bulletin boards.
Flask wraps Werkzeug, using it to handle the details of WSGI while
providing more structure and patterns for defining powerful
applications.
A Simple Example
# save this as app.py
from werkzeug.wrappers import Request, Response
@Request.application
def application(request: Request) -> Response:
return Response("Hello, World!")
if __name__ == "__main__":
from werkzeug.serving import run_simple
run_simple("127.0.0.1", 5000, application)$ python -m app
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)Donate
The Pallets organization develops and supports Werkzeug and other
popular packages. In order to grow the community of contributors and
users, and allow the maintainers to devote more time to the projects,
please donate today.
Contributing
See our detailed contributing documentation for many ways to
contribute, including reporting issues, requesting features, asking or answering
questions, and making PRs.
File: docs/deployment/apache-httpd.rst
Apache httpd
Apache httpd_ is a fast, production level HTTP server. When serving
your application with one of the WSGI servers listed in :doc:index, it
is often good or necessary to put a dedicated HTTP server in front of
it. This "reverse proxy" can handle incoming requests, TLS, and other
security and performance concerns better than the WSGI server.
httpd can be installed using your system package manager, or a pre-built
executable for Windows. Installing and running httpd itself is outside
the scope of this doc. This page outlines the basics of configuring
httpd to proxy your application. Be sure to read its documentation to
understand what features are available.
.. _Apache httpd: https://httpd.apache.org/
Domain Name
Acquiring and configuring a domain name is outside the scope of this
doc. In general, you will buy a domain name from a registrar, pay for
server space with a hosting provider, and then point your registrar
at the hosting provider's name servers.
To simulate this, you can also edit your hosts file, located at/etc/hosts on Linux. Add a line that associates a name with the
local IP.
Modern Linux systems may be configured to treat any domain name that
ends with .localhost like this without adding it to the hosts
file.
.. code-block:: python
:caption: /etc/hosts
127.0.0.1 hello.localhostConfiguration
The httpd configuration is located at /etc/httpd/conf/httpd.conf on
Linux. It may be different depending on your operating system. Check the
docs and look for httpd.conf.
Remove or comment out any existing DocumentRoot directive. Add the
config lines below. We'll assume the WSGI server is listening locally athttp://127.0.0.1:8000.
.. code-block:: apache
:caption: /etc/httpd/conf/httpd.conf
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
ProxyPass / http://127.0.0.1:8000/
RequestHeader set X-Forwarded-Proto http
RequestHeader set X-Forwarded-Prefix /The LoadModule lines might already exist. If so, make sure they are
uncommented instead of adding them manually.
Then :doc:proxy_fix so that your application uses the X-Forwarded
headers. X-Forwarded-For and X-Forwarded-Host are automatically
set by ProxyPass.
Static Files
If your application has static files such as JavaScript, CSS, and
images, it will be more efficient to let Nginx serve them directly
rather than going through the Python application.
Assuming the static files are expected to be available under the/static/ URL, and are stored at /home/project/static/, add the
following to the config above.
.. code-block:: apache
Alias /static/ /home/project/static/File: docs/deployment/eventlet.rst
eventlet
Prefer using :doc:gunicorn with eventlet workers rather than usingeventlet_ directly. Gunicorn provides a much more configurable and
production-tested server.
eventlet_ allows writing asynchronous, coroutine-based code that looks
like standard synchronous Python. It uses greenlet_ to enable task
switching without writing async/await or using asyncio.
:doc:gevent is another library that does the same thing. Certain
dependencies you have, or other considerations, may affect which of the
two you choose to use.
eventlet provides a WSGI server that can handle many connections at once
instead of one per worker process. You must actually use eventlet in
your own code to see any benefit to using the server.
.. _eventlet: https://eventlet.net/
.. _greenlet: https://greenlet.readthedocs.io/en/latest/
Installing
When using eventlet, greenlet>=1.0 is required, otherwise context locals
such as request will not work as expected. When using PyPy,
PyPy>=7.3.7 is required.
Create a virtualenv, install your application, then installeventlet.
.. code-block:: text
$ cd hello-app
$ python -m venv venv
$ . venv/bin/activate
$ pip install . # install your application
$ pip install eventletRunning
To use eventlet to serve your application, write a script that imports
its wsgi.server, as well as your app or app factory.
.. code-block:: python
:caption: wsgi.py
import eventlet
from eventlet import wsgi
from hello import create_app
app = create_app()
wsgi.server(eventlet.listen(("127.0.0.1", 8000), app).. code-block:: text
$ python wsgi.py
(x) wsgi starting up on http://127.0.0.1:8000Binding Externally
eventlet should not be run as root because it would cause your
application code to run as root, which is not secure. However, this
means it will not be possible to bind to port 80 or 443. Instead, a
reverse proxy such as :doc:nginx or :doc:apache-httpd should be used
in front of eventlet.
You can bind to all external IPs on a non-privileged port by using0.0.0.0 in the server arguments shown in the previous section.
Don't do this when using a reverse proxy setup, otherwise it will be
possible to bypass the proxy.
0.0.0.0 is not a valid address to navigate to, you'd use a specific
IP address in your browser.
File: docs/deployment/gevent.rst
gevent
Prefer using :doc:gunicorn or :doc:uwsgi with gevent workers rather
than using gevent_ directly. Gunicorn and uWSGI provide much more
configurable and production-tested servers.
gevent_ allows writing asynchronous, coroutine-based code that looks
like standard synchronous Python. It uses greenlet_ to enable task
switching without writing async/await or using asyncio.
:doc:eventlet is another library that does the same thing. Certain
dependencies you have, or other considerations, may affect which of the
two you choose to use.
gevent provides a WSGI server that can handle many connections at once
instead of one per worker process. You must actually use gevent in your
own code to see any benefit to using the server.
.. _gevent: https://www.gevent.org/
.. _greenlet: https://greenlet.readthedocs.io/en/latest/
Installing
When using gevent, greenlet>=1.0 is required, otherwise context locals
such as request will not work as expected. When using PyPy,
PyPy>=7.3.7 is required.
Create a virtualenv, install your application, then install gevent.
.. code-block:: text
$ cd hello-app
$ python -m venv venv
$ . venv/bin/activate
$ pip install . # install your application
$ pip install geventRunning
To use gevent to serve your application, write a script that imports itsWSGIServer, as well as your app or app factory.
.. code-block:: python
:caption: wsgi.py
from gevent.pywsgi import WSGIServer
from hello import create_app
app = create_app()
http_server = WSGIServer(("127.0.0.1", 8000), app)
http_server.serve_forever().. code-block:: text
$ python wsgi.pyNo output is shown when the server starts.
Binding Externally
gevent should not be run as root because it would cause your
application code to run as root, which is not secure. However, this
means it will not be possible to bind to port 80 or 443. Instead, a
reverse proxy such as :doc:nginx or :doc:apache-httpd should be used
in front of gevent.
You can bind to all external IPs on a non-privileged port by using0.0.0.0 in the server arguments shown in the previous section. Don't
do this when using a reverse proxy setup, otherwise it will be possible
to bypass the proxy.
0.0.0.0 is not a valid address to navigate to, you'd use a specific
IP address in your browser.
File: docs/deployment/gunicorn.rst
Gunicorn
Gunicorn_ is a pure Python WSGI server with simple configuration and
multiple worker implementations for performance tuning.
- It tends to integrate easily with hosting platforms.
- It does not support Windows (but does run on WSL).
- It is easy to install as it does not require additional dependencies
or compilation. - It has built-in async worker support using gevent or eventlet.
This page outlines the basics of running Gunicorn. Be sure to read itsdocumentation_ and use gunicorn --help to understand what features
are available.
.. _Gunicorn: https://gunicorn.org/
.. _documentation: https://docs.gunicorn.org/
Installing
Gunicorn is easy to install, as it does not require external
dependencies or compilation. It runs on Windows only under WSL.
Create a virtualenv, install your application, then installgunicorn.
.. code-block:: text
$ cd hello-app
$ python -m venv venv
$ . venv/bin/activate
$ pip install . # install your application
$ pip install gunicornRunning
The only required argument to Gunicorn tells it how to load your
application. The syntax is {module_import}:{app_variable}.module_import is the dotted import name to the module with your
application. app_variable is the variable with the application. It
can also be a function call (with any arguments) if you're using the
app factory pattern.
.. code-block:: text
# equivalent to 'from hello import app'
$ gunicorn -w 4 'hello:app'
# equivalent to 'from hello import create_app; create_app()'
$ gunicorn -w 4 'hello:create_app()'
Starting gunicorn 20.1.0
Listening at: http://127.0.0.1:8000 (x)
Using worker: sync
Booting worker with pid: x
Booting worker with pid: x
Booting worker with pid: x
Booting worker with pid: xThe -w option specifies the number of processes to run; a starting
value could be CPU * 2. The default is only 1 worker, which is
probably not what you want for the default worker type.
Logs for each request aren't shown by default, only worker info and
errors are shown. To show access logs on stdout, use the--access-logfile=- option.
Binding Externally
Gunicorn should not be run as root because it would cause your
application code to run as root, which is not secure. However, this
means it will not be possible to bind to port 80 or 443. Instead, a
reverse proxy such as :doc:nginx or :doc:apache-httpd should be used
in front of Gunicorn.
You can bind to all external IPs on a non-privileged port using the-b 0.0.0.0 option. Don't do this when using a reverse proxy setup,
otherwise it will be possible to bypass the proxy.
.. code-block:: text
$ gunicorn -w 4 -b 0.0.0.0 'hello:create_app()'
Listening at: http://0.0.0.0:8000 (x)0.0.0.0 is not a valid address to navigate to, you'd use a specific
IP address in your browser.
Async with gevent or eventlet
The default sync worker is appropriate for many use cases. If you need
asynchronous support, Gunicorn provides workers using either gevent_
or eventlet_. This is not the same as Python's async/await, or the
ASGI server spec. You must actually use gevent/eventlet in your own code
to see any benefit to using the workers.
When using either gevent or eventlet, greenlet>=1.0 is required,
otherwise context locals such as request will not work as expected.
When using PyPy, PyPy>=7.3.7 is required.
To use gevent:
.. code-block:: text
$ gunicorn -k gevent 'hello:create_app()'
Starting gunicorn 20.1.0
Listening at: http://127.0.0.1:8000 (x)
Using worker: gevent
Booting worker with pid: xTo use eventlet:
.. code-block:: text
$ gunicorn -k eventlet 'hello:create_app()'
Starting gunicorn 20.1.0
Listening at: http://127.0.0.1:8000 (x)
Using worker: eventlet
Booting worker with pid: x.. _gevent: https://www.gevent.org/
.. _eventlet: https://eventlet.net/
File: docs/deployment/index.rst
Deploying to Production
After developing your application, you'll want to make it available
publicly to other users. When you're developing locally, you're probably
using the built-in development server, debugger, and reloader. These
should not be used in production. Instead, you should use a dedicated
WSGI server or hosting platform, some of which will be described here.
"Production" means "not development", which applies whether you're
serving your application publicly to millions of users or privately /
locally to a single user. Do not use the development server when
deploying to production. It is intended for use only during local
development. It is not designed to be particularly secure, stable, or
efficient.
Self-Hosted Options
Werkzeug is a WSGI application. A WSGI server is used to run the
application, converting incoming HTTP requests to the standard WSGI
environ, and converting outgoing WSGI responses to HTTP responses.
The primary goal of these docs is to familiarize you with the concepts
involved in running a WSGI application using a production WSGI server
and HTTP server. There are many WSGI servers and HTTP servers, with many
configuration possibilities. The pages below discuss the most common
servers, and show the basics of running each one. The next section
discusses platforms that can manage this for you.
.. toctree::
:maxdepth: 1
gunicorn
waitress
mod_wsgi
uwsgi
gevent
eventletWSGI servers have HTTP servers built-in. However, a dedicated HTTP
server may be safer, more efficient, or more capable. Putting an HTTP
server in front of the WSGI server is called a "reverse proxy."
.. toctree::
:maxdepth: 1
proxy_fix
nginx
apache-httpdThis list is not exhaustive, and you should evaluate these and other
servers based on your application's needs. Different servers will have
different capabilities, configuration, and support.
Hosting Platforms
There are many services available for hosting web applications without
needing to maintain your own server, networking, domain, etc. Some
services may have a free tier up to a certain time or bandwidth. Many of
these services use one of the WSGI servers described above, or a similar
interface.
You should evaluate services based on your application's needs.
Different services will have different capabilities, configuration,
pricing, and support.
You'll probably need to :doc:proxy_fix when using most hosting
platforms.
File: docs/deployment/mod_wsgi.rst
mod_wsgi
mod_wsgi_ is a WSGI server integrated with the Apache httpd_ server.
The modern mod_wsgi-express_ command makes it easy to configure and
start the server without needing to write Apache httpd configuration.
- Tightly integrated with Apache httpd.
- Supports Windows directly.
- Requires a compiler and the Apache development headers to install.
- Does not require a reverse proxy setup.
This page outlines the basics of running mod_wsgi-express, not the more
complex installation and configuration with httpd. Be sure to read themod_wsgi-express, mod_wsgi, and Apache httpd_ documentation to
understand what features are available.
.. _mod_wsgi-express: https://pypi.org/project/mod-wsgi/
.. _mod_wsgi: https://modwsgi.readthedocs.io/
.. _Apache httpd: https://httpd.apache.org/
Installing
Installing mod_wsgi requires a compiler and the Apache server and
development headers installed. You will get an error if they are not.
How to install them depends on the OS and package manager that you use.
Create a virtualenv, install your application, then installmod_wsgi.
.. code-block:: text
$ cd hello-app
$ python -m venv venv
$ . venv/bin/activate
$ pip install . # install your application
$ pip install mod_wsgiRunning
The only argument to mod_wsgi-express specifies a script containing
your application, which must be called application. You can
write a small script to import your app with this name, or to create it
if using the app factory pattern.
.. code-block:: python
:caption: wsgi.py
from hello import app
application = app.. code-block:: python
:caption: wsgi.py
from hello import create_app
application = create_app()Now run the mod_wsgi-express start-server command.
.. code-block:: text
$ mod_wsgi-express start-server wsgi.py --processes 4The --processes option specifies the number of worker processes to
run; a starting value could be CPU * 2.
Logs for each request aren't show in the terminal. If an error occurs,
its information is written to the error log file shown when starting the
server.
Binding Externally
Unlike the other WSGI servers in these docs, mod_wsgi can be run as
root to bind to privileged ports like 80 and 443. However, it must be
configured to drop permissions to a different user and group for the
worker processes.
For example, if you created a hello user and group, you should
install your virtualenv and application as that user, then tell
mod_wsgi to drop to that user after starting.
.. code-block:: text
$ sudo /home/hello/venv/bin/mod_wsgi-express start-server \
/home/hello/wsgi.py \
--user hello --group hello --port 80 --processes 4File: docs/deployment/nginx.rst
nginx
nginx_ is a fast, production level HTTP server. When serving your
application with one of the WSGI servers listed in :doc:index, it is
often good or necessary to put a dedicated HTTP server in front of it.
This "reverse proxy" can handle incoming requests, TLS, and other
security and performance concerns better than the WSGI server.
Nginx can be installed using your system package manager, or a pre-built
executable for Windows. Installing and running Nginx itself is outside
the scope of this doc. This page outlines the basics of configuring
Nginx to proxy your application. Be sure to read its documentation to
understand what features are available.
.. _nginx: https://nginx.org/
Domain Name
Acquiring and configuring a domain name is outside the scope of this
doc. In general, you will buy a domain name from a registrar, pay for
server space with a hosting provider, and then point your registrar
at the hosting provider's name servers.
To simulate this, you can also edit your hosts file, located at/etc/hosts on Linux. Add a line that associates a name with the
local IP.
Modern Linux systems may be configured to treat any domain name that
ends with .localhost like this without adding it to the hosts
file.
.. code-block:: python
:caption: /etc/hosts
127.0.0.1 hello.localhostConfiguration
The nginx configuration is located at /etc/nginx/nginx.conf on
Linux. It may be different depending on your operating system. Check the
docs and look for nginx.conf.
Remove or comment out any existing server section. Add a server
section and use the proxy_pass directive to point to the address the
WSGI server is listening on. We'll assume the WSGI server is listening
locally at http://127.0.0.1:8000.
.. code-block:: nginx
:caption: /etc/nginx.conf
server {
listen 80;
server_name _;
location / {
proxy_pass http://127.0.0.1:8000/;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Prefix /;
}
}Then :doc:proxy_fix so that your application uses these headers.
Static Files
If your application has static files such as JavaScript, CSS, and
images, it will be more efficient to let Nginx serve them directly
rather than going through the Python application.
Assuming the static files are expected to be available under the/static/ URL, and are stored at /home/project/static/, add the
following to the server block above.
.. code-block:: nginx
location /static {
alias /home/project/static;
}File: docs/deployment/proxy_fix.rst
Tell Werkzeug it is Behind a Proxy
When using a reverse proxy, or many Python hosting platforms, the proxy
will intercept and forward all external requests to the local WSGI
server.
From the WSGI server and application's perspectives, requests are now
coming from the HTTP server to the local address, rather than from
the remote address to the external server address.
HTTP servers should set X-Forwarded- headers to pass on the real
values to the application. The application can then be told to trust and
use those values by wrapping it with the
:doc:../middleware/proxy_fix middleware provided by Werkzeug.
This middleware should only be used if the application is actually
behind a proxy, and should be configured with the number of proxies that
are chained in front of it. Not all proxies set all the headers. Since
incoming headers can be faked, you must set how many proxies are setting
each header so the middleware knows what to trust.
.. code-block:: python
from werkzeug.middleware.proxy_fix import ProxyFix
app.wsgi_app = ProxyFix(
app.wsgi_app, x_for=1, x_proto=1, x_host=1, x_prefix=1
)Remember, only apply this middleware if you are behind a proxy, and set
the correct number of proxies that set each header. It can be a security
issue if you get this configuration wrong.
File: docs/deployment/uwsgi.rst
uWSGI
uWSGI_ is a fast, compiled server suite with extensive configuration
and capabilities beyond a basic server.
- It can be very performant due to being a compiled program.
- It is complex to configure beyond the basic application, and has so
many options that it can be difficult for beginners to understand. - It does not support Windows (but does run on WSL).
- It requires a compiler to install in some cases.
This page outlines the basics of running uWSGI. Be sure to read its
documentation to understand what features are available.
.. _uWSGI: https://uwsgi-docs.readthedocs.io/en/latest/
Installing
uWSGI has multiple ways to install it. The most straightforward is to
install the pyuwsgi package, which provides precompiled wheels for
common platforms. However, it does not provide SSL support, which can be
provided with a reverse proxy instead.
Create a virtualenv, install your application, then install pyuwsgi.
.. code-block:: text
$ cd hello-app
$ python -m venv venv
$ . venv/bin/activate
$ pip install . # install your application
$ pip install pyuwsgiIf you have a compiler available, you can install the uwsgi package
instead. Or install the pyuwsgi package from sdist instead of wheel.
Either method will include SSL support.
.. code-block:: text
$ pip install uwsgi
# or
$ pip install --no-binary pyuwsgi pyuwsgiRunning
The most basic way to run uWSGI is to tell it to start an HTTP server
and import your application.
.. code-block:: text
$ uwsgi --http 127.0.0.1:8000 --master -p 4 -w hello:app
*** Starting uWSGI 2.0.20 (64bit) on [x] ***
*** Operational MODE: preforking ***
mounting hello:app on /
spawned uWSGI master process (pid: x)
spawned uWSGI worker 1 (pid: x, cores: 1)
spawned uWSGI worker 2 (pid: x, cores: 1)
spawned uWSGI worker 3 (pid: x, cores: 1)
spawned uWSGI worker 4 (pid: x, cores: 1)
spawned uWSGI http 1 (pid: x)If you're using the app factory pattern, you'll need to create a small
Python file to create the app, then point uWSGI at that.
.. code-block:: python
:caption: wsgi.py
from hello import create_app
app = create_app().. code-block:: text
$ uwsgi --http 127.0.0.1:8000 --master -p 4 -w wsgi:appThe --http option starts an HTTP server at 127.0.0.1 port 8000. The--master option specifies the standard worker manager. The -p
option starts 4 worker processes; a starting value could be CPU * 2.
The -w option tells uWSGI how to import your application
Binding Externally
uWSGI should not be run as root with the configuration shown in this doc
because it would cause your application code to run as root, which is
not secure. However, this means it will not be possible to bind to port
80 or 443. Instead, a reverse proxy such as :doc:nginx or
:doc:apache-httpd should be used in front of uWSGI. It is possible to
run uWSGI as root securely, but that is beyond the scope of this doc.
uWSGI has optimized integration with Nginx uWSGI_ andApache mod_proxy_uwsgi_, and possibly other servers, instead of using
a standard HTTP proxy. That configuration is beyond the scope of this
doc, see the links for more information.
.. _Nginx uWSGI: https://uwsgi-docs.readthedocs.io/en/latest/Nginx.html
.. _Apache mod_proxy_uwsgi: https://uwsgi-docs.readthedocs.io/en/latest/Apache.html#mod-proxy-uwsgi
You can bind to all external IPs on a non-privileged port using the--http 0.0.0.0:8000 option. Don't do this when using a reverse proxy
setup, otherwise it will be possible to bypass the proxy.
.. code-block:: text
$ uwsgi --http 0.0.0.0:8000 --master -p 4 -w wsgi:app0.0.0.0 is not a valid address to navigate to, you'd use a specific
IP address in your browser.
Async with gevent
The default sync worker is appropriate for many use cases. If you need
asynchronous support, uWSGI provides a gevent_ worker. This is not the
same as Python's async/await, or the ASGI server spec. You must
actually use gevent in your own code to see any benefit to using the
worker.
When using gevent, greenlet>=1.0 is required, otherwise context locals
such as request will not work as expected. When using PyPy,
PyPy>=7.3.7 is required.
.. code-block:: text
$ uwsgi --http 127.0.0.1:8000 --master --gevent 100 -w wsgi:app
*** Starting uWSGI 2.0.20 (64bit) on [x] ***
*** Operational MODE: async ***
mounting hello:app on /
spawned uWSGI master process (pid: x)
spawned uWSGI worker 1 (pid: x, cores: 100)
spawned uWSGI http 1 (pid: x)
*** running gevent loop engine [addr:x] ***.. _gevent: https://www.gevent.org/
2. Official Technical Reference & Guides (pallets/website)
File: README.md
Pallets Projects Website
This is the code and content for https://palletsprojects.com. Static content
from the content folder is loaded when the server is started then served
quickly from memory or cache. This allows editing content as plain files like a
static site, while also taking advantage of Python and a full application.
File: content/blog/pycon-2018-click/index.md
title = "PyCon and Adding Maintainers to Click"
author_name = "David Lord"
published = 2018-06-01
tags = ["meta"]In May I attended PyCon US 2018 in Cleveland, Ohio. It's a great opportunity to
meet people interested in the Pallets projects and Python web applications. It
can be a little intimidating, but also a lot of fun. The biggest difficulty is
that there are too many things to do, and I always wish everyone could have a
few more days together.
During the main conference, while talks are happening, anyone can organize "open
spaces," impromptu meetings for any topic. I organized a Pallets open space, and
we had a huge turnout. I was kind of unprepared for the size, so we started with
people asking me questions, and then split up into tables for new users, Flask,
Click, and Jinja.
For up to four days after the talks, developers get together for sprints,
working together to contribute to Python open source projects. Experienced
developers help new ones learn how to contribute, and everyone gets to learn
about new projects and meet the developers behind them.
At the open space, I had mentioned that no one had really been maintaining Click
for the past year. It turns out a lot of people use Click. They came motivated
from the open space to contribute during the sprint. Some were new to
contributing, but they all had one thing in common: they knew how Click was
being used more than I did! So I took a chance and gave them all write
permissions to the repository. Click started at ~250 open issues and 68 pull
requests. After 2 days, it was at 140 issues and 22 pull requests. Wow! With
that success, I'm officially welcoming all these new maintainers to the Pallets
Click team. While Click stole the show, we had great contributions to Werkzeug,
Flask, and Jinja as well.
If you want to get involved, a great way is to
watch our repositories on GitHub.
You'll get notifications for each issue, so you can see what's happening and
start contributing. You can help by triaging issues, improving tests and
documentation, and fixing bugs. If your company uses a Pallets project like
Flask, Click, or Jinja, consider pointing them to our
PSF donation page. Donations will help get maintainers to more
events so we can do more sprints like this one. Thank you to everyone at PyCon
and in the community for making Pallets a success!
File: content/blog/blinker-1-6-released.md
title = "Blinker 1.6 Released"
author_name = "P G Jones"
published = 2023-04-02
tags = ["releases"]Signalling allows for applications to be decoupled by allowing designated
receivers to be informed when an action has taken place (the signal). Flask and
Quart both utilise the excellent Blinker
library to support signals, and it is version 1.6 of this library that has been
released.
This is the second major release of Blinker since maintenance transferred to the
Pallets-eco organisation, and represents a desire to
maintain it for the benefit of Flask, Quart, and indeed Blinker users.
The Changelog for 1.6 is
headlined by a mondernisation of the project structure which should ensure
easier maintenance into the years to come. In addition, we've added:
- an ability to temporarily mute signals,
- support for int senders,
- support for async (coroutine) receivers,
- and we've type hinted the project.
File: content/blog/click-7-0-released.md
title = "Click 7.0 Released"
author_name = "David Lord"
published = 2018-09-25
tags = ["releases"]The Pallets team is pleased to release Click 7.0. Thank you to everyone who contributed
online and in person at the PyCon US 2018 sprint! With the help of the community as well
as some new maintainers, we've managed to resolve hundreds of long standing issues and
pull requests.
Due to the length of time since the last release, there are a significant number of new
features and
fixes. Check out the changelog
for a list of all code changes and links to the relevant issues. Changes include:
- Shell autocompletion has improved in a number of areas.
- Native ZSH completion was added, and supports its enhanced parameter
documentation. - The choice type can be completed.
- Completion correctly handles chained commands, spaces, defaults, and partial
completions. - Parameters can provide a callback to customize completion.
- Native ZSH completion was added, and supports its enhanced parameter
- On Windows
click.echocan now output more than 16k characters in one call. On
Windows 7, a 64k limit on binary stream output is also worked around. click.getcharreturns Unicode on Windows.- When piping input and output, more cases of closed pipes are detected and handled
instead of raising errors. - The
CliRunnerused for testing separates stdout and stderr. - New
DateTimeandFloatRangeparameter types. - Flags to mark a parameter as hidden or deprecated.
- Numerous improvements and fixes to i/o, help, parameters, and testing.
Read the Docs
Click is the first Pallets project to move its docs to Read the Docs. Our projects
currently use a custom builder and hosting, but this became too difficult with limited
maintainer time. Thank you to everyone at RTD who helped with the transition!
The new URL for the docs is https://click.palletsprojects.com/. The
old https://click.palletsprojects.com/ domain will redirect to the new one while we
continue to migrate, but will eventually go away. Please use the new URL going forward.
Click's docs use a custom Sphinx theme and extensions. As part of the move, these were
extracted to a separate Python package.
Install Pallets-Sphinx-Themes to use
Click's theme when writing extensions for a more cohesive look.
Install or Upgrade
Install from PyPI with pip:
pip install -U ClickGet Involved
Click and the Pallets team depends on you, the community. Whether you report issues,
write documentation, create patches, or answer questions, we appreciate all the help you
provide. Star the project on GitHub to show support,
and watch the
repository to see discussions and pull requests as they happen.
Donate
We now accept donations through the Python Software Foundation in order to support our
efforts to maintain the projects and grow the community. **Click here to donate.
**
File: content/blog/click-7-1-released.md
title = "Click 7.1 Released"
author_name = "David Lord"
published = 2020-03-09
tags = ["releases"]The Pallets team is pleased to release Click 7.1.
Read the full changelog
to understand what may affect your code when upgrading.
- Drop support for Python 3.4. This will be the last version to
support Python 2.7 and 3.5. - Multiple fixes in low-level Windows compatibility code.
- Colored output in Jupyter notebooks on Linux and Mac.
- Updated Bash and ZSH tab completion support. Add support for Fish.
- Better formatting when option help text contains newlines.
This also fixes a packaging issue from 7.0 where the project name in the
package metadata was changed to "Click" with an upper case "C". This has
been reverted, the name is now correctly reported in all lower case, "click".
Version 8.0 Coming Soon
As outlined in Ending Python 2 Support,
7.1.x will be the last version to support Python 2.7 and 3.5. The next
version will be 8.0 and will support Python 3.6 and newer.
Install or Upgrade
Install from PyPI with pip:
pip install -U clickDonate to Support Pallets
The Pallets organization accepts donations as part of the non-profit
Python Software Foundation (PSF). Donations through the PSF support our
efforts to maintain the projects and grow the community.
File: content/blog/community-survey-2019.md
title = "Take the Pallets / Flask Community Survey"
author_name = "David Lord"
published = 2019-01-29
tags = ["meta"]One of my goals as a Pallets maintainer is to build the community around our projects.
The Pallets projects (Flask, Jinja, Click, etc.) are downloaded millions of times each
month, but it's hard to get a clear picture of what our users do and want with downloads
stats only. We'd like to learn about you and your projects. Knowing more about our
community will help us decide what to focus on to grow the Pallets projects.
Click here to take our Community Survey.
Please share the link with friends, coworkers, and the internet! We're looking forward
to seeing everyone's responses! You can follow https://twitter.com/PalletsTeam or this
blog to get updates about Pallets, including the survey results.
File: content/blog/donate.md
title = "Donate to Support Pallets"
author_name = "David Lord"
published = 2018-04-26
tags = ["meta"]Pallets is excited to announce that we have joined the Python Software
Foundation's Fiscal Sponsorship program. As a non-profit organization,
the PSF will accept donations on behalf of Pallets into a dedicated
account.
Donations enable more attention from maintainers, which translates into
more time devoted to fixing bugs, developing features, and making
quicker releases. Click here to donate today.
The Pallets organization develops and supports Flask, Jinja, Werkzeug,
Click, and other Python libraries. These libraries power applications of
all sizes around the world, and are downloaded millions of times each
month. Despite their popularity, the projects are primarily maintained
by only a few developers. The goal of Pallets is to grow the community
around these projects to create a sustainable group of contributors and
users.
Your donation will help:
- Allow maintainers to devote more of their time to the projects.
- Recognize outstanding contributors in the community.
- Allow maintainers and community members to attend conferences.
- Acquire infrastructure and developer tools.
- Sponsor local meetup events.
- And more!
If you like the work we do, you may donate as an
individual. If your employer uses Flask or any of the Pallets projects,
reach out to them to donate.
Flask and the Pallets team depends on you, the community. We thank you
for all the contributions you've already made, and look forward to
growing the community even more.
File: content/blog/end-python2-prereleases.md
title = "New Flask, Jinja2, Click, Werkzeug, ItsDangerous, and MarkupSafe major release candidates"
author_name = "Philip Jones"
published = 2021-04-29
tags = ["releases"]The Pallets team is pleased to announce that release candidates are
now available for the next major version of each project.
Check out the changelogs for every project to see what's new:
Please help us prepare for the final release by testing the prerelease
versions and reporting any issues you have. To upgrade to pre-releases
with pip, use the --pre flag, e.g.:
pip install -U --pre FlaskThese new major versions all drop support for Python 2 and 3.5,
requiring Python 3.6 as the minimum supported version.
Release highlights
These are a few highlights, see the changelogs linked above for the
full release details. More detailed posts about each project's
highlights will be made with the final releases.
- All projects (Jinja coming soon) now provide type hints.
- Flask gains limited
async/awaitsupport. - Flask supports nested blueprints.
- Flask tells the browser to cache static files more intelligently, so
changes to CSS or images show up immediately. - Flask introduces short form route decorators, such as
@app.post()
as a shortcut for@app.route(methods=["POST"]). - Click's shell completion system has been rewritten.
- Click will now prompt for values where they are omitted.
- Werkzeug now provides
send_fileandsend_from_directoryhelpers. - Werkzeug's test client always returns a
Responseobject. - Werkzeug's multipart parsing performance increases by a factor of 15.
Release date
The Pallets team is aiming to release on or before PyCon 2021, i.e. a
target release date of the 11th of May 2021.
File: content/blog/ending-python2-support.md
title = "Ending Python 2 Support"
author_name = "David Lord"
published = 2019-12-17
tags = ["meta"]Upstream support for Python 2.7 is ending on January 1, 2020.
Pallets is joining the community of open source projects
ending support for Python 2 at that time. Our statement and support plan
are based on PyTest's announcement.
We will be dropping support for Python 2.7 as well as Python 3.5 and
below, as their support windows have ended or will end around the same
time. Future releases of each Pallets project will only support Python
versions still supported upstream, which can be found in the
Python Developer's Guide.
The last version branch of each core project to support Python 2.7
and Python 3.5 are:
- Flask 1.1.x
- Werkzeug 1.0.x
- Click 7.x
- Jinja 2.11.x
- ItsDangerous 1.1.x
- MarkupSafe 1.1.x
Each project will receive a major version bump to indicate support
for only 3.6+:
- Flask 2.0
- Werkzeug 2.0
- Click 8.0
- Jinja 3.0
- ItsDangerous 2.0
- MarkupSafe 2.0
Thanks to the python_requires package metadata, Python 2.7 and
3.5 users with a modern pip version will install the last supported
version automatically even if later versions are available.
The team will no longer backport patches for unsupported versions, but
the branches will continue to exist. The team will be happy to
accept patches contributed by the community for any severe security and
usability issues until mid-2020.
We made this decision based on multiple factors. Foremost is ease of
community contribution and maintainer availability. As time goes on,
fewer contributors have used or are familiar with the differences
between Python 2 and 3. Contributors and maintainers must keep track of
an ever growing list of obscure compatibility issues and workarounds,
and cannot use many modern features.
Over the last two years, we've talked to many developers and teams at
conferences and meetups and heard overwhelming support for the move to
Python 3. This is backed up by data collected from our community in a
survey we ran during January 2019, with 92% of respondents already using
or actively upgrading to Python 3. The PSF developer survey and
PyPI statistics report similar majorities and show adoption continuing
to increase.
Thank you to everyone in the community for your support, and to everyone
who has made this transition a reality. We look forward to continuing
to develop the Pallets projects with you!
File: content/blog/flask-0-11-released.md
title = "Flask 0.11 Released"
author_name = "Armin Ronacher"
published = 2016-05-29
tags = ["releases"]After a very long, long waiting time Flask finally got a new release. There
really was no good reason that there has not been a release in such a long time
but unfortunately once things are postponed for too long a certain release
anxiety kicks in.
In this case this was long tagged as 1.0 but we decided for renaming it to
0.11 and back out some of the more controversial changes. In particular the
new command line interface for Flask was modified a bit to not depend on some
specific functionality in the supporting Click library.
Highlights of this release are the improved development experience which now
stalls the browser on reload instead of bringing up a "connection reset"
page and the new command line support.
Future Plans
This is also the first Flask release under the new pallets organization and
from now on we hope to bring you releases more frequently. Ideally with the
next release we also update the website to find a new home for the showcase,
flask extension list as well as the snippet section to allow the community to
take care of those things themselves.
Changelog
- Added support to serializing top-level arrays to
flask.jsonify. This
introduces a security risk in ancient browsers. See
json-security
for details. - Added before_render_template signal.
- Added
**kwargstoflask.Test.test_clientto support passing
additional keyword arguments to the constructor offlask.Flask.test_client_class. - Added
SESSION_REFRESH_EACH_REQUESTconfig key that controls the
set-cookie behavior. If set toTruea permanent session will be
refreshed each request and get their lifetime extended, if set toFalseit will only be modified if the session actually modifies.
Non permanent sessions are not affected by this and will always
expire if the browser window closes. - Made Flask support custom JSON mimetypes for incoming data.
- Added support for returning tuples in the form
(response, headers)
from a view function. - Added
flask.Config.from_json. - Added
flask.Flask.config_class. - Added
flask.config.Config.get_namespace. - Templates are no longer automatically reloaded outside of debug mode. This
can be configured with the newTEMPLATES_AUTO_RELOADconfig key. - Added a workaround for a limitation in Python 3.3's namespace loader.
- Added support for explicit root paths when using Python 3.3's namespace
packages. - Added the
flaskcommand and theflask.climodule to start the local
debug server through the click CLI system. This is recommended over the oldflask.run()method as it works faster and more reliable due to a
different design and also replacesFlask-Script. - Error handlers that match specific classes are now checked first,
thereby allowing catching exceptions that are subclasses of HTTP
exceptions (inwerkzeug.exceptions). This makes it possible
for an extension author to create exceptions that will by default
result in the HTTP error of their choosing, but may be caught with
a custom error handler if desired. - Added
flask.Config.from_mapping. - Flask will now log by default even if debug is disabled. The log format is
now hardcoded but the default log handling can be disabled through theLOGGER_HANDLER_POLICYconfiguration key. - Removed deprecated module functionality.
- Added the
EXPLAIN_TEMPLATE_LOADINGconfig flag which when enabled will
instruct Flask to explain how it locates templates. This should help
users debug when the wrong templates are loaded. - Enforce blueprint handling in the order they were registered for template
loading. - Ported test suite to py.test.
- Deprecated
request.jsonin favour ofrequest.get_json(). - Add "pretty" and "compressed" separators definitions in jsonify() method.
Reduces JSON response size when JSONIFY_PRETTYPRINT_REGULAR=False by removing
unnecessary white space included by default after separators. - JSON responses are now terminated with a newline character, because it is a
convention that UNIX text files end with a newline and some clients don't
deal well when this newline is missing. See
https://github.com/pallets/flask/pull/1262 -- this came up originally as a
part of https://github.com/kennethreitz/httpbin/issues/168 - The automatically provided
OPTIONSmethod is now correctly disabled if
the user registered an overriding rule with the lowercase-versionoptions(issue#1288). flask.json.jsonify
now supports thedatetime.datetype (pull request#1326).- Don't leak exception info of already caught exceptions to context teardown
handlers (pull request#1393). - Allow custom Jinja environment subclasses (pull
request#1422). flask.gnow haspop()
andsetdefaultmethods.- Turn on autoescape for
flask.templating.render_template_stringby default
(pull request#1515). flask.extis now deprecated (pull
request#1484).send_from_directory
now raises BadRequest if the filename is invalid on
the server OS (pull request#1763).- Added the
JSONIFY_MIMETYPEconfiguration variable (pull
request#1728). - Exceptions during teardown handling will no longer leave bad application
contexts lingering around.