diff --git a/examples/demo/demo.py b/examples/demo/demo.py index dd488fa..9a2f4dc 100644 --- a/examples/demo/demo.py +++ b/examples/demo/demo.py @@ -12,7 +12,7 @@ Then:: """ from wsme import WSRoot, expose, validate -from wsme.types import FileType +from wsme.types import File import bottle @@ -33,10 +33,10 @@ class DemoRoot(WSRoot): def multiply(self, a, b): return a * b - @expose(unicode) - @validate(FileType) + @expose(File) + @validate(File) def echofile(self, afile): - return unicode(afile.value) + return afile @expose(unicode) def helloworld(self): diff --git a/wsme/protocols/commons.py b/wsme/protocols/commons.py index d7d912d..9dfcc81 100644 --- a/wsme/protocols/commons.py +++ b/wsme/protocols/commons.py @@ -5,7 +5,7 @@ import re from simplegeneric import generic from wsme.types import iscomplex, list_attributes, Unset -from wsme.types import UserType, ArrayType, DictType, FileType +from wsme.types import UserType, ArrayType, DictType, File from wsme.utils import parse_isodate, parse_isotime, parse_isodatetime @@ -32,11 +32,11 @@ def datetime_from_param(datatype, value): return parse_isodatetime(value) if value else None -@from_param.when_object(FileType) +@from_param.when_object(File) def filetype_from_param(datatype, value): if isinstance(value, cgi.FieldStorage): - return FileType(fieldstorage=value) - return FileType(content=value) + return File(fieldstorage=value) + return File(content=value) @from_param.when_type(UserType) @@ -47,7 +47,7 @@ def usertype_from_param(datatype, value): @generic def from_params(datatype, params, path, hit_paths): - if iscomplex(datatype): + if iscomplex(datatype) and datatype is not File: objfound = False for key in params: if key.startswith(path + '.'): diff --git a/wsme/types.py b/wsme/types.py index 81be364..a131040 100644 --- a/wsme/types.py +++ b/wsme/types.py @@ -1,4 +1,5 @@ import base64 +import cStringIO as StringIO import datetime import decimal import inspect @@ -140,32 +141,6 @@ class Enum(UserType): return value -class FileType(object): - def __init__(self, filename=None, file=None, content=None, - contenttype=None, fieldstorage=None): - self.filename = filename - self._file = file - self._content = content - self.contenttype = contenttype - if fieldstorage is not None: - if fieldstorage.file: - self._file = fieldstorage.file - self.filename = fieldstorage.filename - self.contenttype = fieldstorage.type - else: - self._content = fieldstorage.value - - @property - def file(self): - return self._file - - @property - def value(self): - if self._content is None and self._file: - self._content = self._file.read() - return self._content - - class UnsetType(object): if sys.version < '3': def __nonzero__(self): @@ -180,7 +155,7 @@ Unset = UnsetType() pod_types = six.integer_types + ( bytes, text, float, bool) dt_types = (datetime.date, datetime.time, datetime.datetime) -extra_types = (binary, decimal.Decimal, FileType) +extra_types = (binary, decimal.Decimal) native_types = pod_types + dt_types + extra_types @@ -523,3 +498,45 @@ def Base__init__(self, **kw): setattr(self, key, value) Base = BaseMeta('Base', (object, ), {'__init__': Base__init__}) + + +class File(Base): + """A complex type that represents a file. + + In the particular case of protocol accepting form encoded data as + input, File can be loaded from a form file field. + """ + filename = wsattr(text) + contenttype = wsattr(text) + + def _get_content(self): + if self._content is None and self._file: + self._content = self._file.read() + return self._content + + def _set_content(self, value): + self._content = value + self._file = None + + content = wsproperty(binary, _get_content, _set_content) + + def __init__(self, filename=None, file=None, content=None, + contenttype=None, fieldstorage=None): + self.filename = filename + self.contenttype = contenttype + self._file = file + self._content = content + + if fieldstorage is not None: + if fieldstorage.file: + self._file = fieldstorage.file + self.filename = fieldstorage.filename + self.contenttype = unicode(fieldstorage.type) + else: + self._content = fieldstorage.value + + @property + def file(self): + if self._file is None and self._content: + self._file = StringIO.StringIO(self._content) + return self._file