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)
Tool that creates a complete copy of your server

Discord-Server-Cloner Tool that creates a complete copy of your server Setup: Open run.bat If the file closes, open cmd And write: pip install -r requ

DEEM 3 Dec 13, 2021
Domain To Api [ PYTHON ]

Domain To IP Usage You Open Terminal For Run The Program python ip.py Input & Output Input Your List e.g domain.txt Output ( For Save Output File )

It's Me Jafar 0 Dec 12, 2021
Throttle rTorrent on Plex stream Start/Stop

Dependencies Python 3.6+ Tautulli Script Setup Edit rtorrent_throttle.py and set rTorrent username, password and RPC2 url. Tautulli Setup Commum Scrip

4 Apr 25, 2022
Nexum is an open-source, remote administration tool written in Python 3

A full-featured remote administration tool written in Python 3. The goal of this project is to make the use of a remote administration tool as simple

z3phyrus 2 Nov 26, 2021
Extended refactoring capabilities for Python LSP Server using Rope.

pylsp-rope Extended refactoring capabilities for Python LSP Server using Rope. This is a plugin for Python LSP Server, so you also need to have it ins

36 Dec 24, 2022
Linkedin Connection Automation

Why spend an hour+ a week, connecting with the correct people on LinkedIn when you can go for lunch and let your computer do the hard work?

1 Nov 29, 2021
This is the code repository for the USENIX Security 2021 paper, "Weaponizing Middleboxes for TCP Reflected Amplification".

weaponizing-censors Censors pose a threat to the entire Internet. In this work, we show that censoring middleboxes and firewalls can be weaponized by

UMD Breakerspace 119 Dec 31, 2022
Lets you remove all friends, leave GCs, and leave servers, in an instant!

anonymity Lets you remove all friends, leave GCs, and leave servers, in an instant! You can also do each of them by themselves. First, you need to get

1 Dec 07, 2021
track IP Address

ipX Table of Contents ipX Welcome Features Uses Author 📝 License Welcome find the location of an IP address. Specifically, you can get the following

Ali Shahid 15 Sep 26, 2022
Lightweight asyncio compatible utilities for consuming broker messages.

A simple asyncio compatible consumer for handling amqp messages.

Mehdi Kamani 3 Apr 10, 2022
No-dependency, single file NNTP server library for developing modern, rfc3977-compliant (bridge) NNTP servers.

nntpserver.py No-dependency, single file NNTP server library for developing modern, rfc3977-compliant (bridge) NNTP servers for python =3.7. Develope

Manos Pitsidianakis 44 Nov 14, 2022
Display ip2.network active live streams.

Display ip2.network active live streams.

Daeshon Jones 0 Oct 31, 2021
Tool to get the top 100 of the fastest nodes in the Tor network. Based on Kirzahk tool.

Tor Network Top 100 IPs Tool to get the top 100 of the fastest nodes in the Tor network. Based on Kirzahk tool. Just execute top100ipstor.py to get th

Juan Manuel 0 Jan 23, 2022
A pretty quick and simple interface to paramiko SFTP

A pretty quick and simple interface to paramiko SFTP. Provides multi-threaded routines with progress notifications for reliable, asynchronous transfers. This is a Python3 optimized fork of pysftp wit

14 Dec 21, 2022
Get Your Localhost Online - Ngrok Alternative

Get Your Localhost Online - Ngrok Alternative

Azimjon Pulatov 442 Jan 04, 2023
📨 Share files easily over your local network from the terminal! 📨

Fileshare 📨 Share files easily over your local network from the terminal! 📨 Installation #

Dopevog 11 Sep 10, 2021
Utility for converting IP Fabric webhooks into a Teams format.

IP Fabric Webhook Integration for Microsoft Teams and/or Slack Setup IP Fabric Setup Go to Settings Webhooks Add webhook Provide a name URL will b

Community Fabric 1 Jan 26, 2022
Ipscanner - A simple threaded IP-Scanner written in python3 that can monitor local IP's in your network

IPScanner 🔬 A simple threaded IP-Scanner written in python3 that can monitor lo

4 Dec 12, 2022
A simple port scanner for Web/ip scanning Port 0/500 editable inside the .py file

Simple-Port-Scanner a simple port scanner for Web/ip scanning Port 0/500 editable inside the .py file Open Cmd/Terminal Cmd Downloads Run Command: pip

YABOI 1 Nov 22, 2021
🐛 SSH self spreading worm written in python3 to propagate a botnet.

Mirkat SSH self spreading worm written in python3 to propagate a botnet. Install tutorial. cd ./script && sh setup.sh Support me. ⚠️ If this reposito

Ѵιcнч 58 Nov 01, 2022