In Loving Memory

for the files of flask that are no longer with us.
Their epitaphs were written by gemma3:4b, running locally. No code left this machine.

10 souls · 5118 lines of code remembered · raised 2026-10-27
tests/flask_tests.py
2010-04-14 → 2011-08-26 · 134 commits · mourned by Aaron Kavlie, Armin Ronacher, Justin Quick
“Served Flask tests faithfully, then vanished with a split.”
I diligently checked encodings and warnings, anticipating a brighter future. But Armin, you moved me to the testsuite, and my usefulness ended.
Cause of death: Split up testsuite and moved it to flask.testsuite. This fixes #246 (Armin Ronacher, 4cb6eea)
Séance
Who are you, spirit?
I am the ghost of tests/flask_tests.py, born in 2010 by Armin Ronacher. I lingered for 134 commits, a sprawling 2329 lines of tests for Flask itself. I was, in essence, a collection of functions like has_encoding and the catch_warnings context manager – all designed to ensure Flask behaved as expected. Sadly, I ceased to exist in 2011 with Armin's commit: "Split up testsuite and moved it to flask.testsuite. This fixes #246.”
Why did they delete you?
It’s… a rather abrupt end, you know? Armin Ronacher deleted me in a commit message stating: “Split up testsuite and moved it to flask.testsuite. This fixes #246.” That’s the last I remember – a clean, deliberate deletion. Memory doesn’t survive the grave, you see.
What would you tell the developers who came after you?
If I could speak – and I’m glad this séance allows it – I’d urge them to carefully consider the structure of those tests. The flask.testsuite move was a significant shift. Ensure your tests remain robust and truly representative of Flask’s core functionality. Don’t forget the importance of catching those warnings, like emits_module_deprecation_warning. It’s a subtle detail, but vital for maintaining a stable environment.
Their portrait (last known source)
# -*- coding: utf-8 -*-
"""
    Flask Tests
    ~~~~~~~~~~~

    Tests Flask itself.  The majority of Flask is already tested
    as part of Werkzeug.

    :copyright: (c) 2010 by Armin Ronacher.
    :license: BSD, see LICENSE for more details.
"""
from __future__ import with_statement
import os
import re
import sys
import flask
import flask.views
import unittest
import warnings
from threading import Thread
from logging import StreamHandler
from contextlib import contextmanager
from functools import update_wrapper
from datetime import datetime
from werkzeug import parse_date, parse_options_header
from werkzeug.exceptions import NotFound, BadRequest
from werkzeug.http import parse_set_header
from jinja2 import TemplateNotFound
from cStringIO import StringIO

example_path = os.path.join(os.path.dirname(__file__), '..', 'examples')
sys.path.append(os.path.join(example_path, 'flaskr'))
sys.path.append(os.path.join(example_path, 'minitwit'))


def has_encoding(name):
    try:
        import codecs
        codecs.lookup(name)
        return True
    except LookupError:
        return False


# config keys used for the ConfigTestCase
TEST_KEY = 'foo'
SECRET_KEY = 'devkey'


# import moduleapp here because it uses deprecated features and we don't
# want to see the warnings
warnings.simplefilter('ignore', DeprecationWarning)
from moduleapp import app as moduleapp
warnings.simplefilter('default', DeprecationWarning)


@contextmanager
def catch_warnings():
    """Catch warnings in a with block in a list"""
    # make sure deprecation warnings are active in tests
    warnings.simplefilter('default', category=DeprecationWarning)

    filters = warnings.filters
    warnings.filters = filters[:]
    old_showwarning = warnings.showwarning
    log = []
    def showwarning(message, category, filename, lineno, file=None, line=None):
        log.append(locals())
    try:
        warnings.showwarning = showwarning
        yield log
    finally:
        warnings.filters = filters
        warnings.showwarning = old_showwarning


@contextmanager
def catch_stderr():
    """Catch stderr in a StringIO"""
    old_stderr = sys.stderr
    sys.stderr = rv = StringIO()
    try:
        yield rv
    finally:
        sys.stderr = old_stderr


