123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181 |
- """A small application that can be used to test a WSGI server and check
- it for WSGI compliance.
- """
- from __future__ import annotations
- import os
- import sys
- import typing as t
- from textwrap import wrap
- from markupsafe import escape
- from . import __version__ as _werkzeug_version
- from .wrappers.request import Request
- from .wrappers.response import Response
- TEMPLATE = """\
- <!doctype html>
- <html lang=en>
- <title>WSGI Information</title>
- <style type="text/css">
- @import url(https://fonts.googleapis.com/css?family=Ubuntu);
- body { font-family: 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva',
- 'Verdana', sans-serif; background-color: white; color: #000;
- font-size: 15px; text-align: center; }
- div.box { text-align: left; width: 45em; margin: auto; padding: 50px 0;
- background-color: white; }
- h1, h2 { font-family: 'Ubuntu', 'Lucida Grande', 'Lucida Sans Unicode',
- 'Geneva', 'Verdana', sans-serif; font-weight: normal; }
- h1 { margin: 0 0 30px 0; }
- h2 { font-size: 1.4em; margin: 1em 0 0.5em 0; }
- table { width: 100%%; border-collapse: collapse; border: 1px solid #AFC5C9 }
- table th { background-color: #AFC1C4; color: white; font-size: 0.72em;
- font-weight: normal; width: 18em; vertical-align: top;
- padding: 0.5em 0 0.1em 0.5em; }
- table td { border: 1px solid #AFC5C9; padding: 0.1em 0 0.1em 0.5em; }
- code { font-family: 'Consolas', 'Monaco', 'Bitstream Vera Sans Mono',
- monospace; font-size: 0.7em; }
- ul li { line-height: 1.5em; }
- ul.path { font-size: 0.7em; margin: 0 -30px; padding: 8px 30px;
- list-style: none; background: #E8EFF0; }
- ul.path li { line-height: 1.6em; }
- li.virtual { color: #999; text-decoration: underline; }
- li.exp { background: white; }
- </style>
- <div class="box">
- <h1>WSGI Information</h1>
- <p>
- This page displays all available information about the WSGI server and
- the underlying Python interpreter.
- <h2 id="python-interpreter">Python Interpreter</h2>
- <table>
- <tr>
- <th>Python Version
- <td>%(python_version)s
- <tr>
- <th>Platform
- <td>%(platform)s [%(os)s]
- <tr>
- <th>API Version
- <td>%(api_version)s
- <tr>
- <th>Byteorder
- <td>%(byteorder)s
- <tr>
- <th>Werkzeug Version
- <td>%(werkzeug_version)s
- </table>
- <h2 id="wsgi-environment">WSGI Environment</h2>
- <table>%(wsgi_env)s</table>
- <h2 id="installed-eggs">Installed Eggs</h2>
- <p>
- The following python packages were installed on the system as
- Python eggs:
- <ul>%(python_eggs)s</ul>
- <h2 id="sys-path">System Path</h2>
- <p>
- The following paths are the current contents of the load path. The
- following entries are looked up for Python packages. Note that not
- all items in this path are folders. Gray and underlined items are
- entries pointing to invalid resources or used by custom import hooks
- such as the zip importer.
- <p>
- Items with a bright background were expanded for display from a relative
- path. If you encounter such paths in the output you might want to check
- your setup as relative paths are usually problematic in multithreaded
- environments.
- <ul class="path">%(sys_path)s</ul>
- </div>
- """
- def iter_sys_path() -> t.Iterator[tuple[str, bool, bool]]:
- if os.name == "posix":
- def strip(x: str) -> str:
- prefix = os.path.expanduser("~")
- if x.startswith(prefix):
- x = f"~{x[len(prefix) :]}"
- return x
- else:
- def strip(x: str) -> str:
- return x
- cwd = os.path.abspath(os.getcwd())
- for item in sys.path:
- path = os.path.join(cwd, item or os.path.curdir)
- yield strip(os.path.normpath(path)), not os.path.isdir(path), path != item
- @Request.application
- def test_app(req: Request) -> Response:
- """Simple test application that dumps the environment. You can use
- it to check if Werkzeug is working properly:
- .. sourcecode:: pycon
- >>> from werkzeug.serving import run_simple
- >>> from werkzeug.testapp import test_app
- >>> run_simple('localhost', 3000, test_app)
- * Running on http://localhost:3000/
- The application displays important information from the WSGI environment,
- the Python interpreter and the installed libraries.
- """
- try:
- import pkg_resources
- except ImportError:
- eggs: t.Iterable[t.Any] = ()
- else:
- eggs = sorted(
- pkg_resources.working_set,
- key=lambda x: x.project_name.lower(),
- )
- python_eggs = []
- for egg in eggs:
- try:
- version = egg.version
- except (ValueError, AttributeError):
- version = "unknown"
- python_eggs.append(
- f"<li>{escape(egg.project_name)} <small>[{escape(version)}]</small>"
- )
- wsgi_env = []
- sorted_environ = sorted(req.environ.items(), key=lambda x: repr(x[0]).lower())
- for key, value in sorted_environ:
- value = "".join(wrap(str(escape(repr(value)))))
- wsgi_env.append(f"<tr><th>{escape(key)}<td><code>{value}</code>")
- sys_path = []
- for item, virtual, expanded in iter_sys_path():
- class_ = []
- if virtual:
- class_.append("virtual")
- if expanded:
- class_.append("exp")
- class_ = f' class="{" ".join(class_)}"' if class_ else ""
- sys_path.append(f"<li{class_}>{escape(item)}")
- context = {
- "python_version": "<br>".join(escape(sys.version).splitlines()),
- "platform": escape(sys.platform),
- "os": escape(os.name),
- "api_version": sys.api_version,
- "byteorder": sys.byteorder,
- "werkzeug_version": _werkzeug_version,
- "python_eggs": "\n".join(python_eggs),
- "wsgi_env": "\n".join(wsgi_env),
- "sys_path": "\n".join(sys_path),
- }
- return Response(TEMPLATE % context, mimetype="text/html")
- if __name__ == "__main__":
- from .serving import run_simple
- run_simple("localhost", 5000, test_app, use_reloader=True)
|