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

Burak Arslan
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jul 13, 2012
  1. Burak Arslan

    tiny docstring update.

    plq authored
  2. Burak Arslan
  3. Burak Arslan

    docstring tweak

    plq authored
  4. Burak Arslan
  5. Burak Arslan
  6. Burak Arslan

    Implement application registry.

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

    formatting

    plq authored
This page is out of date. Refresh to see the latest.
21 spyne/application.py
View
@@ -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]))
2  spyne/auxproc/_base.py
View
@@ -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
5 spyne/model/_base.py
View
@@ -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)
2  spyne/model/complex.py
View
@@ -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
4 spyne/protocol/soap/soap11.py
View
@@ -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):
6 spyne/protocol/xml/model.py
View
@@ -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:
5 spyne/server/null.py
View
@@ -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__)
69 spyne/util/appreg.py
View
@@ -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.