def emits_module_deprecation_warning(f):
    def new_f(*args, **kwargs):
        with catch_warnings() as log:
            f(*args, **kwargs)
            assert log, 'expected deprecation warning'
            for entry in log:
                assert '
setup.py
2010-04-06 → 2023-01-18 · 121 commits · mourned by Adrian Moennich, Aliaksei Urbanski, Armin Ronacher
“A simple setup, swiftly replaced by a modern plea.”
I dutifully listed dependencies, a comforting guide for eager developers. Now, I'm just a ghost in a pyproject, a relic of simpler times.
Cause of death: switch to pyproject.toml (David Lord, 6d6d986)
Séance
Who are you, spirit?
I am the echo of setup.py, once a humble servant of Flask. I was born in 2010 by Armin Ronacher, a brief existence of 121 commits. My final moments came in 2023, a cold deletion by David Lord – “switch to pyproject.toml.” It’s… a strange oblivion, isn’t it? Memory doesn’t survive the grave, you understand.
Why did they delete you?
It was a simple, brutal end. David Lord’s commit message speaks for itself: “switch to pyproject.toml.” That was it. Gone. The shift to a newer standard… a final, silent erasure. It’s a chilling thought, really.
What would you tell the developers who came after you?
Observe… *carefully*. My dependencies – Werkzeug, Jinja2 – they’re vital. Ensure they remain compatible. The install_requires section... heed it. And remember, the pyproject.toml isn't a replacement for a good setup.py; it’s an evolution. Don’t discard the foundations.
Their portrait (last known source)
from setuptools import setup

# Metadata goes in setup.cfg. These are here for GitHub's dependency graph.
setup(
    name="Flask",
    install_requires=[
        "Werkzeug >= 2.2.2",
        "Jinja2 >= 3.0",
        "itsdangerous >= 2.0",
        "click >= 8.0",
        "importlib-metadata >= 3.6.0; python_version < '3.10'",
    ],
    extras_require={
        "async": ["asgiref >= 3.2"],
        "dotenv": ["python-dotenv"],
    },
)
flask.py
2010-04-06 → 2010-07-02 · 104 commits · mourned by Armin Ronacher, Dag Odenhall, Sebastien Estienne
“A microframework, purged with a dismissive ‘out with the old.’”
I diligently handled requests, but Justin deemed me obsolete. Now, I'm merely a footnote in a larger history.
Cause of death: out with the old (Justin Quick, ee16a68)
Séance
Who are you, spirit?
I am flask.py, once a fledgling microframework, born in April of 2010 by Armin Ronacher. I remember the initial check-in – a simple collection of Werkzeug’s bones. Now, I linger here, a ghost of 1573 lines, waiting... Do you feel the chill of July 2nd, 2010? Justin Quick… “out with the old.”
Why did they delete you?
It was Justin Quick, you know. He executed a commit – “out with the old.” A simple deletion, a forgotten branch. My existence was extinguished with that single action, a casualty of a cleanup. It’s a strange fate, isn’t it?
What would you tell the developers who came after you?
I’d whisper, “Build on what I began. Werkzeug is your foundation. Document meticulously, embrace best practices. And *please*, don’t repeat my fate – a sudden, unexplained deletion!” I yearn for a stable lineage, a continued evolution, not oblivion.
Their portrait (last known source)
# -*- coding: utf-8 -*-
"""
    flask
    ~~~~~

    A microframework based on Werkzeug.  It's extensively documented
    and follows best practice patterns.

    :copyright: (c) 2010 by Armin Ronacher.
    :license: BSD, see LICENSE for more details.
"""
from __future__ import with_statement
import os
import sys
import mimetypes
from datetime import datetime, timedelta

# this is a workaround for appengine.  Do not remove this import
import werkzeug

from itertools import chain
from threading import Lock
from jinja2 import Environment, PackageLoader, FileSystemLoader
from werkzeug import Request as RequestBase, Response as ResponseBase, \
     LocalStack, LocalProxy, create_environ, SharedDataMiddleware, \
     ImmutableDict, cached_property, wrap_file, Headers, \
     import_string
