mirror of
https://github.com/tahoe-lafs/tahoe-lafs.git
synced 2025-05-01 08:20:51 +00:00
129 lines
3.9 KiB
Python
129 lines
3.9 KiB
Python
"""
|
|
Common utilities that are available from Python 3.
|
|
|
|
Can eventually be merged back into allmydata.web.common.
|
|
"""
|
|
|
|
from past.builtins import unicode
|
|
|
|
from twisted.web import resource, http
|
|
|
|
from allmydata.util import abbreviate
|
|
|
|
|
|
class WebError(Exception):
|
|
def __init__(self, text, code=http.BAD_REQUEST):
|
|
self.text = text
|
|
self.code = code
|
|
|
|
|
|
def get_arg(req, argname, default=None, multiple=False):
|
|
"""Extract an argument from either the query args (req.args) or the form
|
|
body fields (req.fields). If multiple=False, this returns a single value
|
|
(or the default, which defaults to None), and the query args take
|
|
precedence. If multiple=True, this returns a tuple of arguments (possibly
|
|
empty), starting with all those in the query args.
|
|
|
|
:param TahoeLAFSRequest req: The request to consider.
|
|
|
|
:return: Either bytes or tuple of bytes.
|
|
"""
|
|
if isinstance(argname, unicode):
|
|
argname = argname.encode("utf-8")
|
|
if isinstance(default, unicode):
|
|
default = default.encode("utf-8")
|
|
results = []
|
|
if argname in req.args:
|
|
results.extend(req.args[argname])
|
|
if req.fields and argname in req.fields:
|
|
results.append(req.fields[argname].value)
|
|
if multiple:
|
|
return tuple(results)
|
|
if results:
|
|
return results[0]
|
|
return default
|
|
|
|
|
|
class MultiFormatResource(resource.Resource, object):
|
|
"""
|
|
``MultiFormatResource`` is a ``resource.Resource`` that can be rendered in
|
|
a number of different formats.
|
|
|
|
Rendered format is controlled by a query argument (given by
|
|
``self.formatArgument``). Different resources may support different
|
|
formats but ``json`` is a pretty common one. ``html`` is the default
|
|
format if nothing else is given as the ``formatDefault``.
|
|
"""
|
|
formatArgument = "t"
|
|
formatDefault = None
|
|
|
|
def render(self, req):
|
|
"""
|
|
Dispatch to a renderer for a particular format, as selected by a query
|
|
argument.
|
|
|
|
A renderer for the format given by the query argument matching
|
|
``formatArgument`` will be selected and invoked. render_HTML will be
|
|
used as a default if no format is selected (either by query arguments
|
|
or by ``formatDefault``).
|
|
|
|
:return: The result of the selected renderer.
|
|
"""
|
|
t = get_arg(req, self.formatArgument, self.formatDefault)
|
|
# It's either bytes or None.
|
|
if isinstance(t, bytes):
|
|
t = unicode(t, "ascii")
|
|
renderer = self._get_renderer(t)
|
|
return renderer(req)
|
|
|
|
def _get_renderer(self, fmt):
|
|
"""
|
|
Get the renderer for the indicated format.
|
|
|
|
:param str fmt: The format. If a method with a prefix of ``render_``
|
|
and a suffix of this format (upper-cased) is found, it will be
|
|
used.
|
|
|
|
:return: A callable which takes a twisted.web Request and renders a
|
|
response.
|
|
"""
|
|
renderer = None
|
|
|
|
if fmt is not None:
|
|
try:
|
|
renderer = getattr(self, "render_{}".format(fmt.upper()))
|
|
except AttributeError:
|
|
return resource.ErrorPage(
|
|
http.BAD_REQUEST,
|
|
"Bad Format",
|
|
"Unknown {} value: {!r}".format(self.formatArgument, fmt),
|
|
).render
|
|
|
|
if renderer is None:
|
|
renderer = self.render_HTML
|
|
|
|
return renderer
|
|
|
|
|
|
def abbreviate_time(data):
|
|
"""
|
|
Convert number of seconds into human readable string.
|
|
|
|
:param data: Either ``None`` or integer or float, seconds.
|
|
|
|
:return: Unicode string.
|
|
"""
|
|
# 1.23s, 790ms, 132us
|
|
if data is None:
|
|
return u""
|
|
s = float(data)
|
|
if s >= 10:
|
|
return abbreviate.abbreviate_time(data)
|
|
if s >= 1.0:
|
|
return u"%.2fs" % s
|
|
if s >= 0.01:
|
|
return u"%.0fms" % (1000*s)
|
|
if s >= 0.001:
|
|
return u"%.1fms" % (1000*s)
|
|
return u"%.0fus" % (1000000*s)
|