Skip to content

Commit

Permalink
fix binary support and examples.
Browse files Browse the repository at this point in the history
  • Loading branch information
plq committed Sep 13, 2011
1 parent 85abfc0 commit 80d3274
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 27 deletions.
83 changes: 83 additions & 0 deletions examples/binary_http.py
@@ -0,0 +1,83 @@
#!/usr/bin/env python
# encoding: utf8
#
# rpclib - Copyright (C) Rpclib contributors
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
#

import os
import logging

from tempfile import mkstemp

from rpclib.application import Application
from rpclib.decorator import srpc
from rpclib.interface.wsdl import Wsdl11
from rpclib.model.binary import Attachment
from rpclib.model.fault import Fault
from rpclib.model.primitive import String
from rpclib.protocol.http import HttpRpc
from rpclib.service import ServiceBase
from rpclib.server.wsgi import WsgiApplication

class DocumentArchiver(ServiceBase):
@srpc(Attachment, _returns=String)
def put(document):
'''This method accepts an Attachment object, and returns
the filename of the archived file
'''
fd, fname = mkstemp()
os.close(fd)

document.file_name = fname
document.save_to_file()

return fname

@srpc(String, _returns=Attachment)
def get(file_path):
'''This method loads a document from the specified file path
and returns it. If the path isn't found, an exception is
raised.
'''

if not os.path.exists(file_path):
raise Fault("Client.FileName", "File '%s' not found" % file_path)

document = Attachment(file_name=file_path)
# the service automatically loads the data from the file.
# alternatively, The data could be manually loaded into memory
# and loaded into the Attachment like:
# document = Attachment(data=data_from_file)
return document

if __name__=='__main__':
try:
from wsgiref.simple_server import make_server
except ImportError:
print "Error: example server code requires Python >= 2.5"

application = Application([DocumentArchiver], 'rpclib.examples.binary',
interface=Wsdl11(), in_protocol=HttpRpc(), out_protocol=HttpRpc())

logging.basicConfig(level=logging.DEBUG)
logging.getLogger('rpclib.protocol.soap.soap11').setLevel(logging.DEBUG)

server = make_server('127.0.0.1', 7789, WsgiApplication(application))
print "listening to http://127.0.0.1:7789"
print "wsdl is at: http://localhost:7789/?wsdl"

server.serve_forever()
18 changes: 11 additions & 7 deletions examples/binary.py → examples/binary_soap.py
Expand Up @@ -19,21 +19,23 @@
#

import os
import logging

from tempfile import mkstemp

from rpclib.application import Application
from rpclib.decorator import srpc
from rpclib.interface.wsdl import Wsdl11
from rpclib.model.binary import Attachment
from rpclib.model.fault import Fault
from rpclib.model.primitive import String
from rpclib.protocol.soap import Soap11
from rpclib.service import ServiceBase
from rpclib.model.primitive import String
from rpclib.model.binary import Attachment
from rpclib.server.wsgi import WsgiApplication

class DocumentArchiver(ServiceBase):
@srpc(Attachment, _returns=String)
def archive_document(document):
def put(document):
'''This method accepts an Attachment object, and returns
the filename of the archived file
'''
Expand All @@ -46,14 +48,14 @@ def archive_document(document):
return fname

@srpc(String, _returns=Attachment)
def get_archived_document(file_path):
def get(file_path):
'''This method loads a document from the specified file path
and returns it. If the path isn't found, an exception is
and returns it. If the path isn't found, an exception is
raised.
'''

if not os.path.exists(file_path):
raise Exception("File [%s] not found"%file_path)
raise Fault("Client.FileName", "File '%s' not found" % file_path)

document = Attachment(file_name=file_path)
# the service automatically loads the data from the file.
Expand All @@ -71,8 +73,10 @@ def get_archived_document(file_path):
application = Application([DocumentArchiver], 'rpclib.examples.binary',
interface=Wsdl11(), in_protocol=Soap11(), out_protocol=Soap11())

server = make_server('127.0.0.1', 7789, WsgiApplication(application))
logging.basicConfig(level=logging.DEBUG)
logging.getLogger('rpclib.protocol.soap.soap11').setLevel(logging.DEBUG)

server = make_server('127.0.0.1', 7789, WsgiApplication(application))
print "listening to http://127.0.0.1:7789"
print "wsdl is at: http://localhost:7789/?wsdl"

