├── .coveragerc
├── .flake8
├── .github
├── dependabot.yml
└── workflows
│ └── ci-tests.yml
├── .gitignore
├── .readthedocs.yaml
├── CHANGES.txt
├── HISTORY.txt
├── MANIFEST.in
├── README.rst
├── RELEASING.rst
├── contributing.md
├── docs
├── Makefile
├── _static
│ └── .empty
├── api
│ ├── client.txt
│ ├── cookies.txt
│ ├── dec.txt
│ ├── exceptions.txt
│ ├── multidict.txt
│ ├── request.txt
│ ├── response.txt
│ ├── static.txt
│ └── webob.txt
├── changes.txt
├── comment-example-code
│ └── example.py
├── comment-example.txt
├── conf.py
├── differences.txt
├── do-it-yourself.txt
├── doctests.py
├── experimental
│ └── samesite.txt
├── file-example-code
│ └── test-file.txt
├── file-example.txt
├── index.txt
├── jsonrpc-example-code
│ ├── jsonrpc.py
│ ├── test_jsonrpc.py
│ └── test_jsonrpc.txt
├── jsonrpc-example.txt
├── license.txt
├── reference.txt
├── whatsnew-1.5.txt
├── whatsnew-1.6.txt
├── whatsnew-1.7.txt
├── whatsnew-1.8.txt
├── wiki-example-code
│ └── example.py
└── wiki-example.txt
├── pyproject.toml
├── setup.cfg
├── setup.py
├── src
└── webob
│ ├── __init__.py
│ ├── acceptparse.py
│ ├── byterange.py
│ ├── cachecontrol.py
│ ├── client.py
│ ├── compat.py
│ ├── cookies.py
│ ├── datetime_utils.py
│ ├── dec.py
│ ├── descriptors.py
│ ├── etag.py
│ ├── exc.py
│ ├── headers.py
│ ├── multidict.py
│ ├── request.py
│ ├── response.py
│ ├── static.py
│ └── util.py
├── tests
├── conftest.py
├── performance_test.py
├── test_acceptparse.py
├── test_byterange.py
├── test_cachecontrol.py
├── test_client.py
├── test_client_functional.py
├── test_compat.py
├── test_cookies.py
├── test_cookies_bw.py
├── test_datetime_utils.py
├── test_dec.py
├── test_descriptors.py
├── test_etag.py
├── test_etag_nose.py
├── test_exc.py
├── test_headers.py
├── test_in_wsgiref.py
├── test_misc.py
├── test_multidict.py
├── test_request.py
├── test_response.py
├── test_static.py
├── test_transcode.py
└── test_util.py
└── tox.ini
/.coveragerc:
--------------------------------------------------------------------------------
1 | [run]
2 | parallel = true
3 | source =
4 | webob
5 |
6 | [paths]
7 | source =
8 | src/webob
9 | */site-packages/webob
10 |
11 | [report]
12 | show_missing = true
13 | precision = 2
14 |
15 | [html]
16 | show_contexts = True
17 |
--------------------------------------------------------------------------------
/.flake8:
--------------------------------------------------------------------------------
1 | # Recommended flake8 settings while editing WebOb, we use Black for the final linting/say in how code is formatted
2 | #
3 | # pip install flake8 flake8-bugbear
4 | #
5 | # This will warn/error on things that black does not fix, on purpose.
6 | #
7 | # Run:
8 | #
9 | # tox -e run-flake8
10 | #
11 | # To have it automatically create and install the appropriate tools, and run
12 | # flake8 across the source code/tests
13 |
14 | [flake8]
15 | # max line length is set to 88 in black, here it is set to 80 and we enable bugbear's B950 warning, which is:
16 | #
17 | # B950: Line too long. This is a pragmatic equivalent of pycodestyle’s E501: it
18 | # considers “max-line-length” but only triggers when the value has been
19 | # exceeded by more than 10%. You will no longer be forced to reformat code due
20 | # to the closing parenthesis being one character too far to satisfy the linter.
21 | # At the same time, if you do significantly violate the line length, you will
22 | # receive a message that states what the actual limit is. This is inspired by
23 | # Raymond Hettinger’s “Beyond PEP 8” talk and highway patrol not stopping you
24 | # if you drive < 5mph too fast. Disable E501 to avoid duplicate warnings.
25 | max-line-length = 80
26 | max-complexity = 12
27 | select = E,F,W,C,B,B9
28 | ignore =
29 | # E123 closing bracket does not match indentation of opening bracket’s line
30 | E123
31 | # E203 whitespace before ‘:’ (Not PEP8 compliant, Python Black)
32 | E203
33 | # E501 line too long (82 > 79 characters) (replaced by B950 from flake8-bugbear, https://github.com/PyCQA/flake8-bugbear)
34 | E501
35 | # W503 line break before binary operator (Not PEP8 compliant, Python Black)
36 | W503
37 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # Set update schedule for GitHub Actions
2 |
3 | version: 2
4 | updates:
5 |
6 | - package-ecosystem: "github-actions"
7 | directory: "/"
8 | schedule:
9 | # Check for updates to GitHub Actions every weekday
10 | interval: "daily"
11 |
--------------------------------------------------------------------------------
/.github/workflows/ci-tests.yml:
--------------------------------------------------------------------------------
1 | name: Build and test
2 |
3 | on:
4 | # Only on pushes to main or one of the release branches we build on push
5 | push:
6 | branches:
7 | - main
8 | - "[0-9].[0-9]+-branch"
9 | tags:
10 | - "*"
11 | # Build pull requests
12 | pull_request:
13 |
14 | jobs:
15 | test:
16 | strategy:
17 | matrix:
18 | py:
19 | - "3.9"
20 | - "3.10"
21 | - "3.11"
22 | - "3.12"
23 | - "3.13"
24 | - "pypy-3.9"
25 | - "pypy-3.10"
26 | # Pre-release
27 | os:
28 | - "ubuntu-22.04"
29 | - "windows-latest"
30 | - "macos-14" # arm64
31 | - "macos-13" # x64
32 | architecture:
33 | - x64
34 | - x86
35 | - arm64
36 | include:
37 | - py: "pypy-3.9"
38 | toxenv: "pypy39"
39 | - py: "pypy-3.10"
40 | toxenv: "pypy310"
41 | exclude:
42 | # Ubuntu does not have x86/arm64 Python
43 | - os: "ubuntu-22.04"
44 | architecture: x86
45 | - os: "ubuntu-22.04"
46 | architecture: arm64
47 | # MacOS we need to make sure to remove x86 on all
48 | # We need to run no arm64 on macos-13 (Intel), but some
49 | # Python versions: 3.9/3.10
50 | #
51 | # From 3.11 onward, there is support for running x64 and
52 | # arm64 on Apple Silicon based systems (macos-14)
53 | - os: "macos-13"
54 | architecture: x86
55 | - os: "macos-13"
56 | architecture: arm64
57 | - os: "macos-14"
58 | architecture: x86
59 | - os: "macos-14"
60 | architecture: x64
61 | py: "3.9"
62 | - os: "macos-14"
63 | architecture: x64
64 | py: "3.10"
65 | # Windows does not have arm64 releases
66 | - os: "windows-latest"
67 | architecture: arm64
68 | # Don't run all PyPy versions except latest on
69 | # Windows/macOS. They are expensive to run.
70 | - os: "windows-latest"
71 | py: "pypy-3.9"
72 | - os: "macos-13"
73 | py: "pypy-3.9"
74 | - os: "macos-14"
75 | py: "pypy-3.9"
76 |
77 | name: "Python: ${{ matrix.py }}-${{ matrix.architecture }} on ${{ matrix.os }}"
78 | runs-on: ${{ matrix.os }}
79 | steps:
80 | - uses: actions/checkout@v4
81 | - name: Setup python
82 | uses: actions/setup-python@v5
83 | with:
84 | python-version: ${{ matrix.py }}
85 | architecture: ${{ matrix.architecture }}
86 | - run: pip install tox
87 | - name: Running tox with specific toxenv
88 | if: ${{ matrix.toxenv != '' }}
89 | env:
90 | TOXENV: ${{ matrix.toxenv }}
91 | run: tox
92 | - name: Running tox for current python version
93 | if: ${{ matrix.toxenv == '' }}
94 | run: tox -e py
95 |
96 | coverage:
97 | runs-on: ubuntu-22.04
98 | name: Validate coverage
99 | steps:
100 | - uses: actions/checkout@v4
101 | - name: Setup python
102 | uses: actions/setup-python@v5
103 | with:
104 | python-version: "3.13"
105 | architecture: x64
106 |
107 | - run: pip install tox
108 | - run: tox -e py313,coverage
109 | docs:
110 | runs-on: ubuntu-22.04
111 | name: Build the documentation
112 | steps:
113 | - uses: actions/checkout@v4
114 | - name: Setup python
115 | uses: actions/setup-python@v5
116 | with:
117 | python-version: "3.13"
118 | architecture: x64
119 | - run: pip install tox
120 | - run: tox -e docs
121 | lint:
122 | runs-on: ubuntu-22.04
123 | name: Lint the package
124 | steps:
125 | - uses: actions/checkout@v4
126 | - name: Setup python
127 | uses: actions/setup-python@v5
128 | with:
129 | python-version: "3.13"
130 | architecture: x64
131 | - run: pip install tox
132 | - run: tox -e lint
133 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *$py.class
2 | *.egg
3 | *.pyc
4 | *.pyo
5 | *.swp
6 | *~
7 | .*.swp
8 | .tox/
9 | __pycache__/
10 | _build/
11 | build/
12 | dist/
13 | env*/
14 | .coverage
15 | .coverage.*
16 | .cache/
17 | WebOb.egg-info/
18 | pytest*.xml
19 | coverage*.xml
20 | .pytest_cache/
21 |
--------------------------------------------------------------------------------
/.readthedocs.yaml:
--------------------------------------------------------------------------------
1 | # https://docs.readthedocs.io/en/stable/config-file/v2.html
2 | version: 2
3 | build:
4 | os: ubuntu-22.04
5 | tools:
6 | python: '3.12'
7 | sphinx:
8 | configuration: docs/conf.py
9 | python:
10 | install:
11 | - method: pip
12 | path: .
13 | extra_requirements:
14 | - docs
15 |
--------------------------------------------------------------------------------
/CHANGES.txt:
--------------------------------------------------------------------------------
1 | Unreleased
2 | ----------
3 |
4 | Security Fix
5 | ~~~~~~~~~~~~
6 |
7 | - The use of WebOb's Response object to redirect a request to a new location
8 | can lead to an open redirect if the Location header is not a full URI.
9 |
10 | See https://github.com/Pylons/webob/security/advisories/GHSA-mg3v-6m49-jhp3
11 | and CVE-2024-42353
12 |
13 | Thanks to Sara Gao for the report
14 |
15 | (This fix was released in WebOb 1.8.8)
16 |
17 | Feature
18 | ~~~~~~~
19 |
20 | - Rename "master" git branch to "main"
21 |
22 | - Add support for Python 3.12.
23 |
24 | - Add Request.remote_host, exposing REMOTE_HOST environment variable.
25 |
26 | - Added ``acceptparse.Accept.parse_offer`` to codify what types of offers
27 | are compatible with ``acceptparse.AcceptValidHeader.acceptable_offers``,
28 | ``acceptparse.AcceptMissingHeader.acceptable_offers``, and
29 | ``acceptparse.AcceptInvalidHeader.acceptable_offers``. This API also
30 | normalizes the offer with lowercased type/subtype and parameter names.
31 | See https://github.com/Pylons/webob/pull/376 and
32 | https://github.com/Pylons/webob/pull/379
33 |
34 | Compatibility
35 | ~~~~~~~~~~~~~
36 |
37 |
38 | Backwards Incompatibilities
39 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~
40 |
41 | - Drop support for Python 2.7, 3.4, 3.5, 3.6, and 3.7.
42 |
43 | Experimental Features
44 | ~~~~~~~~~~~~~~~~~~~~~
45 |
46 | - The SameSite value now includes a new option named "None", this is a new
47 | change that was introduced in
48 | https://tools.ietf.org/html/draft-west-cookie-incrementalism-00
49 |
50 | Please be aware that older clients are incompatible with this change:
51 | https://www.chromium.org/updates/same-site/incompatible-clients, WebOb does
52 | not enable SameSite on cookies by default, so there is no backwards
53 | incompatible change here.
54 |
55 | See https://github.com/Pylons/webob/issues/406
56 |
57 | - Validation of SameSite values can be disabled by toggling a module flag. This
58 | is in anticipation of future changes in evolving cookie standards.
59 | The discussion in https://github.com/Pylons/webob/pull/407 (which initially
60 | expanded the allowed options) notes the sudden change to browser cookie
61 | implementation details may happen again.
62 |
63 | In May 2019, Google announced a new model for privacy controls in their
64 | browsers, which affected the list of valid options for the SameSite attribute
65 | of cookies. In late 2019, the company began to roll out these changes to their
66 | browsers to force developer adoption of the new specification.
67 | See https://www.chromium.org/updates/same-site and
68 | https://blog.chromium.org/2019/10/developers-get-ready-for-new.html for more
69 | details on this change.
70 |
71 | See https://github.com/Pylons/webob/pull/409
72 |
73 |
74 | Bugfix
75 | ~~~~~~
76 |
77 | - Response.content_type now accepts unicode strings on Python 2 and encodes
78 | them to latin-1. See https://github.com/Pylons/webob/pull/389 and
79 | https://github.com/Pylons/webob/issues/388
80 |
81 | - Accept header classes now support a .copy() function that may be used to
82 | create a copy. This allows ``create_accept_header`` and other like functions
83 | to accept an pre-existing Accept header. See
84 | https://github.com/Pylons/webob/pull/386 and
85 | https://github.com/Pylons/webob/issues/385
86 |
87 | - SameSite may now be passed as str or bytes to `Response.set_cookie` and
88 | `cookies.make_cookie`. This was an oversight as all other arguments would be
89 | correctly coerced before being serialized. See
90 | https://github.com/Pylons/webob/issues/361 and
91 | https://github.com/Pylons/webob/pull/362
92 |
93 | - acceptparse.MIMEAccept which is deprecated in WebOb 1.8.0 made a backwards
94 | incompatible change that led to it raising on an invalid Accept header. This
95 | behaviour has now been reversed, as well as some other fixes to allow
96 | MIMEAccept to behave more like the old version. See
97 | https://github.com/Pylons/webob/pull/356
98 |
99 | - ``acceptparse.AcceptValidHeader``, ``acceptparse.AcceptInvalidHeader``, and
100 | ``acceptparse.AcceptNoHeader`` will now always ignore offers that do not
101 | match the required media type grammar when calling ``.acceptable_offers()``.
102 | Previous versions raised a ``ValueError`` for invalid offers in
103 | ``AcceptValidHeader`` and returned them as acceptable in the others.
104 | See https://github.com/Pylons/webob/pull/372
105 |
106 | - ``Response.body_file.write`` and ``Response.write`` now returns the written
107 | length. See https://github.com/Pylons/webob/pull/422
108 |
109 | Warnings
110 | ~~~~~~~~
111 |
112 | - Some backslashes introduced with the new accept handling code were causing
113 | DeprecationWarnings upon compiling the source to pyc files, all of the
114 | backslashes have been reigned in as appropriate, and users should no longer
115 | see DeprecationWarnings for invalid escape sequence. See
116 | https://github.com/Pylons/webob/issues/384
117 |
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | graft src
2 | graft docs
3 | prune docs/_build
4 | graft tests
5 |
6 | include README.rst
7 | include CHANGES.txt HISTORY.txt
8 | include contributing.md RELEASING.rst
9 | include pyproject.toml
10 | include .coveragerc .flake8 tox.ini
11 | include .readthedocs.yaml
12 |
13 | global-exclude __pycache__ *.py[cod]
14 | global-exclude .DS_Store
15 |
--------------------------------------------------------------------------------
/README.rst:
--------------------------------------------------------------------------------
1 | WebOb
2 | =====
3 |
4 | .. image:: https://github.com/Pylons/webob/workflows/Build%20and%20test/badge.svg?branch=main
5 | :target: https://github.com/Pylons/webob/actions?query=workflow%3A%22Build+and+test%22
6 | :alt: main CI Status
7 |
8 | .. image:: https://readthedocs.org/projects/webob/badge/?version=stable
9 | :target: https://docs.pylonsproject.org/projects/webob/en/stable/
10 | :alt: Documentation Status
11 |
12 | WebOb provides objects for HTTP requests and responses. Specifically
13 | it does this by wrapping the `WSGI `_ request
14 | environment and response status/headers/app_iter(body).
15 |
16 | The request and response objects provide many conveniences for parsing
17 | HTTP request and forming HTTP responses. Both objects are read/write:
18 | as a result, WebOb is also a nice way to create HTTP requests and
19 | parse HTTP responses.
20 |
21 | Support and Documentation
22 | -------------------------
23 |
24 | See the `WebOb Documentation website `_ to view
25 | documentation, report bugs, and obtain support.
26 |
27 | License
28 | -------
29 |
30 | WebOb is offered under the `MIT-license
31 | `_.
32 |
33 | Authors
34 | -------
35 |
36 | WebOb was authored by Ian Bicking and is currently maintained by the `Pylons
37 | Project `_ and a team of contributors.
38 |
--------------------------------------------------------------------------------
/RELEASING.rst:
--------------------------------------------------------------------------------
1 | Releasing WebOb
2 | ===============
3 |
4 | - For clarity, we define releases as follows.
5 |
6 | - Alpha, beta, dev and similar statuses do not qualify whether a release is
7 | major or minor. The term "pre-release" means alpha, beta, or dev.
8 |
9 | - A release is final when it is no longer pre-release.
10 |
11 | - A *major* release is where the first number either before or after the
12 | first dot increases. Examples: 1.6.0 to 1.7.0a1, or 1.8.0 to 2.0.0.
13 |
14 | - A *minor* or *bug fix* release is where the number after the second dot
15 | increases. Example: 1.6.0 to 1.6.1.
16 |
17 |
18 | Releasing
19 | ---------
20 |
21 | - First install the required pre-requisites::
22 |
23 | $ pip install setuptools_git twine
24 |
25 | - Edit ``CHANGES.txt`` to add a release number and data and then modify
26 | ``setup.py`` to update the version number as well.
27 |
28 | - Run ``python setup.py sdist bdist_wheel``, then verify ``dist/*`` hasn't
29 | increased dramatically compared to previous versions (for example,
30 | accidentally including a large file in the release or pyc files).
31 |
32 | - Upload the resulting package to PyPi: ``twine upload
33 | dist/WebOb-*{whl,tar.gz}``
34 |
35 | Marketing and communications
36 | ----------------------------
37 |
38 | - Announce to Twitter::
39 |
40 | WebOb 1.x released.
41 |
42 | PyPI
43 | https://pypi.python.org/pypi/webob/1.x.y
44 |
45 | Changes
46 | http://docs.webob.org/en/1.x-branch/
47 |
48 | Issues
49 | https://github.com/Pylons/webob/issues
50 |
51 | - Announce to maillist::
52 |
53 | WebOb 1.x.y has been released.
54 |
55 | Here are the changes:
56 |
57 | <>
58 |
59 | You can install it via PyPI:
60 |
61 | pip install webob==1.x.y
62 |
63 | Enjoy, and please report any issues you find to the issue tracker at
64 | https://github.com/Pylons/webob/issues
65 |
66 | Thanks!
67 |
68 | - WebOb developers
69 |
--------------------------------------------------------------------------------
/contributing.md:
--------------------------------------------------------------------------------
1 | Contributing
2 | ============
3 |
4 | All projects under the Pylons Projects, including this one, follow the
5 | guidelines established at [How to
6 | Contribute](http://www.pylonsproject.org/community/how-to-contribute) and
7 | [Coding Style and
8 | Standards](http://docs.pylonsproject.org/en/latest/community/codestyle.html).
9 |
10 | You can contribute to this project in several ways.
11 |
12 | * [File an Issue on GitHub](https://github.com/Pylons/webob/issues)
13 | * Fork this project and create a branch with your suggested change. When ready,
14 | submit a pull request for consideration. [GitHub
15 | Flow](https://guides.github.com/introduction/flow/index.html) describes the
16 | workflow process and why it's a good practice.
17 | * Join the IRC channel #pyramid on irc.freenode.net.
18 |
19 |
20 | Git Branches
21 | ------------
22 | Git branches and their purpose and status at the time of this writing are
23 | listed below.
24 |
25 | * [main](https://github.com/Pylons/webob/) - The branch on which further
26 | development takes place. The default branch on GitHub.
27 | * [1.6-branch](https://github.com/Pylons/webob/tree/1.6-branch) - The branch
28 | classified as "stable" or "latest". Actively maintained.
29 | * [1.5-branch](https://github.com/Pylons/webob/tree/1.5-branch) - The oldest
30 | actively maintained and stable branch.
31 |
32 | Older branches are not actively maintained. In general, two stable branches and
33 | one or two development branches are actively maintained.
34 |
35 |
36 | Running Tests
37 | -------------
38 |
39 | Run `tox` from within your checkout. This will run the tests across all
40 | supported systems and attempt to build the docs.
41 |
42 | For example, to run the test suite with your current Python runtime:
43 |
44 | ```shell
45 | tox -e py
46 | ```
47 |
48 | If you wish to run multiple targets, you can do so by separating them with a
49 | comma:
50 |
51 | ```shell
52 | tox -e py312,coverage
53 | ```
54 |
55 | If you've already run the coverage target and want to see the results in HTML,
56 | you can override `tox.ini` settings with the `commands` option:
57 |
58 | ```shell
59 | tox -e coverage -x testenv:coverage.commands="coverage html"
60 | ```
61 |
62 | To build the docs:
63 |
64 | ```shell
65 | tox -e docs
66 | ```
67 |
68 | List all possible targets:
69 |
70 | ```shell
71 | tox list # or `tox l`
72 | ```
73 |
74 | See `tox.ini` file for details, or for general `tox` usage.
75 |
76 |
77 | Building documentation for a Pylons Project project
78 | ---------------------------------------------------
79 |
80 | *Note:* These instructions might not work for Windows users. Suggestions to
81 | improve the process for Windows users are welcome by submitting an issue or a
82 | pull request.
83 |
84 | 1. Fork the repo on GitHub by clicking the [Fork] button.
85 | 2. Clone your fork into a workspace on your local machine.
86 |
87 | git clone git@github.com:/webob.git
88 |
89 | 3. Add a git remote "upstream" for the cloned fork.
90 |
91 | git remote add upstream git@github.com:Pylons/webob.git
92 |
93 | 4. Set an environment variable to your virtual environment.
94 |
95 | # Mac and Linux
96 | $ export VENV=~/hack-on-webob/env
97 |
98 | # Windows
99 | set VENV=c:\hack-on-webob\env
100 |
101 | 5. Try to build the docs in your workspace.
102 |
103 | # Mac and Linux
104 | $ make clean html SPHINXBUILD=$VENV/bin/sphinx-build
105 |
106 | # Windows
107 | c:\> make clean html SPHINXBUILD=%VENV%\bin\sphinx-build
108 |
109 | If successful, then you can make changes to the documentation. You can
110 | load the built documentation in the `/_build/html/` directory in a web
111 | browser.
112 |
113 | 6. From this point forward, follow the typical [git
114 | workflow](https://help.github.com/articles/what-is-a-good-git-workflow/).
115 | Start by pulling from the upstream to get the most current changes.
116 |
117 | git pull upstream main
118 |
119 | 7. Make a branch, make changes to the docs, and rebuild them as indicated in
120 | step 5. To speed up the build process, you can omit `clean` from the above
121 | command to rebuild only those pages that depend on the files you have
122 | changed.
123 |
124 | 8. Once you are satisfied with your changes and the documentation builds
125 | successfully without errors or warnings, then git commit and push them to
126 | your "origin" repository on GitHub.
127 |
128 | git commit -m "commit message"
129 | git push -u origin --all # first time only, subsequent can be just 'git push'.
130 |
131 | 9. Create a [pull request](https://help.github.com/articles/using-pull-requests/).
132 |
133 | 10. Repeat the process starting from Step 6.
--------------------------------------------------------------------------------
/docs/Makefile:
--------------------------------------------------------------------------------
1 | # Makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line.
5 | SPHINXOPTS =
6 | SPHINXBUILD = sphinx-build
7 | PAPER =
8 | BUILDDIR = _build
9 |
10 | # User-friendly check for sphinx-build
11 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
12 | $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
13 | endif
14 |
15 | # Internal variables.
16 | PAPEROPT_a4 = -D latex_paper_size=a4
17 | PAPEROPT_letter = -D latex_paper_size=letter
18 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
19 | # the i18n builder cannot share the environment and doctrees with the others
20 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
21 |
22 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext
23 |
24 | help:
25 | @echo "Please use \`make ' where is one of"
26 | @echo " html to make standalone HTML files"
27 | @echo " dirhtml to make HTML files named index.html in directories"
28 | @echo " singlehtml to make a single large HTML file"
29 | @echo " pickle to make pickle files"
30 | @echo " json to make JSON files"
31 | @echo " htmlhelp to make HTML files and a HTML help project"
32 | @echo " qthelp to make HTML files and a qthelp project"
33 | @echo " applehelp to make an Apple Help Book"
34 | @echo " devhelp to make HTML files and a Devhelp project"
35 | @echo " epub to make an epub"
36 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
37 | @echo " latexpdf to make LaTeX files and run them through pdflatex"
38 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
39 | @echo " text to make text files"
40 | @echo " man to make manual pages"
41 | @echo " texinfo to make Texinfo files"
42 | @echo " info to make Texinfo files and run them through makeinfo"
43 | @echo " gettext to make PO message catalogs"
44 | @echo " changes to make an overview of all changed/added/deprecated items"
45 | @echo " xml to make Docutils-native XML files"
46 | @echo " pseudoxml to make pseudoxml-XML files for display purposes"
47 | @echo " linkcheck to check all external links for integrity"
48 | @echo " doctest to run all doctests embedded in the documentation (if enabled)"
49 | @echo " coverage to run coverage check of the documentation (if enabled)"
50 |
51 | clean:
52 | rm -rf $(BUILDDIR)/*
53 |
54 | html:
55 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
56 | @echo
57 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
58 |
59 | dirhtml:
60 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
61 | @echo
62 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
63 |
64 | singlehtml:
65 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
66 | @echo
67 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
68 |
69 | pickle:
70 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
71 | @echo
72 | @echo "Build finished; now you can process the pickle files."
73 |
74 | json:
75 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
76 | @echo
77 | @echo "Build finished; now you can process the JSON files."
78 |
79 | htmlhelp:
80 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
81 | @echo
82 | @echo "Build finished; now you can run HTML Help Workshop with the" \
83 | ".hhp project file in $(BUILDDIR)/htmlhelp."
84 |
85 | qthelp:
86 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
87 | @echo
88 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \
89 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
90 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/WebOb.qhcp"
91 | @echo "To view the help file:"
92 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/WebOb.qhc"
93 |
94 | applehelp:
95 | $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp
96 | @echo
97 | @echo "Build finished. The help book is in $(BUILDDIR)/applehelp."
98 | @echo "N.B. You won't be able to view it unless you put it in" \
99 | "~/Library/Documentation/Help or install it in your application" \
100 | "bundle."
101 |
102 | devhelp:
103 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
104 | @echo
105 | @echo "Build finished."
106 | @echo "To view the help file:"
107 | @echo "# mkdir -p $$HOME/.local/share/devhelp/WebOb"
108 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/WebOb"
109 | @echo "# devhelp"
110 |
111 | epub:
112 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
113 | @echo
114 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
115 |
116 | latex:
117 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
118 | @echo
119 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
120 | @echo "Run \`make' in that directory to run these through (pdf)latex" \
121 | "(use \`make latexpdf' here to do that automatically)."
122 |
123 | latexpdf:
124 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
125 | @echo "Running LaTeX files through pdflatex..."
126 | $(MAKE) -C $(BUILDDIR)/latex all-pdf
127 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
128 |
129 | latexpdfja:
130 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
131 | @echo "Running LaTeX files through platex and dvipdfmx..."
132 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
133 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
134 |
135 | text:
136 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
137 | @echo
138 | @echo "Build finished. The text files are in $(BUILDDIR)/text."
139 |
140 | man:
141 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
142 | @echo
143 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
144 |
145 | texinfo:
146 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
147 | @echo
148 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
149 | @echo "Run \`make' in that directory to run these through makeinfo" \
150 | "(use \`make info' here to do that automatically)."
151 |
152 | info:
153 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
154 | @echo "Running Texinfo files through makeinfo..."
155 | make -C $(BUILDDIR)/texinfo info
156 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
157 |
158 | gettext:
159 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
160 | @echo
161 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
162 |
163 | changes:
164 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
165 | @echo
166 | @echo "The overview file is in $(BUILDDIR)/changes."
167 |
168 | linkcheck:
169 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
170 | @echo
171 | @echo "Link check complete; look for any errors in the above output " \
172 | "or in $(BUILDDIR)/linkcheck/output.txt."
173 |
174 | doctest:
175 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
176 | @echo "Testing of doctests in the sources finished, look at the " \
177 | "results in $(BUILDDIR)/doctest/output.txt."
178 |
179 | coverage:
180 | $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage
181 | @echo "Testing of coverage in the sources finished, look at the " \
182 | "results in $(BUILDDIR)/coverage/python.txt."
183 |
184 | xml:
185 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
186 | @echo
187 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml."
188 |
189 | pseudoxml:
190 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
191 | @echo
192 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
193 |
--------------------------------------------------------------------------------
/docs/_static/.empty:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Pylons/webob/39d5af3c797e7b867f152c2e8c979de42d029403/docs/_static/.empty
--------------------------------------------------------------------------------
/docs/api/client.txt:
--------------------------------------------------------------------------------
1 | :mod:`webob.client` -- Send WSGI requests over HTTP
2 | ===================================================
3 |
4 | .. automodule:: webob.client
5 |
6 | Client
7 | ------
8 |
9 | .. autoclass:: SendRequest
10 | :members:
11 |
12 | .. autoclass:: send_request_app
13 |
--------------------------------------------------------------------------------
/docs/api/cookies.txt:
--------------------------------------------------------------------------------
1 | :mod:`webob.cookies` -- Cookies
2 | ===============================
3 |
4 | Cookies
5 | -------
6 |
7 | .. autoclass:: webob.cookies.CookieProfile
8 | :members:
9 | .. autoclass:: webob.cookies.SignedCookieProfile
10 | :members:
11 | .. autoclass:: webob.cookies.SignedSerializer
12 | :members:
13 | .. autoclass:: webob.cookies.JSONSerializer
14 | :members:
15 | .. autofunction:: webob.cookies.make_cookie
16 |
17 |
--------------------------------------------------------------------------------
/docs/api/dec.txt:
--------------------------------------------------------------------------------
1 | :mod:`webob.dec` -- WSGIfy decorator
2 | ====================================
3 |
4 | .. automodule:: webob.dec
5 |
6 | Decorator
7 | ---------
8 |
9 | .. autoclass:: wsgify
10 | :members:
11 |
--------------------------------------------------------------------------------
/docs/api/exceptions.txt:
--------------------------------------------------------------------------------
1 | :mod:`webob.exc` -- WebOb Exceptions
2 | ====================================
3 |
4 | .. automodule:: webob.exc
5 |
6 | HTTP Exceptions
7 | ---------------
8 |
9 | .. autoexception:: HTTPException
10 | .. autoexception:: WSGIHTTPException
11 | .. autoexception:: HTTPError
12 | .. autoexception:: HTTPRedirection
13 | .. autoexception:: HTTPOk
14 | .. autoexception:: HTTPCreated
15 | .. autoexception:: HTTPAccepted
16 | .. autoexception:: HTTPNonAuthoritativeInformation
17 | .. autoexception:: HTTPNoContent
18 | .. autoexception:: HTTPResetContent
19 | .. autoexception:: HTTPPartialContent
20 | .. autoexception:: _HTTPMove
21 | .. autoexception:: HTTPMultipleChoices
22 | .. autoexception:: HTTPMovedPermanently
23 | .. autoexception:: HTTPFound
24 | .. autoexception:: HTTPSeeOther
25 | .. autoexception:: HTTPNotModified
26 | .. autoexception:: HTTPUseProxy
27 | .. autoexception:: HTTPTemporaryRedirect
28 | .. autoexception:: HTTPClientError
29 | .. autoexception:: HTTPBadRequest
30 | .. autoexception:: HTTPUnauthorized
31 | .. autoexception:: HTTPPaymentRequired
32 | .. autoexception:: HTTPForbidden
33 | .. autoexception:: HTTPNotFound
34 | .. autoexception:: HTTPMethodNotAllowed
35 | .. autoexception:: HTTPNotAcceptable
36 | .. autoexception:: HTTPProxyAuthenticationRequired
37 | .. autoexception:: HTTPRequestTimeout
38 | .. autoexception:: HTTPConflict
39 | .. autoexception:: HTTPGone
40 | .. autoexception:: HTTPLengthRequired
41 | .. autoexception:: HTTPPreconditionFailed
42 | .. autoexception:: HTTPRequestEntityTooLarge
43 | .. autoexception:: HTTPRequestURITooLong
44 | .. autoexception:: HTTPUnsupportedMediaType
45 | .. autoexception:: HTTPRequestRangeNotSatisfiable
46 | .. autoexception:: HTTPExpectationFailed
47 | .. autoexception:: HTTPUnprocessableEntity
48 | .. autoexception:: HTTPLocked
49 | .. autoexception:: HTTPFailedDependency
50 | .. autoexception:: HTTPPreconditionRequired
51 | .. autoexception:: HTTPTooManyRequests
52 | .. autoexception:: HTTPRequestHeaderFieldsTooLarge
53 | .. autoexception:: HTTPUnavailableForLegalReasons
54 | .. autoexception:: HTTPServerError
55 | .. autoexception:: HTTPInternalServerError
56 | .. autoexception:: HTTPNotImplemented
57 | .. autoexception:: HTTPBadGateway
58 | .. autoexception:: HTTPServiceUnavailable
59 | .. autoexception:: HTTPGatewayTimeout
60 | .. autoexception:: HTTPVersionNotSupported
61 | .. autoexception:: HTTPInsufficientStorage
62 | .. autoexception:: HTTPNetworkAuthenticationRequired
63 | .. autoexception:: HTTPExceptionMiddleware
64 |
65 |
--------------------------------------------------------------------------------
/docs/api/multidict.txt:
--------------------------------------------------------------------------------
1 | :mod:`webob.multidict` -- multi-value dictionary object
2 | =======================================================
3 |
4 | multidict
5 | ---------
6 |
7 | Several parts of WebOb use a "multidict", which is a dictionary where a key can
8 | have multiple values. The quintessential example is a query string like
9 | ``?pref=red&pref=blue``. The ``pref`` variable has two values, ``red`` and
10 | ``blue``.
11 |
12 | In a multidict, when you do ``request.GET['pref']``, you'll get back only
13 | ``'blue'`` (the last value of ``pref``). Sometimes returning a string and
14 | other times returning a list is a cause of frequent exceptions. If you want
15 | *all* the values back, use ``request.GET.getall('pref')``. If you want to be
16 | sure there is *one and only one* value, use ``request.GET.getone('pref')``,
17 | which will raise an exception if there is zero or more than one value for
18 | ``pref``.
19 |
20 | When you use operations like ``request.GET.items()``, you'll get back something
21 | like ``[('pref', 'red'), ('pref', 'blue')]``. All the key/value pairs will
22 | show up. Similarly ``request.GET.keys()`` returns ``['pref', 'pref']``.
23 | Multidict is a view on a list of tuples; all the keys are ordered, and all the
24 | values are ordered.
25 |
26 | .. automodule:: webob.multidict
27 | .. autoclass:: MultiDict
28 | :members:
29 | :inherited-members:
30 | .. autoclass:: NestedMultiDict
31 | :members:
32 | .. autoclass:: NoVars
33 | :members:
34 |
35 |
--------------------------------------------------------------------------------
/docs/api/request.txt:
--------------------------------------------------------------------------------
1 | :mod:`webob.request` -- Request
2 | ===============================
3 |
4 | Request
5 | -------
6 |
7 | .. automodule:: webob.request
8 | .. autoclass:: webob.request.Request
9 | .. autoclass:: webob.request.BaseRequest
10 | :members:
11 |
12 |
13 |
--------------------------------------------------------------------------------
/docs/api/response.txt:
--------------------------------------------------------------------------------
1 | :mod:`webob.response` -- Response
2 | =================================
3 |
4 | Response
5 | --------
6 |
7 | .. automodule:: webob.response
8 | .. autoclass:: webob.response.Response
9 | :members:
10 | .. autoclass:: webob.response.ResponseBodyFile
11 | :members:
12 | .. autoclass:: webob.response.AppIterRange
13 | :members:
14 |
--------------------------------------------------------------------------------
/docs/api/static.txt:
--------------------------------------------------------------------------------
1 | :mod:`webob.static` -- Serving static files
2 | ===========================================
3 |
4 | .. automodule:: webob.static
5 |
6 | .. autoclass:: webob.static.FileApp
7 | :members:
8 |
9 | .. autoclass:: webob.static.DirectoryApp
10 | :members:
11 |
12 |
13 |
--------------------------------------------------------------------------------
/docs/api/webob.txt:
--------------------------------------------------------------------------------
1 | :mod:`webob` -- Request/Response objects
2 | ========================================
3 |
4 | Headers
5 | -------
6 |
7 | .. _acceptheader:
8 |
9 | Accept*
10 | ~~~~~~~
11 |
12 | .. automodule:: webob.acceptparse
13 |
14 |
15 | Convenience functions to automatically create the appropriate header objects of
16 | a certain type:
17 |
18 | .. autofunction:: create_accept_header
19 | .. autofunction:: create_accept_charset_header
20 | .. autofunction:: create_accept_encoding_header
21 | .. autofunction:: create_accept_language_header
22 |
23 | The classes that may be returned by one of the functions above, and their
24 | methods:
25 |
26 | .. autoclass:: Accept
27 | :members: parse
28 |
29 | .. autoclass:: AcceptOffer
30 | :members: __str__
31 |
32 | .. autoclass:: AcceptValidHeader
33 | :members: parse, header_value, parsed, __init__, __add__, __bool__,
34 | __contains__, __iter__, __radd__, __repr__, __str__,
35 | accept_html, accepts_html, acceptable_offers, best_match, quality
36 |
37 | .. autoclass:: AcceptNoHeader
38 | :members: parse, header_value, parsed, __init__, __add__, __bool__,
39 | __contains__, __iter__, __radd__, __repr__, __str__,
40 | accept_html, accepts_html, acceptable_offers, best_match, quality
41 |
42 | .. autoclass:: AcceptInvalidHeader
43 | :members: parse, header_value, parsed, __init__, __add__, __bool__,
44 | __contains__, __iter__, __radd__, __repr__, __str__,
45 | accept_html, accepts_html, acceptable_offers, best_match, quality
46 |
47 | .. autoclass:: AcceptCharset
48 | :members: parse
49 |
50 | .. autoclass:: AcceptCharsetValidHeader
51 | :members: parse, header_value, parsed, __init__, __add__, __bool__,
52 | __contains__, __iter__, __radd__, __repr__, __str__,
53 | acceptable_offers, best_match, quality
54 |
55 | .. autoclass:: AcceptCharsetNoHeader
56 | :members: parse, header_value, parsed, __init__, __add__, __bool__,
57 | __contains__, __iter__, __radd__, __repr__, __str__,
58 | acceptable_offers, best_match, quality
59 |
60 | .. autoclass:: AcceptCharsetInvalidHeader
61 | :members: parse, header_value, parsed, __init__, __add__, __bool__,
62 | __contains__, __iter__, __radd__, __repr__, __str__,
63 | acceptable_offers, best_match, quality
64 |
65 | .. autoclass:: AcceptEncoding
66 | :members: parse
67 |
68 | .. autoclass:: AcceptEncodingValidHeader
69 | :members: parse, header_value, parsed, __init__, __add__, __bool__,
70 | __contains__, __iter__, __radd__, __repr__, __str__,
71 | acceptable_offers, best_match, quality
72 |
73 | .. autoclass:: AcceptEncodingNoHeader
74 | :members: parse, header_value, parsed, __init__, __add__, __bool__,
75 | __contains__, __iter__, __radd__, __repr__, __str__,
76 | acceptable_offers, best_match, quality
77 |
78 | .. autoclass:: AcceptEncodingInvalidHeader
79 | :members: parse, header_value, parsed, __init__, __add__, __bool__,
80 | __contains__, __iter__, __radd__, __repr__, __str__,
81 | acceptable_offers, best_match, quality
82 |
83 | .. autoclass:: AcceptLanguage
84 | :members: parse
85 |
86 | .. autoclass:: AcceptLanguageValidHeader
87 | :members: header_value, parsed, __init__, __add__, __contains__, __iter__,
88 | __radd__, __str__, parse, basic_filtering, best_match, lookup,
89 | quality
90 |
91 | .. autoclass:: AcceptLanguageNoHeader
92 | :members: header_value, parsed, __init__, __add__, __contains__, __iter__,
93 | __radd__, __str__, parse, basic_filtering, best_match, lookup,
94 | quality
95 |
96 | .. autoclass:: AcceptLanguageInvalidHeader
97 | :members: header_value, parsed, __init__, __add__, __contains__, __iter__,
98 | __radd__, __str__, parse, basic_filtering, best_match, lookup,
99 | quality
100 |
101 | Deprecated:
102 |
103 | .. autoclass:: MIMEAccept
104 |
105 |
106 | Cache-Control
107 | ~~~~~~~~~~~~~
108 | .. autoclass:: webob.cachecontrol.CacheControl
109 | :members:
110 |
111 | Range and related headers
112 | ~~~~~~~~~~~~~~~~~~~~~~~~~
113 | .. autoclass:: webob.byterange.Range
114 | :members:
115 | .. autoclass:: webob.byterange.ContentRange
116 | :members:
117 | .. autoclass:: webob.etag.IfRange
118 | :members:
119 |
120 | ETag
121 | ~~~~
122 | .. autoclass:: webob.etag.ETagMatcher
123 | :members:
124 |
125 | Misc Functions and Internals
126 | ----------------------------
127 |
128 | .. autofunction:: webob.html_escape
129 |
130 | .. comment:
131 | not sure what to do with these constants; not autoclass
132 | .. autoclass:: webob.day
133 | .. autoclass:: webob.week
134 | .. autoclass:: webob.hour
135 | .. autoclass:: webob.minute
136 | .. autoclass:: webob.second
137 | .. autoclass:: webob.month
138 | .. autoclass:: webob.year
139 |
140 | .. autoclass:: webob.headers.ResponseHeaders
141 | :members:
142 | .. autoclass:: webob.headers.EnvironHeaders
143 | :members:
144 |
145 | .. autoclass:: webob.cachecontrol.UpdateDict
146 | :members:
147 |
148 |
149 | .. comment:
150 | Descriptors
151 | -----------
152 |
153 | .. autoclass:: webob.descriptors.environ_getter
154 | .. autoclass:: webob.descriptors.header_getter
155 | .. autoclass:: webob.descriptors.converter
156 | .. autoclass:: webob.descriptors.deprecated_property
157 |
--------------------------------------------------------------------------------
/docs/changes.txt:
--------------------------------------------------------------------------------
1 | .. _changelog:
2 |
3 | WebOb Change History
4 | ====================
5 |
6 | .. include:: ../CHANGES.txt
7 |
8 | .. include:: ../HISTORY.txt
9 |
--------------------------------------------------------------------------------
/docs/comment-example-code/example.py:
--------------------------------------------------------------------------------
1 | import os
2 | import urllib
3 | import time
4 | import re
5 | from cPickle import load, dump
6 | from webob import Request, Response, html_escape
7 | from webob import exc
8 |
9 |
10 | class Commenter(object):
11 | def __init__(self, app, storage_dir):
12 | self.app = app
13 | self.storage_dir = storage_dir
14 | if not os.path.exists(storage_dir):
15 | os.makedirs(storage_dir)
16 |
17 | def __call__(self, environ, start_response):
18 | req = Request(environ)
19 | if req.path_info_peek() == ".comments":
20 | return self.process_comment(req)(environ, start_response)
21 | # This is the base path of *this* middleware:
22 | base_url = req.application_url
23 | resp = req.get_response(self.app)
24 | if resp.content_type != "text/html" or resp.status_code != 200:
25 | # Not an HTML response, we don't want to
26 | # do anything to it
27 | return resp(environ, start_response)
28 | # Make sure the content isn't gzipped:
29 | resp.decode_content()
30 | comments = self.get_data(req.url)
31 | body = resp.body
32 | body = self.add_to_end(body, self.format_comments(comments))
33 | body = self.add_to_end(body, self.submit_form(base_url, req))
34 | resp.body = body
35 | return resp(environ, start_response)
36 |
37 | def get_data(self, url):
38 | # Double-quoting makes the filename safe
39 | filename = self.url_filename(url)
40 | if not os.path.exists(filename):
41 | return []
42 | else:
43 | f = open(filename, "rb")
44 | data = load(f)
45 | f.close()
46 | return data
47 |
48 | def save_data(self, url, data):
49 | filename = self.url_filename(url)
50 | f = open(filename, "wb")
51 | dump(data, f)
52 | f.close()
53 |
54 | def url_filename(self, url):
55 | return os.path.join(self.storage_dir, urllib.quote(url, ""))
56 |
57 | _end_body_re = re.compile(r"", re.I | re.S)
58 |
59 | def add_to_end(self, html, extra_html):
60 | """
61 | Adds extra_html to the end of the html page (before