From 3f3b0a08df7b752ccdec20445339ace5a5439699 Mon Sep 17 00:00:00 2001 From: Christophe de Vienne Date: Thu, 23 Aug 2012 23:22:44 +0200 Subject: [PATCH] New type: FileType. Supports file inputs in forms + documents and demonstrate it in the demo. Should solve issue #4. --- doc/changes.rst | 2 ++ doc/types.rst | 5 +++++ examples/demo/demo.cfg | 7 ------- examples/demo/demo.py | 29 ++++++++++++++++++----------- examples/demo/setup.py | 4 +--- wsme/protocols/commons.py | 10 +++++++++- wsme/types.py | 28 +++++++++++++++++++++++++++- 7 files changed, 62 insertions(+), 23 deletions(-) delete mode 100644 examples/demo/demo.cfg diff --git a/doc/changes.rst b/doc/changes.rst index 2cf0875..68483d1 100644 --- a/doc/changes.rst +++ b/doc/changes.rst @@ -8,6 +8,8 @@ Changes * String types handling is clearer. +* New FileType type. + * Supports cross-referenced types. * Various bugfixes. diff --git a/doc/types.rst b/doc/types.rst index f1ef3db..5c8ecec 100644 --- a/doc/types.rst +++ b/doc/types.rst @@ -50,6 +50,11 @@ The native types are : A time (:py:class:`datetime.time`) + - .. wsme:type:: Filetype + + A file (:py:class:`wsme.types.Filetype`). Currently FileType is + supported only as input type on protocols that accept form inputs. + - Arrays -- This is a special case. When stating a list datatype, always state its content type as the unique element of a list. Example:: diff --git a/examples/demo/demo.cfg b/examples/demo/demo.cfg deleted file mode 100644 index 4fdca0d..0000000 --- a/examples/demo/demo.cfg +++ /dev/null @@ -1,7 +0,0 @@ -[app:main] -paste.app_factory = demo:app_factory - -[server:main] -use = egg:PasteScript#wsgiutils -host = 127.0.0.1 -port = 8989 diff --git a/examples/demo/demo.py b/examples/demo/demo.py index 24ef8ab..dd488fa 100644 --- a/examples/demo/demo.py +++ b/examples/demo/demo.py @@ -8,11 +8,13 @@ To run it:: Then:: - paster serve demo.cfg + python demo.py """ from wsme import WSRoot, expose, validate -from wsme.wsgi import adapt +from wsme.types import FileType + +import bottle from six import u @@ -31,6 +33,11 @@ class DemoRoot(WSRoot): def multiply(self, a, b): return a * b + @expose(unicode) + @validate(FileType) + def echofile(self, afile): + return unicode(afile.value) + @expose(unicode) def helloworld(self): return u"こんにちは世界 (<- Hello World in Japanese !)" @@ -68,17 +75,17 @@ class DemoRoot(WSRoot): return persons -def app_factory(global_config, **local_conf): - root = DemoRoot() +root = DemoRoot(webpath='/ws') - root.addprotocol('soap', - tns='http://example.com/demo', - typenamespace='http://example.com/demo/types', - baseURL='http://127.0.0.1:8989/', - ) +root.addprotocol('soap', + tns='http://example.com/demo', + typenamespace='http://example.com/demo/types', + baseURL='http://127.0.0.1:8989/ws/', +) - root.addprotocol('restjson') +root.addprotocol('restjson') - return adapt(root) +bottle.mount('/ws/', root.wsgiapp()) logging.basicConfig(level=logging.DEBUG) +bottle.run() diff --git a/examples/demo/setup.py b/examples/demo/setup.py index 4ca4a76..b623851 100644 --- a/examples/demo/setup.py +++ b/examples/demo/setup.py @@ -4,9 +4,7 @@ setup(name='demo', install_requires=[ 'WSME', 'WSME-Soap', - 'PasteScript', - 'PasteDeploy', - 'WSGIUtils', + 'Bottle', 'Pygments', ], package=['demo']) diff --git a/wsme/protocols/commons.py b/wsme/protocols/commons.py index 2ed4d7c..d7d912d 100644 --- a/wsme/protocols/commons.py +++ b/wsme/protocols/commons.py @@ -1,10 +1,11 @@ +import cgi import datetime import re from simplegeneric import generic from wsme.types import iscomplex, list_attributes, Unset -from wsme.types import UserType, ArrayType, DictType +from wsme.types import UserType, ArrayType, DictType, FileType from wsme.utils import parse_isodate, parse_isotime, parse_isodatetime @@ -31,6 +32,13 @@ def datetime_from_param(datatype, value): return parse_isodatetime(value) if value else None +@from_param.when_object(FileType) +def filetype_from_param(datatype, value): + if isinstance(value, cgi.FieldStorage): + return FileType(fieldstorage=value) + return FileType(content=value) + + @from_param.when_type(UserType) def usertype_from_param(datatype, value): return datatype.frombasetype( diff --git a/wsme/types.py b/wsme/types.py index b04d91e..81be364 100644 --- a/wsme/types.py +++ b/wsme/types.py @@ -140,6 +140,32 @@ 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): @@ -154,7 +180,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) +extra_types = (binary, decimal.Decimal, FileType) native_types = pod_types + dt_types + extra_types