Translation of UI (german and english)
Bugfix for feeds
- removed categories related and up
- load new books now working
- category random now working
login page is free of non accessible elements
boolean custom column is vivible in UI
books with only with certain languages can be shown
book shelfs can be deleted from UI
Anonymous user view is more resticted
Added browse of series in sidebar
Dependencys in vendor folder are updated to newer versions (licencs files are now present)
Bugfix editing Authors names
Made upload on windows working
This commit is contained in:
Vendored
+112
-30
@@ -5,18 +5,20 @@
|
||||
|
||||
This module provides mixins and classes with an immutable interface.
|
||||
|
||||
:copyright: (c) 2013 by the Werkzeug Team, see AUTHORS for more details.
|
||||
:copyright: (c) 2014 by the Werkzeug Team, see AUTHORS for more details.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
import re
|
||||
import sys
|
||||
import codecs
|
||||
import mimetypes
|
||||
from copy import deepcopy
|
||||
from itertools import repeat
|
||||
|
||||
from werkzeug._internal import _missing, _empty_stream
|
||||
from werkzeug._compat import iterkeys, itervalues, iteritems, iterlists, \
|
||||
PY2, text_type, integer_types, string_types, make_literal_wrapper
|
||||
PY2, text_type, integer_types, string_types, make_literal_wrapper, \
|
||||
to_native
|
||||
from werkzeug.filesystem import get_filesystem_encoding
|
||||
|
||||
|
||||
_locale_delim_re = re.compile(r'[_-]')
|
||||
@@ -48,12 +50,13 @@ def iter_multi_items(mapping):
|
||||
def native_itermethods(names):
|
||||
if not PY2:
|
||||
return lambda x: x
|
||||
|
||||
def setmethod(cls, name):
|
||||
itermethod = getattr(cls, name)
|
||||
setattr(cls, 'iter%s' % name, itermethod)
|
||||
listmethod = lambda self, *a, **kw: list(itermethod(self, *a, **kw))
|
||||
listmethod.__doc__ = \
|
||||
'Like :py:meth:`iter%s`, but returns a list.' % name
|
||||
'Like :py:meth:`iter%s`, but returns a list.' % name
|
||||
setattr(cls, name, listmethod)
|
||||
|
||||
def wrap(cls):
|
||||
@@ -64,6 +67,7 @@ def native_itermethods(names):
|
||||
|
||||
|
||||
class ImmutableListMixin(object):
|
||||
|
||||
"""Makes a :class:`list` immutable.
|
||||
|
||||
.. versionadded:: 0.5
|
||||
@@ -119,6 +123,7 @@ class ImmutableListMixin(object):
|
||||
|
||||
|
||||
class ImmutableList(ImmutableListMixin, list):
|
||||
|
||||
"""An immutable :class:`list`.
|
||||
|
||||
.. versionadded:: 0.5
|
||||
@@ -129,11 +134,12 @@ class ImmutableList(ImmutableListMixin, list):
|
||||
def __repr__(self):
|
||||
return '%s(%s)' % (
|
||||
self.__class__.__name__,
|
||||
dict.__repr__(self),
|
||||
list.__repr__(self),
|
||||
)
|
||||
|
||||
|
||||
class ImmutableDictMixin(object):
|
||||
|
||||
"""Makes a :class:`dict` immutable.
|
||||
|
||||
.. versionadded:: 0.5
|
||||
@@ -183,6 +189,7 @@ class ImmutableDictMixin(object):
|
||||
|
||||
|
||||
class ImmutableMultiDictMixin(ImmutableDictMixin):
|
||||
|
||||
"""Makes a :class:`MultiDict` immutable.
|
||||
|
||||
.. versionadded:: 0.5
|
||||
@@ -213,6 +220,7 @@ class ImmutableMultiDictMixin(ImmutableDictMixin):
|
||||
|
||||
|
||||
class UpdateDictMixin(object):
|
||||
|
||||
"""Makes dicts call `self.on_update` on modifications.
|
||||
|
||||
.. versionadded:: 0.5
|
||||
@@ -257,6 +265,7 @@ class UpdateDictMixin(object):
|
||||
|
||||
|
||||
class TypeConversionDict(dict):
|
||||
|
||||
"""Works like a regular dict but the :meth:`get` method can perform
|
||||
type conversions. :class:`MultiDict` and :class:`CombinedMultiDict`
|
||||
are subclasses of this class and provide the same feature.
|
||||
@@ -295,6 +304,7 @@ class TypeConversionDict(dict):
|
||||
|
||||
|
||||
class ImmutableTypeConversionDict(ImmutableDictMixin, TypeConversionDict):
|
||||
|
||||
"""Works like a :class:`TypeConversionDict` but does not support
|
||||
modifications.
|
||||
|
||||
@@ -314,6 +324,7 @@ class ImmutableTypeConversionDict(ImmutableDictMixin, TypeConversionDict):
|
||||
|
||||
@native_itermethods(['keys', 'values', 'items', 'lists', 'listvalues'])
|
||||
class MultiDict(TypeConversionDict):
|
||||
|
||||
"""A :class:`MultiDict` is a dictionary subclass customized to deal with
|
||||
multiple values for the same key which is for example used by the parsing
|
||||
functions in the wrappers. This is necessary because some HTML form
|
||||
@@ -361,6 +372,8 @@ class MultiDict(TypeConversionDict):
|
||||
tmp = {}
|
||||
for key, value in iteritems(mapping):
|
||||
if isinstance(value, (tuple, list)):
|
||||
if len(value) == 0:
|
||||
continue
|
||||
value = list(value)
|
||||
else:
|
||||
value = [value]
|
||||
@@ -387,7 +400,9 @@ class MultiDict(TypeConversionDict):
|
||||
:raise KeyError: if the key does not exist.
|
||||
"""
|
||||
if key in self:
|
||||
return dict.__getitem__(self, key)[0]
|
||||
lst = dict.__getitem__(self, key)
|
||||
if len(lst) > 0:
|
||||
return lst[0]
|
||||
raise exceptions.BadRequestKeyError(key)
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
@@ -537,6 +552,10 @@ class MultiDict(TypeConversionDict):
|
||||
"""Return a shallow copy of this object."""
|
||||
return self.__class__(self)
|
||||
|
||||
def deepcopy(self, memo=None):
|
||||
"""Return a deep copy of this object."""
|
||||
return self.__class__(deepcopy(self.to_dict(flat=False), memo))
|
||||
|
||||
def to_dict(self, flat=True):
|
||||
"""Return the contents as regular dict. If `flat` is `True` the
|
||||
returned dict will only have the first item present, if `flat` is
|
||||
@@ -552,7 +571,23 @@ class MultiDict(TypeConversionDict):
|
||||
return dict(self.lists())
|
||||
|
||||
def update(self, other_dict):
|
||||
"""update() extends rather than replaces existing key lists."""
|
||||
"""update() extends rather than replaces existing key lists:
|
||||
|
||||
>>> a = MultiDict({'x': 1})
|
||||
>>> b = MultiDict({'x': 2, 'y': 3})
|
||||
>>> a.update(b)
|
||||
>>> a
|
||||
MultiDict([('y', 3), ('x', 1), ('x', 2)])
|
||||
|
||||
If the value list for a key in ``other_dict`` is empty, no new values
|
||||
will be added to the dict and the key will not be created:
|
||||
|
||||
>>> x = {'empty_list': []}
|
||||
>>> y = MultiDict()
|
||||
>>> y.update(x)
|
||||
>>> y
|
||||
MultiDict([])
|
||||
"""
|
||||
for key, value in iter_multi_items(other_dict):
|
||||
MultiDict.add(self, key, value)
|
||||
|
||||
@@ -605,11 +640,15 @@ class MultiDict(TypeConversionDict):
|
||||
def __copy__(self):
|
||||
return self.copy()
|
||||
|
||||
def __deepcopy__(self, memo):
|
||||
return self.deepcopy(memo=memo)
|
||||
|
||||
def __repr__(self):
|
||||
return '%s(%r)' % (self.__class__.__name__, list(iteritems(self, multi=True)))
|
||||
|
||||
|
||||
class _omd_bucket(object):
|
||||
|
||||
"""Wraps values in the :class:`OrderedMultiDict`. This makes it
|
||||
possible to keep an order over multiple different keys. It requires
|
||||
a lot of extra memory and slows down access a lot, but makes it
|
||||
@@ -642,6 +681,7 @@ class _omd_bucket(object):
|
||||
|
||||
@native_itermethods(['keys', 'values', 'items', 'lists', 'listvalues'])
|
||||
class OrderedMultiDict(MultiDict):
|
||||
|
||||
"""Works like a regular :class:`MultiDict` but preserves the
|
||||
order of the fields. To convert the ordered multi dict into a
|
||||
list you can use the :meth:`items` method and pass it ``multi=True``.
|
||||
@@ -818,7 +858,7 @@ class OrderedMultiDict(MultiDict):
|
||||
|
||||
def _options_header_vkw(value, kw):
|
||||
return dump_options_header(value, dict((k.replace('_', '-'), v)
|
||||
for k, v in kw.items()))
|
||||
for k, v in kw.items()))
|
||||
|
||||
|
||||
def _unicodify_header_value(value):
|
||||
@@ -831,6 +871,7 @@ def _unicodify_header_value(value):
|
||||
|
||||
@native_itermethods(['keys', 'values', 'items'])
|
||||
class Headers(object):
|
||||
|
||||
"""An object that stores some headers. It has a dict-like interface
|
||||
but is ordered and can store the same keys multiple times.
|
||||
|
||||
@@ -892,7 +933,7 @@ class Headers(object):
|
||||
|
||||
def __eq__(self, other):
|
||||
return other.__class__ is self.__class__ and \
|
||||
set(other._list) == set(self._list)
|
||||
set(other._list) == set(self._list)
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self.__eq__(other)
|
||||
@@ -1091,7 +1132,7 @@ class Headers(object):
|
||||
raise TypeError('Value should be unicode.')
|
||||
if u'\n' in value or u'\r' in value:
|
||||
raise ValueError('Detected newline in header value. This is '
|
||||
'a potential security problem')
|
||||
'a potential security problem')
|
||||
|
||||
def add_header(self, _key, _value, **_kw):
|
||||
"""Add a new header tuple to the list.
|
||||
@@ -1182,7 +1223,7 @@ class Headers(object):
|
||||
:return: list
|
||||
"""
|
||||
if PY2:
|
||||
return [(k, v.encode('latin1')) for k, v in self]
|
||||
return [(to_native(k), v.encode('latin1')) for k, v in self]
|
||||
return list(self)
|
||||
|
||||
def copy(self):
|
||||
@@ -1207,6 +1248,7 @@ class Headers(object):
|
||||
|
||||
|
||||
class ImmutableHeadersMixin(object):
|
||||
|
||||
"""Makes a :class:`Headers` immutable. We do not mark them as
|
||||
hashable though since the only usecase for this datastructure
|
||||
in Werkzeug is a view on a mutable structure.
|
||||
@@ -1244,6 +1286,7 @@ class ImmutableHeadersMixin(object):
|
||||
|
||||
|
||||
class EnvironHeaders(ImmutableHeadersMixin, Headers):
|
||||
|
||||
"""Read only version of the headers from a WSGI environment. This
|
||||
provides the same interface as `Headers` and is constructed from
|
||||
a WSGI environment.
|
||||
@@ -1289,6 +1332,7 @@ class EnvironHeaders(ImmutableHeadersMixin, Headers):
|
||||
|
||||
@native_itermethods(['keys', 'values', 'items', 'lists', 'listvalues'])
|
||||
class CombinedMultiDict(ImmutableMultiDictMixin, MultiDict):
|
||||
|
||||
"""A read only :class:`MultiDict` that you can pass multiple :class:`MultiDict`
|
||||
instances as sequence and it will combine the return values of all wrapped
|
||||
dicts:
|
||||
@@ -1345,11 +1389,20 @@ class CombinedMultiDict(ImmutableMultiDictMixin, MultiDict):
|
||||
rv.extend(d.getlist(key, type))
|
||||
return rv
|
||||
|
||||
def keys(self):
|
||||
def _keys_impl(self):
|
||||
"""This function exists so __len__ can be implemented more efficiently,
|
||||
saving one list creation from an iterator.
|
||||
|
||||
Using this for Python 2's ``dict.keys`` behavior would be useless since
|
||||
`dict.keys` in Python 2 returns a list, while we have a set here.
|
||||
"""
|
||||
rv = set()
|
||||
for d in self.dicts:
|
||||
rv.update(d.keys())
|
||||
return iter(rv)
|
||||
rv.update(iterkeys(d))
|
||||
return rv
|
||||
|
||||
def keys(self):
|
||||
return iter(self._keys_impl())
|
||||
|
||||
__iter__ = keys
|
||||
|
||||
@@ -1397,7 +1450,7 @@ class CombinedMultiDict(ImmutableMultiDictMixin, MultiDict):
|
||||
return rv
|
||||
|
||||
def __len__(self):
|
||||
return len(self.keys())
|
||||
return len(self._keys_impl())
|
||||
|
||||
def __contains__(self, key):
|
||||
for d in self.dicts:
|
||||
@@ -1412,6 +1465,7 @@ class CombinedMultiDict(ImmutableMultiDictMixin, MultiDict):
|
||||
|
||||
|
||||
class FileMultiDict(MultiDict):
|
||||
|
||||
"""A special :class:`MultiDict` that has convenience methods to add
|
||||
files to it. This is used for :class:`EnvironBuilder` and generally
|
||||
useful for unittesting.
|
||||
@@ -1437,13 +1491,14 @@ class FileMultiDict(MultiDict):
|
||||
file = open(file, 'rb')
|
||||
if filename and content_type is None:
|
||||
content_type = mimetypes.guess_type(filename)[0] or \
|
||||
'application/octet-stream'
|
||||
'application/octet-stream'
|
||||
value = FileStorage(file, filename, name, content_type)
|
||||
|
||||
self.add(name, value)
|
||||
|
||||
|
||||
class ImmutableDict(ImmutableDictMixin, dict):
|
||||
|
||||
"""An immutable :class:`dict`.
|
||||
|
||||
.. versionadded:: 0.5
|
||||
@@ -1467,6 +1522,7 @@ class ImmutableDict(ImmutableDictMixin, dict):
|
||||
|
||||
|
||||
class ImmutableMultiDict(ImmutableMultiDictMixin, MultiDict):
|
||||
|
||||
"""An immutable :class:`MultiDict`.
|
||||
|
||||
.. versionadded:: 0.5
|
||||
@@ -1484,6 +1540,7 @@ class ImmutableMultiDict(ImmutableMultiDictMixin, MultiDict):
|
||||
|
||||
|
||||
class ImmutableOrderedMultiDict(ImmutableMultiDictMixin, OrderedMultiDict):
|
||||
|
||||
"""An immutable :class:`OrderedMultiDict`.
|
||||
|
||||
.. versionadded:: 0.6
|
||||
@@ -1505,6 +1562,7 @@ class ImmutableOrderedMultiDict(ImmutableMultiDictMixin, OrderedMultiDict):
|
||||
|
||||
@native_itermethods(['values'])
|
||||
class Accept(ImmutableList):
|
||||
|
||||
"""An :class:`Accept` object is just a list subclass for lists of
|
||||
``(value, quality)`` tuples. It is automatically sorted by quality.
|
||||
|
||||
@@ -1641,7 +1699,8 @@ class Accept(ImmutableList):
|
||||
for client_item, quality in self:
|
||||
if quality <= best_quality:
|
||||
break
|
||||
if self._value_matches(server_item, client_item):
|
||||
if self._value_matches(server_item, client_item) \
|
||||
and quality > 0:
|
||||
best_quality = quality
|
||||
result = server_item
|
||||
return result
|
||||
@@ -1654,6 +1713,7 @@ class Accept(ImmutableList):
|
||||
|
||||
|
||||
class MIMEAccept(Accept):
|
||||
|
||||
"""Like :class:`Accept` but with special methods and behavior for
|
||||
mimetypes.
|
||||
"""
|
||||
@@ -1708,6 +1768,7 @@ class MIMEAccept(Accept):
|
||||
|
||||
|
||||
class LanguageAccept(Accept):
|
||||
|
||||
"""Like :class:`Accept` but with normalization for languages."""
|
||||
|
||||
def _value_matches(self, value, item):
|
||||
@@ -1717,6 +1778,7 @@ class LanguageAccept(Accept):
|
||||
|
||||
|
||||
class CharsetAccept(Accept):
|
||||
|
||||
"""Like :class:`Accept` but with normalization for charsets."""
|
||||
|
||||
def _value_matches(self, value, item):
|
||||
@@ -1738,6 +1800,7 @@ def cache_property(key, empty, type):
|
||||
|
||||
|
||||
class _CacheControl(UpdateDictMixin, dict):
|
||||
|
||||
"""Subclass of a dict that stores values for a Cache-Control header. It
|
||||
has accessors for all the cache-control directives specified in RFC 2616.
|
||||
The class does not differentiate between request and response directives.
|
||||
@@ -1822,13 +1885,16 @@ class _CacheControl(UpdateDictMixin, dict):
|
||||
return self.to_header()
|
||||
|
||||
def __repr__(self):
|
||||
return '<%s %r>' % (
|
||||
return '<%s %s>' % (
|
||||
self.__class__.__name__,
|
||||
self.to_header()
|
||||
" ".join(
|
||||
"%s=%r" % (k, v) for k, v in sorted(self.items())
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
class RequestCacheControl(ImmutableDictMixin, _CacheControl):
|
||||
|
||||
"""A cache control for requests. This is immutable and gives access
|
||||
to all the request-relevant cache control headers.
|
||||
|
||||
@@ -1849,6 +1915,7 @@ class RequestCacheControl(ImmutableDictMixin, _CacheControl):
|
||||
|
||||
|
||||
class ResponseCacheControl(_CacheControl):
|
||||
|
||||
"""A cache control for responses. Unlike :class:`RequestCacheControl`
|
||||
this is mutable and gives access to response-relevant cache control
|
||||
headers.
|
||||
@@ -1876,6 +1943,7 @@ _CacheControl.cache_property = staticmethod(cache_property)
|
||||
|
||||
|
||||
class CallbackDict(UpdateDictMixin, dict):
|
||||
|
||||
"""A dict that calls a function passed every time something is changed.
|
||||
The function is passed the dict instance.
|
||||
"""
|
||||
@@ -1892,6 +1960,7 @@ class CallbackDict(UpdateDictMixin, dict):
|
||||
|
||||
|
||||
class HeaderSet(object):
|
||||
|
||||
"""Similar to the :class:`ETags` class this implements a set-like structure.
|
||||
Unlike :class:`ETags` this is case insensitive and used for vary, allow, and
|
||||
content-language headers.
|
||||
@@ -2045,6 +2114,7 @@ class HeaderSet(object):
|
||||
|
||||
|
||||
class ETags(object):
|
||||
|
||||
"""A set that can be used to check if one etag is present in a collection
|
||||
of etags.
|
||||
"""
|
||||
@@ -2094,7 +2164,7 @@ class ETags(object):
|
||||
return '*'
|
||||
return ', '.join(
|
||||
['"%s"' % x for x in self._strong] +
|
||||
['w/"%s"' % x for x in self._weak]
|
||||
['W/"%s"' % x for x in self._weak]
|
||||
)
|
||||
|
||||
def __call__(self, etag=None, data=None, include_weak=False):
|
||||
@@ -2107,9 +2177,11 @@ class ETags(object):
|
||||
return True
|
||||
return etag in self._strong
|
||||
|
||||
def __nonzero__(self):
|
||||
def __bool__(self):
|
||||
return bool(self.star_tag or self._strong or self._weak)
|
||||
|
||||
__nonzero__ = __bool__
|
||||
|
||||
def __str__(self):
|
||||
return self.to_header()
|
||||
|
||||
@@ -2124,6 +2196,7 @@ class ETags(object):
|
||||
|
||||
|
||||
class IfRange(object):
|
||||
|
||||
"""Very simple object that represents the `If-Range` header in parsed
|
||||
form. It will either have neither a etag or date or one of either but
|
||||
never both.
|
||||
@@ -2154,6 +2227,7 @@ class IfRange(object):
|
||||
|
||||
|
||||
class Range(object):
|
||||
|
||||
"""Represents a range header. All the methods are only supporting bytes
|
||||
as unit. It does store multiple ranges but :meth:`range_for_length` will
|
||||
only work if only one range is provided.
|
||||
@@ -2209,6 +2283,7 @@ class Range(object):
|
||||
|
||||
|
||||
class ContentRange(object):
|
||||
|
||||
"""Represents the content range header.
|
||||
|
||||
.. versionadded:: 0.7
|
||||
@@ -2223,6 +2298,7 @@ class ContentRange(object):
|
||||
def _callback_property(name):
|
||||
def fget(self):
|
||||
return getattr(self, name)
|
||||
|
||||
def fset(self, value):
|
||||
setattr(self, name, value)
|
||||
if self.on_update is not None:
|
||||
@@ -2285,6 +2361,7 @@ class ContentRange(object):
|
||||
|
||||
|
||||
class Authorization(ImmutableDictMixin, dict):
|
||||
|
||||
"""Represents an `Authorization` header sent by the client. You should
|
||||
not create this kind of object yourself but use it when it's returned by
|
||||
the `parse_authorization_header` function.
|
||||
@@ -2345,10 +2422,11 @@ class Authorization(ImmutableDictMixin, dict):
|
||||
|
||||
|
||||
class WWWAuthenticate(UpdateDictMixin, dict):
|
||||
|
||||
"""Provides simple access to `WWW-Authenticate` headers."""
|
||||
|
||||
#: list of keys that require quoting in the generated header
|
||||
_require_quoting = frozenset(['domain', 'nonce', 'opaque', 'realm'])
|
||||
_require_quoting = frozenset(['domain', 'nonce', 'opaque', 'realm', 'qop'])
|
||||
|
||||
def __init__(self, auth_type=None, values=None, on_update=None):
|
||||
dict.__init__(self, values or ())
|
||||
@@ -2389,7 +2467,7 @@ class WWWAuthenticate(UpdateDictMixin, dict):
|
||||
auth_type = d.pop('__auth_type__', None) or 'basic'
|
||||
return '%s %s' % (auth_type.title(), ', '.join([
|
||||
'%s=%s' % (key, quote_header_value(value,
|
||||
allow_token=key not in self._require_quoting))
|
||||
allow_token=key not in self._require_quoting))
|
||||
for key, value in iteritems(d)
|
||||
]))
|
||||
|
||||
@@ -2412,6 +2490,7 @@ class WWWAuthenticate(UpdateDictMixin, dict):
|
||||
For more information have a look at the sourcecode to see how the
|
||||
regular properties (:attr:`realm` etc.) are implemented.
|
||||
"""
|
||||
|
||||
def _set_value(self, value):
|
||||
if value is None:
|
||||
self.pop(name, None)
|
||||
@@ -2462,6 +2541,7 @@ class WWWAuthenticate(UpdateDictMixin, dict):
|
||||
val = self.get('stale')
|
||||
if val is not None:
|
||||
return val.lower() == 'true'
|
||||
|
||||
def _set_stale(self, value):
|
||||
if value is None:
|
||||
self.pop('stale', None)
|
||||
@@ -2479,6 +2559,7 @@ class WWWAuthenticate(UpdateDictMixin, dict):
|
||||
|
||||
|
||||
class FileStorage(object):
|
||||
|
||||
"""The :class:`FileStorage` class is a thin wrapper over incoming files.
|
||||
It is used by the request object to represent uploaded files. All the
|
||||
attributes of the wrapper stream are proxied by the file storage so
|
||||
@@ -2506,7 +2587,7 @@ class FileStorage(object):
|
||||
# This might not be if the name attribute is bytes due to the
|
||||
# file being opened from the bytes API.
|
||||
if not PY2 and isinstance(filename, bytes):
|
||||
filename = filename.decode(sys.getfilesystemencoding(),
|
||||
filename = filename.decode(get_filesystem_encoding(),
|
||||
'replace')
|
||||
|
||||
self.filename = filename
|
||||
@@ -2535,15 +2616,15 @@ class FileStorage(object):
|
||||
|
||||
@property
|
||||
def mimetype(self):
|
||||
"""Like :attr:`content_type` but without parameters (eg, without
|
||||
charset, type etc.). For example if the content
|
||||
type is ``text/html; charset=utf-8`` the mimetype would be
|
||||
"""Like :attr:`content_type`, but without parameters (eg, without
|
||||
charset, type etc.) and always lowercase. For example if the content
|
||||
type is ``text/HTML; charset=utf-8`` the mimetype would be
|
||||
``'text/html'``.
|
||||
|
||||
.. versionadded:: 0.7
|
||||
"""
|
||||
self._parse_content_type()
|
||||
return self._parsed_content_type[0]
|
||||
return self._parsed_content_type[0].lower()
|
||||
|
||||
@property
|
||||
def mimetype_params(self):
|
||||
@@ -2590,6 +2671,7 @@ class FileStorage(object):
|
||||
|
||||
def __nonzero__(self):
|
||||
return bool(self.filename)
|
||||
__bool__ = __nonzero__
|
||||
|
||||
def __getattr__(self, name):
|
||||
return getattr(self.stream, name)
|
||||
@@ -2607,6 +2689,6 @@ class FileStorage(object):
|
||||
|
||||
# circular dependencies
|
||||
from werkzeug.http import dump_options_header, dump_header, generate_etag, \
|
||||
quote_header_value, parse_set_header, unquote_etag, quote_etag, \
|
||||
parse_options_header, http_date, is_byte_range_valid
|
||||
quote_header_value, parse_set_header, unquote_etag, quote_etag, \
|
||||
parse_options_header, http_date, is_byte_range_valid
|
||||
from werkzeug import exceptions
|
||||
|
||||
Reference in New Issue
Block a user