Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Application Registry and misc. fixes #157

Merged
merged 7 commits into from

1 participant

Commits on Jul 13, 2012
  1. @plq

    tiny docstring update.

    plq authored
  2. @plq
  3. @plq

    docstring tweak

    plq authored
  4. @plq
  5. @plq
  6. @plq

    Implement application registry.

    plq authored
    It can get useful for calling exposed functions from within the application.
Commits on Jul 15, 2012
  1. @plq

    formatting

    plq authored
This page is out of date. Refresh to see the latest.
View
21 spyne/application.py
@@ -28,6 +28,7 @@
from spyne.model.fault import Fault
from spyne.interface import Interface
from spyne._base import EventManager
+from spyne.util.appreg import register_application
class Application(object):
@@ -38,14 +39,14 @@ class Application(object):
the exposed services.
:param tns: The targetNamespace attribute of the exposed
service.
- :param interface: Ignored.
- :param in_protocol: A ProtocolBase instance that defines the input
- protocol.
- :param out_protocol: A ProtocolBase instance that defines the output
- protocol.
:param name: The optional name attribute of the exposed service.
The default is the name of the application class
which is, by default, 'Application'.
+ :param in_protocol: A ProtocolBase instance that defines the input
+ protocol. It's only optional for NullServer transport.
+ :param out_protocol: A ProtocolBase instance that defines the output
+ protocol. It's only optional for NullServer transport.
+ :param interface: Ignored. Kept for backwards-compatibility purposes.
Supported events:
* method_call:
@@ -67,9 +68,8 @@ class Application(object):
transport = None
- def __init__(self, services, tns, in_protocol, out_protocol, interface=None,
- name=None):
-
+ def __init__(self, services, tns, name=None,
+ in_protocol=None, out_protocol=None, interface=None):
self.services = services
self.tns = tns
self.name = name
@@ -77,6 +77,8 @@ def __init__(self, services, tns, in_protocol, out_protocol, interface=None,
if self.name is None:
self.name = self.__class__.__name__.split('.')[-1]
+ register_application(self)
+
self.event_manager = EventManager(self)
self.error_handler = None
@@ -162,3 +164,6 @@ def reinitialize(self):
if d.aux is not None and not id(d.aux) in aux_memo:
d.aux.initialize(server)
aux_memo.add(id(d.aux))
+
+ def __hash__(self):
+ return hash(tuple([id(s) for s in self.services]))
View
2  spyne/auxproc/_base.py
@@ -32,7 +32,7 @@
execution methods like persistent or non-persistent queueing, async execution
in another thread, process or node.
-Auxprocs define how an auxiliary method is going to be executed.
+AuxProcs define how an auxiliary method is going to be executed.
"""
import logging
View
5 spyne/model/_base.py
@@ -19,6 +19,7 @@
import spyne.const.xml_ns
+from decimal import Decimal
"""This module contains the ModelBase class and other building blocks for
defining models.
@@ -217,7 +218,7 @@ def customize(cls, **kwargs):
return type(cls_name, cls_bases, cls_dict)
@staticmethod
- def _s_customize(cls, ** kwargs):
+ def _s_customize(cls, **kwargs):
"""This function duplicates and customizes the class it belongs to. The
original class remains unchanged.
@@ -238,6 +239,8 @@ class Annotations(cls.Annotations):
for k, v in kwargs.items():
if k in ("doc", "appinfo"):
setattr(Annotations, k, v)
+ elif k == 'max_occurs' and v == 'unbounded':
+ setattr(Attributes, k, Decimal('inf'))
else:
setattr(Attributes, k, v)
View
2  spyne/model/complex.py
@@ -427,7 +427,7 @@ class Array(ComplexModel):
the same name as the serialized class. It's contained in a Python list.
"""
- def __new__(cls, serializer, ** kwargs):
+ def __new__(cls, serializer, **kwargs):
retval = cls.customize(**kwargs)
# hack to default to unbounded arrays when the user didn't specify
View
4 spyne/protocol/soap/soap11.py
@@ -326,6 +326,9 @@ def serialize(self, ctx, message):
ctx.out_document.append(ctx.out_body_doc)
+ if self.cleanup_namespaces:
+ etree.cleanup_namespaces(ctx.out_document)
+
if self.log_messages:
if message is self.REQUEST:
line_header = '%sRequest%s' % (LIGHT_GREEN, END_COLOR)
@@ -333,6 +336,7 @@ def serialize(self, ctx, message):
line_header = '%sResponse%s' % (LIGHT_RED, END_COLOR)
logger.debug('%s %s' % (line_header, etree.tostring(ctx.out_document,
xml_declaration=True, pretty_print=True)))
+
self.event_manager.fire_event('after_serialize', ctx)
def fault_to_http_response_code(self, fault):
View
6 spyne/protocol/xml/model.py
@@ -135,6 +135,9 @@ def get_members_etree(prot, cls, inst, parent):
except: # to guard against sqlalchemy throwing NoSuchColumnError
subvalue = None
+ # This is a tight loop, so enable this only when necessary.
+ logger.debug("get %r(%r) from %r: %r" % (k, v, inst, subvalue))
+
if issubclass(v, XmlAttribute):
v.marshall(k, subvalue, parent)
continue
@@ -259,7 +262,8 @@ def enum_from_element(prot, cls, element):
def fault_to_parent_element(prot, cls, value, tns, parent_elt, name=None):
element = etree.SubElement(parent_elt, "{%s}Fault" % _ns_soap_env)
- etree.SubElement(element, 'faultcode').text = '%s:%s' % (_pref_soap_env, value.faultcode)
+ etree.SubElement(element, 'faultcode').text = '%s:%s' % (_pref_soap_env,
+ value.faultcode)
etree.SubElement(element, 'faultstring').text = value.faultstring
etree.SubElement(element, 'faultactor').text = value.faultactor
if value.detail != None:
View
5 spyne/server/null.py
@@ -17,7 +17,10 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
#
-"""This module contains the NullServer class and its helper objects."""
+"""This module contains the NullServer class and its helper objects.
+
+The name comes from the "null modem connection". Look it up.
+"""
import logging
logger = logging.getLogger(__name__)
View
69 spyne/util/appreg.py
@@ -0,0 +1,69 @@
+
+#
+# spyne - Copyright (C) Spyne 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
+#
+
+"""
+Module that contains the Spyne Application Registry.
+"""
+
+import logging
+logger = logging.getLogger(__name__)
+
+_applications = {}
+
+from collections import namedtuple
+
+_ApplicationMetaData = namedtuple("_ApplicationMetaData",
+ ['app', 'inst_stack', 'null'])
+
+def register_application(app):
+ """Registers application in the registration was successful and False otherwise.
+ """
+
+ key = (app.tns, app.name)
+
+ from spyne.server.null import NullServer
+
+ try:
+ import traceback
+ stack = traceback.format_stack()
+ except ImportError:
+ stack = None
+
+ prev = _applications.get(key, None)
+
+ if prev is not None:
+ if hash(prev.app) == hash(app):
+ logger.debug("Application %r previously registered as %r is the same"
+ " as %r. Skipping." % (prev.app, key, app))
+ prev.inst_stack.append(stack)
+ else:
+ logger.warning("Overwriting application %r(%r)." % (key, app))
+
+ if prev.inst_stack is not None:
+ logger.debug("Stack trace of the instantiation:\n%s" %
+ ''.join(prev.inst_stack))
+
+ _applications[key] = _ApplicationMetaData(app=app, inst_stack=[stack],
+ null=NullServer(app))
+
+ logger.debug("Registering %r as %r" % (app, key))
+
+
+def get_application(tns, name):
+ return _applications.get((tns, name), None)
Something went wrong with that request. Please try again.