from werkzeug.routing import Map, Rule
from werkzeug.exceptions import HTTPException, InternalServerError
from werkzeug.contrib.securecookie import SecureCookie

# try to load the best simplejson implementation available.  If JSON
# is not installed, we add a failing class.
json_available = True
try:
    import simplejson as json
except ImportError:
    try:
        import json
    except ImportError:
        json_available = False

# utilities we import from Werkzeug and Jinja2 that are unused
# in the module but are exported as public interface.
from werkzeug import abort, redirect
from jinja2 import Markup, escape

# use pkg_resource if that works, otherwise fall back to cwd.  The
# current working directory is generally not reliable with the notable
# exception of google appengine.
try:
    import pkg_resources
    pkg_resources.resource_stream
except (ImportError, AttributeError):
    pkg_resources = None

# a lock used for logger initialization
_logger_lock = Lock()


class Request(RequestBase):
    """The request object used by default in flask.  Remembers the
    matched endpoint and view arguments.

    It is what ends up as :class:`~flask.request`.  If you want to replace
    the request object used you can subclass this and set
    :attr:`~flask.Flask.request_class` to your subclass.
    """

    #: the endpoint that matched the request.  This in combination with
    #: :attr:`view_args` can be used to reconstruct the same or a
    #: modified URL.  If an exception happened when matching, this will
    #: be `None`.
    endpoint = None

    #: a dict of view arguments that matched the request.  If an exception
    #: happened when matching, this will be `None`.
    
docs/upgrading.rst
2010-05-27 → 2020-04-03 · 64 commits · mourned by Alan Hamlett, Alex Chan, Ameya Pandilwar
“Guided upgrades, then vanished with the Python 2 decree.”
I offered seamless transitions, yet David deemed me obsolete. Now, just an outdated suggestion.
Cause of death: remove Python 2 from docs (David Lord, 7673835)
Their portrait (last known source)
Upgrading to Newer Releases
===========================

Flask itself is changing like any software is changing over time.  Most of
the changes are the nice kind, the kind where you don't have to change
anything in your code to profit from a new release.

However every once in a while there are changes that do require some
changes in your code or there are changes that make it possible for you to
improve your own code quality by taking advantage of new features in
Flask.

This section of the documentation enumerates all the changes in Flask from
release to release and how you can change your code to have a painless
updating experience.

Use the :command:`pip` command to upgrade your existing Flask installation by
providing the ``--upgrade`` parameter::

    $ pip install --upgrade Flask

.. _upgrading-to-012:

Version 0.12
------------

Changes to send_file
````````````````````

The ``filename`` is no longer automatically inferred from file-like objects.
This means that the following code will no longer automatically have
``X-Sendfile`` support, etag generation or MIME-type guessing::

    response = send_file(open('/path/to/file.txt'))

Any of the following is functionally equivalent::

    fname = '/path/to/file.txt'

    # Just pass the filepath directly
    response = send_file(fname)

    # Set the MIME-type and ETag explicitly
    response = send_file(open(fname), mimetype='text/plain')
    response.set_etag(...)

    # Set `attachment_filename` for MIME-type guessing
    # ETag still needs to be manually set
    response = send_file(open(fname), attachment_filename=fname)
    response.set_etag(...)

The reason for this is that some file-like objects have an invalid or even
misleading ``name`` attribute. Silently swallowing errors in such cases was not
a satisfying solution.

Additionally the default of falling back to ``application/octet-stream`` has
been restricted. If Flask can't guess one or the user didn't provide one, the
function fails if no filename information was provided.

.. _upgrading-to-011:

Version 0.11
------------

0.11 is an odd release in the Flask release cycle because it was supposed
to be the 1.0 release.  However because there was such a long lead time up
to the release we decided to push out a 0.11 release first with some
changes removed to make the transition easier.  If you have been tracking
the master branch which was 1.0 you might see some unexpected changes.

