A transport agnostic sync/async RPC library that focuses on exposing services with a well-defined API using popular protocols.

Overview

WARNING: This is from spyne's development branch. This version is not released yet! Latest stable release can be found in the 2_13 branch.

If you like and use Spyne, star it on Github!

About

Spyne aims to save the protocol implementers the hassle of implementing their own remote procedure call api and the application programmers the hassle of jumping through hoops just to expose their services using multiple protocols and transports.

In other words, Spyne is a framework for building distributed solutions that strictly follow the MVC pattern, where Model = spyne.model, View = spyne.protocol and Controller = user code.

Spyne comes with the implementations of popular transport, protocol and interface document standards along with a well-defined API that lets you build on existing functionality.

The following are the primary sources of information about spyne:

Requirements

Spyne source distribution is a collection of highly decoupled components, which makes it a bit difficult to put a simple list of requirements, as literally everything except pytz is optional.

Python version

Spyne 2.13 supports Python 2.7, 3.6, 3.7 and 3.8.

Libraries

Additionally the following software packages are needed for various subsystems of Spyne:

  • A Wsgi server of your choice is needed to wrap spyne.server.wsgi.WsgiApplication
  • lxml>=3.2.5 is needed for any xml-related protocol.
  • lxml>=3.4.1 is needed for any html-related protocol.
  • SQLAlchemy is needed for spyne.model.complex.TTableModel.
  • pyzmq is needed for spyne.client.zeromq.ZeroMQClient and spyne.server.zeromq.ZeroMQServer.
  • Werkzeug is needed for using spyne.protocol.http.HttpRpc under a wsgi transport.
  • PyParsing is needed for using HttpPattern's with spyne.protocol.http.HttpRpc.
  • Twisted is needed for anything in spyne.server.twisted and spyne.client.twisted.
  • Django (tested with 1.8 and up) is needed for anything in spyne.server.django.
  • Pyramid is needed for spyne.server.pyramid.PyramidApplication.
  • msgpack>=1.0.0 is needed for spyne.protocol.msgpack.
  • PyYaml is needed for spyne.protocol.yaml.
  • simplejson is used when found for spyne.protocol.json.

You are advised to add these as requirements to your own projects, as these are only optional dependencies of Spyne, thus not handled in its setup script.

Installing

You first need to have package manager (pip, easy_install) installed. Spyne ships with a setuptools bootstrapper, so if setup.py refuses to run because it can't find setuptools, do:

bin/distribute_setup.py

You can add append --user to get it installed with $HOME/.local as prefix.

You can get spyne via pypi:

easy_install [--user] spyne

or you can clone the latest master tree from Github:

git clone git://github.com/arskom/spyne.git

To install from source distribution, you can run the setup script as usual:

python setup.py install [--user]

If you want to make any changes to the Spyne code, just use

python setup.py develop [--user]

so that you can painlessly test your patches.

Finally, to run the tests, you need to first install every single library that Spyne integrates with, along with additional packages like pytest or tox that are only needed when running Spyne testsuite. An up-to-date list is maintained in the requirements/ directory, in separate files for both Python 2.7 and >=3.6. To install everything, run:

pip install [--user] -r requirements/test_requirements.txt

If you are still stuck on Python 2.x however, you should use:

pip install [--user] -r requirements/test_requirements_py27.txt

Assuming all dependencies are installed without any issues, the following command will run the whole test suite:

python setup.py test

Spyne's test harness has evolved a lot in the 10+ years the project has been active. It has 3 main stages: Traditional unit tests, tests that perform end-to-end testing by starting actual daemons that listen on real TCP sockets on hard-coded ports, and finally Django tests that are managed by tox. Naively running pytest etc in the root directory will fail as their auto-discovery mechanism was not implemented with Spyne's requirements in mind.

Getting Support

Official support channels are as follows:

Please don't use the issue tracker for asking questions. It's a database that holds the most important information for the project, so we must avoid cluttering it as much as possible.

Contributing

If you feel like helping out, see the CONTRIBUTING.rst file in the Spyne source distribution for starting points and general guidelines.