Expand Down
41 changes: 32 additions & 9 deletions src/rpclib/model/binary.py
Expand Up @@ -70,21 +70,44 @@ def to_string(cls, value):
if not (value.data is None):
# the data has already been loaded, just encode
# and return the element
return value.data
data = value.data

elif not (value.file_name is None):
# the data hasn't been loaded, but a file has been
# specified
data_string = StringIO()

file_name = value.file_name
file = open(file_name, 'rb')
base64.encode(file, data_string)
file.close()
data = open(value.file_name, 'rb').read()

# go back to the begining of the data
data_string.seek(0)
return data_string.read()
else:
raise Exception("Neither data nor a file_name has been specified")

return data

@classmethod
@nillable_string
def to_base64(cls, value):
ostream = StringIO()
if not (value.data is None):
istream = StringIO(value.data)

elif not (value.file_name is None):
istream = open(value.file_name, 'rb')

else:
raise Exception("Neither data nor a file_name has been specified")

base64.encode(istream, ostream)
ostream.seek(0)

return ostream.read()

@classmethod
@nillable_string
def from_base64(cls, value):
istream = StringIO(value)
ostream = StringIO()

base64.decode(istream, ostream)
ostream.seek(0)

return Attachment(data=ostream.read())
5 changes: 5 additions & 0 deletions src/rpclib/protocol/xml/_base.py
Expand Up @@ -29,6 +29,7 @@
from rpclib.error import NotFoundError
from rpclib.model import ModelBase

from rpclib.model.binary import Attachment
from rpclib.model.complex import Array
from rpclib.model.complex import Iterable
from rpclib.model.complex import ComplexModelBase
Expand All @@ -42,6 +43,7 @@
from rpclib.protocol import ProtocolBase

from rpclib.protocol.xml.model import base_to_parent_element
from rpclib.protocol.xml.model.binary import binary_to_parent_element
from rpclib.protocol.xml.model.enum import enum_to_parent_element
from rpclib.protocol.xml.model.fault import fault_to_parent_element
from rpclib.protocol.xml.model.complex import complex_to_parent_element
Expand All @@ -51,6 +53,7 @@
from rpclib.protocol.xml.model.primitive import duration_to_parent_element

from rpclib.protocol.xml.model import base_from_element
from rpclib.protocol.xml.model.binary import binary_from_element
from rpclib.protocol.xml.model.complex import array_from_element
from rpclib.protocol.xml.model.complex import iterable_from_element
from rpclib.protocol.xml.model.complex import complex_from_element
Expand All @@ -62,6 +65,7 @@

_serialization_handlers = cdict({
ModelBase: base_to_parent_element,
Attachment: binary_to_parent_element,
ComplexModelBase: complex_to_parent_element,
Fault: fault_to_parent_element,
String: string_to_parent_element,
Expand All @@ -73,6 +77,7 @@

_deserialization_handlers = cdict({
ModelBase: base_from_element,
Attachment: binary_from_element,
ComplexModelBase: complex_from_element,
Fault: fault_from_element,
String: string_from_element,
Expand Down
17 changes: 6 additions & 11 deletions src/rpclib/protocol/xml/model/binary.py
Expand Up @@ -24,28 +24,23 @@

from lxml import etree

from rpclib.model.binary import Attachment

from _base import nillable_value
from _base import nillable_element


@nillable_value
def to_parent_element(cls, value, tns, parent_elt, name='retval'):
def binary_to_parent_element(prot, cls, value, tns, parent_elt, name='retval'):
'''This class method takes the data from the attachment and
base64 encodes it as the text of an Element. An attachment can
specify a file_name and if no data is given, it will read the data
from the file
'''

element = etree.SubElement(parent_elt, '{%s}%s' % (tns,name))
element.text = base64.encodestring(cls.to_string(value))
element = etree.SubElement(parent_elt, "{%s}%s" % (tns,name))
element.text = cls.to_base64(value)

@nillable_element
def from_xml(cls, element):
def binary_from_element(prot, cls, element):
'''This method returns an Attachment object that contains
the base64 decoded string of the text of the given element
'''
data = base64.decodestring(element.text)
a = Attachment(data=data)
return a

return cls.from_base64(element.text)

0 comments on commit 80d3274

Please sign in to comment.