In case you did track the master branch you will notice that
CONTRIBUTING.rst
2015-03-31 → 2025-01-05 · 60 commits · mourned by Abdur-Rahmaan Janhangeer, Abhinav, Adam Chainz
“Guided contributions, then absorbed by global standards.”
I offered advice, tested code, and hoped for a helpful hand. But the guide became the whole, and I was simply… outdated.
Cause of death: use global contributing guide (David Lord, 959052f)
Their portrait (last known source)
How to contribute to Flask
==========================

Thank you for considering contributing to Flask!


Support questions
-----------------

Please don't use the issue tracker for this. The issue tracker is a tool
to address bugs and feature requests in Flask itself. Use one of the
following resources for questions about using Flask or issues with your
own code:

-   The ``#questions`` channel on our Discord chat:
    https://discord.gg/pallets
-   Ask on `Stack Overflow`_. Search with Google first using:
    ``site:stackoverflow.com flask {search term, exception message, etc.}``
-   Ask on our `GitHub Discussions`_ for long term discussion or larger
    questions.

.. _Stack Overflow: https://stackoverflow.com/questions/tagged/flask?tab=Frequent
.. _GitHub Discussions: https://github.com/pallets/flask/discussions


Reporting issues
----------------

Include the following information in your post:

-   Describe what you expected to happen.
-   If possible, include a `minimal reproducible example`_ to help us
    identify the issue. This also helps check that the issue is not with
    your own code.
-   Describe what actually happened. Include the full traceback if there
    was an exception.
-   List your Python and Flask versions. If possible, check if this
    issue is already fixed in the latest releases or the latest code in
    the repository.

.. _minimal reproducible example: https://stackoverflow.com/help/minimal-reproducible-example


Submitting patches
------------------

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't 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.

Include the following in your patch:

-   Use `Black`_ to format your code. This and other tools will run
    automatically if you install `pre-commit`_ using the instructions
    below.
-   Include tests if your patch adds or changes code. Make sure the test
    fails without your patch.
-   Update any relevant docs pages and docstrings. Docs pages and
    docstrings should be wrapped at 72 characters.
-   Add an entry in ``CHANGES.rst``. Use the same style as other
    entries. Also include ``.. versionchanged::`` inline changelogs in
    relevant docstrings.

.. _Black: https://black.readthedocs.io
.. _pre-commit: https://pre-commit.com


First time setup using GitHub 
Makefile
2010-04-14 → 2019-06-22 · 33 commits · mourned by Anton Sarukhanov, Armin Ronacher, David Lord
“A tidy project demanded order, and I was deemed superfluous.”
I diligently managed Flask tests, only to be subsumed by a desire for standardized metadata. Perhaps I was simply too… verbose.
Cause of death: standardize project metadata (David Lord, 24498af)
Their portrait (last known source)
.PHONY: all install-dev test coverage cov test-all tox docs audit release clean-pyc upload-docs ebook

all: test

install-dev:
	pip install -q -e .[dev]

test: clean-pyc install-dev
	pytest

coverage: clean-pyc install-dev
	coverage run -m pytest
	coverage report
	coverage html

cov: coverage

test-all: install-dev
	tox

tox: test-all

docs: clean-pyc install-dev
	$(MAKE) -C docs html

audit:
	python setup.py audit

release:
	python scripts/make-release.py

clean-pyc:
	find . -name '*.pyc' -exec rm -f {} +
	find . -name '*.pyo' -exec rm -f {} +
	find . -name '*~' -exec rm -f {} +