Comments
  • Value error __class__ is not in list during spyne import

    Value error __class__ is not in list during spyne import

    Hello,

    I had a working SOAP service working under Django 1.7 / Python 2.7 / Spyne 2.11. I am migrating my full application to Python 3.4 and as far as I understand, XML related features should work on Py3.

    The application crashes during the import of DjangoView when processing the request (Django starts ok)

    • Exception returned is Value error __class__ is not in list.
    • Exception location is spyne\util\odict.py in __delitem__, line 68

    The code in odict.py:

        def __delitem__(self, key):
            if not isinstance(key, int):
                key = self.__list.index(key) # ouch.
    

    My urls.py:

        from django.conf.urls import patterns, url
        from spyne.server.django import DjangoView
        from soap.views import app
    
        urlpatterns = patterns(
            '',
            url(r'^test/', DjangoView.as_view(application=app), name='test-service'),
        )
    

    Any idea on this ? I really appreciate Spyne and would not like to have to seek a new SOAP framework or reimplement everything manually.

    Defect 
    opened by penoux 40
  • Default value for nillable violates XMLSchema

    Default value for nillable violates XMLSchema

    Why does nillable attribute is True by default? According to XMLSchema, elements aren't nillable by default. Database columns aren't null by default.

    Do you think it's good idea to make it configurable?

    Invalid 
    opened by DXist 39
  • Schema parser struggles with additional namespaces

    Schema parser struggles with additional namespaces

    The Office OpenXML schemas are spread out across multiple files. parse_schema_file seems to struggle with the various namespaces in use. It also struggles with the encoding declaration of the file which is weird, because lxml doesn't when I read it. I wonder if that's because it's using fromstring(file.read()) rather than parse(file, parser)?

    schema = parse_schema_file("openpyxl/tests/schemas/sml.xsd")
    Traceback (most recent call last):
      File "/Applications/WingIDE.app/Contents/Resources/src/debug/tserver/_sandbox.py", line 1, in <module>
        # Used internally for debug sandbox under external interpreter
      File "/Users/charlieclark/Projects/openpyxl/lib/python3.4/site-packages/spyne/util/xml.py", line 153, in parse_schema_file
        .parse_schema(elt)
      File "/Users/charlieclark/Projects/openpyxl/lib/python3.4/site-packages/spyne/interface/xml_schema/parser.py", line 545, in parse_schema
        file_name = self.files[imp.namespace]
    builtins.KeyError: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'
    
    Defect 
    opened by Themanwithoutaplan 33
  • Programmer control of sequence declaration in WSDL

    Programmer control of sequence declaration in WSDL

    I have been bitten once again by me changing something apparently innocuous in my type definitions (adding a nillable I think), and then breaking every client that generates compiled code from the WSDL. (This means just about everyone who doesn't use python-suds).

    We have discussed before: https://github.com/arskom/spyne/issues/233#issuecomment-18737172

    So, here is a patch that fixes it - at the expense of breaking all existing servers in this way one final time, of course.

    The patch works by automagically assigning every subclass of ModelBase a unique number called declare_order. The number is incremented each time a new subclass is created.

    ComplexModelBase inserts fields into _type_info in ascending order of declare_order. The WSDL already generated it's sequence in the order things were put into _type_info, so if you create a new type for every field in a ComplexModel like this:

    class MyStruct(ComplexModel):
      y = Unicode()
      x = Double()
    

    Then the WSDL generated by Spyne will match the declared order of the fields in Python (ie y will be declared then x) - like just about every other SOAP implementation on the planet.

    If you don't generate new types then the fallback is to use the names. So in this case in the WSDL x would be declared before y, because that is the sort order of the names. Not perfect, but it will be stable across revisions of Spyne, and python.

    opened by rstuart 33
  • Test mandatory input elements validation

    Test mandatory input elements validation

    test_mandatory_element_attributes fails

    UPDATE This pull request was initiates to solve this question http://stackoverflow.com/questions/19514045/how-to-describe-element-attributes-with-spyne/19519355

    opened by satyrius 22
  • Django with Python 3.4 WSDL is wrong type (bytes, not string)

    Django with Python 3.4 WSDL is wrong type (bytes, not string)

    With Django 1.6.5 and Python 3.4.1 attempting to generate WSDL results in the following error:

    sequence item 0: expected str instance, bytes found

    The reason for this is that xml.etree.tostring() returns a bytes object, not a string object unless you specify the encoding as "unicode". Since the encoding is specified as UTF-8 a bytes object is returned. Django expects responses to be strings, not bytes objects.

    Adding the line

    self.__wsdl = self.__wsdl.decode("utf-8")

    at the end of the build_interface_document() method in interface/wsdl/wsdl11.py resolves the issue. I'm not sure if this is a desirable solution, however.

    opened by anthony-tuininga 18
  • Feature/transparent declared for python2

    Feature/transparent declared for python2

    This is an attempt to implement ordered class attributes for Python 2.

    See https://github.com/arskom/spyne/pull/313 for solution that requires class customization.

    For statically defined classes there is inspect magic, that tries to find class code object.

    Those users who create classes dynamically have to specify class attributes as odict instance.

    opened by DXist 18
  • Feature/django mapper

    Feature/django mapper

    This pull request provides initial support for mapping Django models to spyne complex types.

    Revised version of https://github.com/arskom/spyne/pull/269

    opened by DXist 18
  • Fix collections.abc imports

    Fix collections.abc imports

    • Abstract base classes are no longer exposed in the top-level collections module in Python 3.9: https://docs.python.org/3.9/whatsnew/3.9.html#removed
    • Consolidate docstrings in util.oset.new
    • Remove unnecessary list call in util.oset.new

    Attempt to fix these warnings:

    /app/venv/lib/python3.8/site-packages/spyne/util/oset/new.py:10: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated since Python 3.3, and in 3.9 it will stop working
      class oset(collections.MutableSet):
    /app/venv/lib/python3.8/site-packages/spyne/protocol/dictdoc/hier.py:29: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated since Python 3.3, and in 3.9 it will stop working
      from collections import defaultdict, Iterable as AbcIterable
    
    opened by antonagestam 17
  • Invalid output conversion

    Invalid output conversion

    rpclib is doing invalid output conversion of floats - if your function is supposed to return float and you will return string, value in XML is invalid (see that quotes):

    <tns:testfResult>'1.1'</tns:testfResult>
    

    server example:

    import logging
    
    from rpclib.application import Application
    from rpclib.decorator import srpc
    from rpclib.decorator import rpc
    from rpclib.interface.wsdl import Wsdl11
    from rpclib.protocol.soap import Soap11
    from rpclib.service import ServiceBase
    from rpclib.model.primitive import Integer
    from rpclib.model.primitive import String
    from rpclib.model.primitive import Float
    from rpclib.model.complex import Array
    from rpclib.model.complex import ComplexModel
    from rpclib.server.wsgi import WsgiApplication
    
    class tests(ServiceBase):
    
      @rpc(_returns=Float)
      def testf(ctx):
        return "1.1"
    
    if __name__ == '__main__':
      from wsgiref.simple_server import make_server
    
      logging.basicConfig(level=logging.DEBUG)
      logging.getLogger('rpclib.protocol.xml').setLevel(logging.DEBUG)
    
      application = Application([tests], 'tests', interface=Wsdl11(), in_protocol=Soap11(validator="soft"), out_protocol=Soap11())
    
      host = "127.0.0.1"
      port = 8080
    
      server = make_server(host, port, WsgiApplication(application))
    
      print "listening to http://%s:%s" % (host, port)
      print "wsdl is at: http://%s:%s/?wsdl" % (host, port)
    
      server.serve_forever()
    
    Invalid 
    opened by azurit 17
  • soap:address is duplicated

    soap:address is duplicated

    I use python3.7 and spyne 2.13.10 (build from source)

    I set up services as the Application takes many services on registration.

    def create_spyne_app():
        from spyne import ServiceBase
        from .controllers import soap
    
        services = set()
        for module in _import_submodules_from_package(soap):
            for name, service in inspect.getmembers(module, lambda x: inspect.isclass(x) and issubclass(x, ServiceBase)):
                if service is not ServiceBase:
                    services.add(service)
    
        print(services)
        # from soap to soap protocol
        return WsgiApplication(
                   Application(services,
                       tns='spyne.example.flask',
                       in_protocol=Soap11(validator='lxml'),
                       out_protocol=Soap11()
               ))
    
    ...
    
    # init with flask
    
        app.wsgi_app = DispatcherMiddleware(app.wsgi_app, {
            "/LeapServiceWS/services": create_spyne_app(),
            })
    
    

    Then I access to http://localhost:5000/LeapServiceWS/services/?wsdl I got <wsdlsoap11:address location="http://localhost:5000/LeapServiceWS/services/HelloWorldService/"/> duplicated in each service tag

    ...
    <wsdl:service name="CustomerAccountListInq">
    <wsdl:port name="Application" binding="tns:Application">
    <wsdlsoap11:address location="http://localhost:5000/LeapServiceWS/services/HelloWorldService/"/>
    </wsdl:port>
    </wsdl:service>
    <wsdl:service name="HelloWorldService">
    <wsdl:port name="Application" binding="tns:Application">
    <wsdlsoap11:address location="http://localhost:5000/LeapServiceWS/services/HelloWorldService/"/>
    </wsdl:port>
    </wsdl:service>
    ..
    

    then I went to http://localhost:5000/LeapServiceWS/services/HelloWordService/?wsdl which specific service and I got another service description also.

    ...
    <wsdl:service name="CustomerAccountListInq">
    <wsdl:port name="Application" binding="tns:Application">
    <wsdlsoap11:address location="http://localhost:5000/LeapServiceWS/services/HelloWordService/"/>
    </wsdl:port>
    </wsdl:service>
    <wsdl:service name="HelloWorldService">
    <wsdl:port name="Application" binding="tns:Application">
    <wsdlsoap11:address location="http://localhost:5000/LeapServiceWS/services/HelloWordService/"/>
    </wsdl:port>
    </wsdl:service>
    ...
    

    so I am not sure this is expected behavior of Soap ? not sure how to solve or I need to register with different wsgi app ?

    Invalid 
    opened by jingz 16
  • First draft to show how to make syntactically nicer with type annotations

    First draft to show how to make syntactically nicer with type annotations

    Just the initial example - dont want to go too far down the rabbit hole if there's no appetite. Open to thoughts

    Example

    class HelloWorldService(ServiceBase):
        @typed_rpc
        def say_hello(
            self,
            name: Unicode,
            times: UnsignedInteger32,
            a: Iterable(Decimal),
            b: Iterable(Iterable(Decimal)),
        ) -> Iterable(Unicode):
            for _ in range(times):
                yield f"Hello, {name}"
    

    Example 2

    class HelloWorldService(ServiceBase):
        @typed_rpc(_is_async=True)
        def say_hello(
            self,
            name: Unicode,
            times: UnsignedInteger32,
            a: Iterable(Decimal),
            b: Iterable(Iterable(Decimal)),
        ) -> Iterable(Unicode):
            for _ in range(times):
                yield f"Hello, {name}"
    
    Enhancement 
    opened by ghandic 2
  • Bugfix/return client errors

    Bugfix/return client errors

    Handle 2 cases where bad client data cause a 500 Internal Server Error, rather than the nicer soap11env:Client.XMLSyntaxError.

    Case 1: Client does not send body in its request. This causes an empty generator to be passed to _parse_xml_string, which causes an unhandled StopIteration exception.

    Case 2: Client sends badly encoded data in its request. This causes a badly encoded byte string to be passed to _parse_xml_string, which causes a UnicodeDecodeError when we try to decode it.

    opened by sashawood 1
  • add GitHub URL for PyPi

    add GitHub URL for PyPi

    opened by andriyor 1
  • only old docs available

    only old docs available

    Please update the documentation for 2.13 The link to documentation http://spyne.io/docs/ only gives docs for 2.10 and incomplete docs for 2.13.

    What is needed to update those for the latest release?

    Documentation 
    opened by maurerle 1
Releases(spyne-2.14.0)
TicTacToe using Socket Server

TicTacToe using Socket Server This is a project for the class : 18CSC302J - Computer Networks by Dr. S.Babu Contributors Suvodeep Sinha RA191100301010

Suvodeep Sinha 12 Nov 30, 2022
ServerStatus with node management and monitor

ServerStatus with node management and monitor

lidalao 162 Jan 01, 2023
Process incoming JSON-RPC requests in Python

August 16, 2021: Version 5 has been released. Read about the changes in version 5, or read the full documentation. Version 5 is for Python 3.8+ only.

Exploding Labs 156 Dec 31, 2022
Truetool - A TrueCharts automatic and bulk update utility

truetool A easy tool for frequently used TrueNAS SCALE CLI utilities. Previously

TrueCharts 125 Jan 04, 2023
Proxlist - Retrieve proxy servers.

Finding and storing a list of proxies can be taxing - especially ones that are free and may not work only minutes from now. proxlist will validate the proxy and return a rotating random proxy to you

Justin Hammond 2 Mar 17, 2022
Home Assistant integration for MyEnergi devices

myenergi for Home Assistant myenergi custom component for Home Assistant This is a very early release, will add more documentations soon! This compone

Johan Isacsson 70 Dec 18, 2022
Multiple-requests-poster - A tool to send multiple requests to a particular website written in Python

Multiple-requests-poster - A tool to send multiple requests to a particular website written in Python

RLX 2 Feb 14, 2022
Fmog: Fortinet Mass Object Generator. This script will take a list of IP addresses and create address objects with the same name

Fmog: Fortinet Mass Object Generator This script will take a list of IP addresses and create address objects with the same name. It will also add them

2 Oct 26, 2021
Real-time text-editor using python tcp socket

Real-time text-editor using python tcp socket This project does not need any external libraries so you don't need to use virtual environments. All you

MatiYo 3 Aug 05, 2022
An improved version of the original AutoDD

AutoDD = Automatically does the "due diligence" for you. If you want to know what stocks people are talking about on reddit, this little program might help you.

Steven Zhu 169 Oct 05, 2022
Query protocol and response

whois Query protocol and response _MᵃˢᵗᵉʳBᵘʳⁿᵗ_ _ ( ) _ ( )( ) _ | | ( ) | || |__ _ (_) ___ | | | | | || _ `\ /'_`\ | |/',__) |

MasterBurnt 4 Sep 05, 2021
Tool written on Python that locate all up host on your subnet

HOSTSCAN Easy to use command line network host scanner. From noob to noobs. Dependencies Nmap 7.92 or superior Python 3.9 or superior All requirements

NexCreep 4 Feb 27, 2022
A Scapy implementation of SMS-SUBMIT and (U)SIM Application Toolkit command packets.

A Scapy implementation of SMS-SUBMIT and (U)SIM Application Toolkit command packets.

mnemonic 83 Dec 11, 2022
Solismod - A script subscribes to MQTT topics and waits for a message

SolisMod This is a first attempt to modify Solis inverter settings As SolisMon3,

9 Nov 14, 2022
基于多线程快速端口扫描脚本,支持目标批量导入、结果导出。

JWS_portscan 基于多线程快速端口扫描脚本,支持目标批量导入、结果导出。如果扫描公网资产,为了提升扫描的精准性,建议放到服务器运行。 用法 依赖安装:pip3 install -r requriement.txt 支持参数:python3 JWS_portscan.py --help 脚本

jammny 5 Apr 12, 2022
IoT owl is light face detection and recognition system made for small IoT devices like raspberry pi.

IoT Owl IoT owl is light face detection and recognition system made for small IoT devices like raspberry pi. Versions Heavy with mask detection withou

Ret2Me 6 Jun 06, 2022
Public HTTPS access to Home Assistant with Dataplicity service

Custom component for public HTTPS access to Home Assistant with Dataplicity service. Should work on any Linux PC or ARM, not only Raspberry as Dataplicity service said. Don't work on Windows.

Alex X 70 Oct 03, 2022
Simple app that redirect fixed URL to changing URL, configurable via POST requests

This is a basic URL redirection service. It stores associations between apps and redirection URLs, for apps with changing URLs. You can then use GET r

Maxime Weyl 2 Jan 28, 2022
Very simple and tiny file sharing service written in python

Simple File sharing tool Sharing client usage (You will need to use python3 for linux) main.py --send -f file/path Optionnal flags : pwd : set a passw

2 Jul 26, 2022
RollerScanner — Fast Port Scanner Written On Python

RollerScanner RollerScanner — Fast Port Scanner Written On Python Installation You should clone this repository using: git clone https://github.com/Ma

68 Nov 09, 2022