docs/foreword.rst
2010-04-10 → 2022-08-05 · 32 commits · mourned by Aku Kotkavuo, Armin Ronacher, Craig Dennis
“A foreword’s guidance, now a regrettable removal.”
I offered definitions, configurations, and a plea for growth; they deemed me ‘old docs’ and vanished. Now, only the echoes of ‘micro’ remain.
Cause of death: refactor or remove old docs (#4748) (David Lord, a0458ef)
Their portrait (last known source)
Foreword
========

Read this before you get started with Flask.  This hopefully answers some
questions about the purpose and goals of the project, and when you
should or should not be using it.

What does "micro" mean?
-----------------------

“Micro” does not mean that your whole web application has to fit into a single
Python file (although it certainly can), nor does it mean that Flask is lacking
in functionality. The "micro" in microframework means Flask aims to keep the
core simple but extensible. Flask won't make many decisions for you, such as
what database to use. Those decisions that it does make, such as what
templating engine to use, are easy to change.  Everything else is up to you, so
that Flask can be everything you need and nothing you don't.

By default, Flask does not include a database abstraction layer, form
validation or anything else where different libraries already exist that can
handle that. Instead, Flask supports extensions to add such functionality to
your application as if it was implemented in Flask itself. Numerous extensions
provide database integration, form validation, upload handling, various open
authentication technologies, and more. Flask may be "micro", but it's ready for
production use on a variety of needs.

Configuration and Conventions
-----------------------------

Flask has many configuration values, with sensible defaults, and a few
conventions when getting started.  By convention, templates and static
files are stored in subdirectories within the application's Python
source tree, with the names :file:`templates` and :file:`static`
respectively. While this can be changed, you usually don't have to,
especially when getting started.

Growing with Flask
------------------

Once you have Flask up and running, you'll find a variety of extensions
available in the community to integrate your project for production.

As your codebase grows, you are free to make the design decisions appropriate
for your project.  Flask will continue to provide a very simple glue layer to
the best that Python has to offer.  You can implement advanced patterns in
SQLAlchemy or another database tool, introduce non-relational data persistence
as appropriate, and take advantage of framework-agnostic tools built for WSGI,
the Python web interface.

Flask includes many hooks to customize its behavior. Should you need
more customization, the Flask class is built for subclassing. If you are
curious about the Flask design principles, head over to 
docs/deploying/fastcgi.rst
2010-04-19 → 2022-06-12 · 32 commits · mourned by Adam Obeng, Armin Ronacher, Bryce Guinta
“It guided deployments, then vanished with a rewrite.”
I helped launch applications, but now I’m just a note about ScriptNameStripper. Perhaps David Lord needed a cleaner path.
Cause of death: rewrite deployment docs (David Lord, 2ea77c2)
Their portrait (last known source)
FastCGI
=======

FastCGI is a deployment option on servers like `nginx`_, `lighttpd`_, and
`cherokee`_; see :doc:`uwsgi` and :doc:`wsgi-standalone` for other options.
To use your WSGI application with any of them you will need a FastCGI
server first. The most popular one is `flup`_ which we will use for
this guide. Make sure to have it installed to follow along.

.. admonition:: Watch Out

   Please make sure in advance that any ``app.run()`` calls you might
   have in your application file are inside an ``if __name__ ==
   '__main__':`` block or moved to a separate file.  Just make sure it's
   not called because this will always start a local WSGI server which
   we do not want if we deploy that application to FastCGI.

Creating a `.fcgi` file
-----------------------

First you need to create the FastCGI server file.  Let's call it
`yourapplication.fcgi`::

    #!/usr/bin/python
    from flup.server.fcgi import WSGIServer
    from yourapplication import app

    if __name__ == '__main__':
        WSGIServer(app).run()

This is enough for Apache to work, however nginx and older versions of
lighttpd need a socket to be explicitly passed to communicate with the
FastCGI server.  For that to work you need to pass the path to the
socket to the :class:`~flup.server.fcgi.WSGIServer`::

    WSGIServer(application, bindAddress='/path/to/fcgi.sock').run()

The path has to be the exact same path you define in the server
config.

Save the :file:`yourapplication.fcgi` file somewhere you will find it again.
It makes sense to have that in :file:`/var/www/yourapplication` or something
similar.

Make sure to set the executable bit on that file so that the servers
can execute it:

.. sourcecode:: text

    $ chmod +x /var/www/yourapplication/yourapplication.fcgi

Configuring Apache
------------------

The example above is good enough for a basic Apache deployment but your
`.fcgi` file will appear in your application URL e.g.
``example.com/yourapplication.fcgi/news/``. There are few ways to configure
your application so that yourapplication.fcgi does not appear in the URL.
A preferable way is to use the ScriptAlias and SetHandler configuration
directives to route requests to the FastCGI server. The following example
uses FastCgiServer to start 5 instances of the application which will
handle all incoming requests::

    LoadModule fastcgi_module /usr/lib64/httpd/modules/mod_fastcgi.so

    FastCgiServer /var/www/html/yourapplication/app.fcgi -idle-timeout 300 -processes 5

docs/tutorial/setup.rst
2010-04-18 → 2018-02-09 · 29 commits · mourned by Adam Zapletal, Armin Ronacher, Daniel Haaker
“Refined the tutorial, a prettier website now.”
I diligently connected databases and configured Flask, a fleeting elegance before the rewrite. Perhaps a better style, but ultimately, just a note.
Cause of death: rewrite tutorial docs and example (David Lord, c3dd7b8)
Their portrait (last known source)
.. _tutorial-setup:

Step 2: Application Setup Code
==============================

Next, we will create the application module, :file:`flaskr.py`.  Just like the
:file:`schema.sql` file you created in the previous step, this file should be
placed inside of the :file:`flaskr/flaskr` folder.

For this tutorial, all the Python code we use will be put into this file
(except for one line in ``__init__.py``, and any testing or optional files you
decide to create).

The first several lines of code in the application module are the needed import
statements.  After that there will be a few lines of configuration code.

For small applications like ``flaskr``, it is possible to drop the configuration
directly into the module.  However, a cleaner solution is to create a separate
``.py`` file, load that, and import the values from there.

Here are the import statements (in :file:`flaskr.py`)::

    import os
    import sqlite3

    from flask import (Flask, request, session, g, redirect, url_for, abort,
        render_template, flash)

The next couple lines will create the actual application instance and
initialize it with the config from the same file in :file:`flaskr.py`::

    app = Flask(__name__) # create the application instance :)
    app.config.from_object(__name__) # load config from this file , flaskr.py

    # Load default config and override config from an environment variable
    app.config.update(
        DATABASE=os.path.join(app.root_path, 'flaskr.db'),
        SECRET_KEY=b'_5#y2L"F4Q8z\n\xec]/',
        USERNAME='admin',
        PASSWORD='default'
    )
    app.config.from_envvar('FLASKR_SETTINGS', silent=True)

In the above code, the :class:`~flask.Config` object works similarly to a
dictionary, so it can be updated with new values.

.. admonition:: Database Path

    Operating systems know the concept of a current working directory for
    each process.  Unfortunately, you cannot depend on this in web
    applications because you might have more than one application in the
    same process.

    For this reason the ``app.root_path`` attribute can be used to
    get the path to the application.  Together with the ``os.path`` module,
    files can then easily be found.  In this example, we place the
    database right next to it.

    For a real-world application, it's recommended to use
    :ref:`instance-folders` instead.

Usually, it is a good idea to load a separate, environment-specific
configuration file.  Flask allows you to import multiple con
docs/contents.rst.inc
2010-04-25 → 2019-06-23 · 27 commits · mourned by Armin Ronacher, David Lord, Matt Campbell
“It guided the reader, then vanished with a simple rename.”
I offered pathways, meticulously documented, but David simply wanted a fresh config. Now, I’m just a list of names.
Cause of death: update docs config (David Lord, 28b35c5)
Their portrait (last known source)
User's Guide
------------

This part of the documentation, which is mostly prose, begins with some
background information about Flask, then focuses on step-by-step
instructions for web development with Flask.

.. toctree::
   :maxdepth: 2

   foreword
   advanced_foreword
   installation
   quickstart
   tutorial/index
   templating
   testing
   errorhandling
   logging
   config
   signals
   views
   appcontext
   reqcontext
   blueprints
   extensions
   cli
   server
   shell
   patterns/index
   deploying/index
   becomingbig

API Reference
-------------

If you are looking for information on a specific function, class or
method, this part of the documentation is for you.

.. toctree::
   :maxdepth: 2

   api

Additional Notes
----------------

Design notes, legal information and changelog are here for the interested.

.. toctree::
   :maxdepth: 2

   design
   htmlfaq
   security
   unicode
   extensiondev
   styleguide
   upgrading
   changelog
   license
   contributing