Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Types introduced in service end up in spyne.model.primitive namespace #569

Open
tlandschoff-scale opened this issue May 28, 2018 · 9 comments
Labels

Comments

@tlandschoff-scale
Copy link

Hello world,

we are working on upgrading our application from spyne 2.9 to spyne 2.13 (for Python 3 support). While working on this, we noticed that spyne now misplaces the local types introduced for our service.

Here is a full example:

#!/usr/bin/env python

import logging
import uuid

from spyne.application import Application
from spyne.decorator import srpc
from spyne.interface import Wsdl11
from spyne.protocol.soap import Soap11
from spyne.service import ServiceBase
from spyne.model.primitive import Unicode


UUIDType = Unicode(
    type_name="UUIDType",
    pattern=r"[A-Fa-f0-9]{8}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{12}",
)

namespace = uuid.UUID("2faf5f8c-08be-445c-b228-fd33dd6b943b")

class ServiceWithNewType(ServiceBase):
    @srpc(UUIDType, _returns=UUIDType)
    def derive_uuid(original):
        return str(uuid.uuid3(namespace, original))


if __name__=='__main__':
    logging.basicConfig(level=logging.DEBUG)
    app = Application([ServiceWithNewType], 'expected.namespace', in_protocol=Soap11(), out_protocol=Soap11())
    app.transport = 'null.spyne'

    wsdl = Wsdl11(app.interface)
    wsdl.build_interface_document('URL')
    wsdl_str = wsdl.get_interface_document()
    print(wsdl_str)

Here is the WSDL that is generated by spyne 2.9 and spyne 2.12: generated_wsdl.zip
This was created by running

$ pip install spyne==2.9.3
$ python service_type_misplaced.py | xmllint -format - > service_type_spyne2_9.wsdl
$ pip install spyne==2.12.14
$ python service_type_misplaced.py | xmllint -format - > service_type_spyne2_12.wsdl

Here is the diff between both WSDL files:
WSDL_Diff_Generator.pdf

I think the old behaviour makes much more sense and would rather like it back. Trying to come up with a patch...

Greetings, Torsten

@tlandschoff-scale
Copy link
Author

BTW: This can be worked around by explicitly giving the namespace like this:

UUIDType = Unicode(
    type_name="UUIDType",
    pattern=r"[A-Fa-f0-9]{8}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{12}",
    __namespace__="expected.namespace",
)

This makes the wsdl of spyne 2.9 and spyne 2.12 match up again for this example.

@tlandschoff-scale
Copy link
Author

FYI: The behaviour in spyne master at 049b789 is unchanged.

@plq plq modified the milestone: 2.13 May 28, 2018
@plq plq added the Defect label May 28, 2018
@plq
Copy link
Member

plq commented May 28, 2018

this could be the result of calling resolve_namespace() too early somewhere.

I think the old behaviour makes much more sense

agreed

and would rather like it back. Trying to come up with a patch...

please do as I can't say I have time to look at this right now.

@tlandschoff-scale
Copy link
Author

tlandschoff-scale commented May 30, 2018

Edit: Simplified the stack trace, dropping pytest and debugger frames.

this could be the result of calling resolve_namespace() too early somewhere.

You bet. Here is the traceback of that call:

  File "/home/torsten.landschoff/workspace/spyne/spyne/test/model/test_primitive.py", line 574, in test_new_type
    custom_type = Unicode(pattern='123')
  File "/home/torsten.landschoff/workspace/spyne/spyne/model/primitive/string.py", line 86, in __new__
    retval = SimpleModel.__new__(cls,  ** kwargs)
  File "/home/torsten.landschoff/workspace/spyne/spyne/model/_base.py", line 803, in __new__
    return cls.customize(**kwargs)
  File "/home/torsten.landschoff/workspace/spyne/spyne/model/_base.py", line 821, in customize
    retval.resolve_namespace(retval, kwargs.get('__namespace__'))

It appears to me that commit 7029e18 changed the behaviour to call resolve_namespace immediately when customizing a type.

@plq
Copy link
Member

plq commented May 30, 2018

2013?! Honestly?! shows how much spyne's soap protocol gets used I guess :)

@tlandschoff-scale
Copy link
Author

I guess it's more about how many people care about the generated WSDL. After all, whatever the namespace, this would stil work.

@tlandschoff-scale
Copy link
Author

BTW: I just noted this comment in resolve_namespace:

    def resolve_namespace(cls, default_ns, tags=None):
        """This call finalizes the namespace assignment. The default namespace
        is not available until the application calls populate_interface method
        of the interface generator.
        """

Given this comment, the changes in 7029e18 appear to be wrong in that resolve_namespace is now called immediately when creating a new type.

@plq
Copy link
Member

plq commented May 31, 2018

Given this comment, the changes in 7029e18 appear to be wrong in that resolve_namespace is now called immediately when creating a new type.

yes, this needs to be fixed.

@AndTheDaysGoBy
Copy link

AndTheDaysGoBy commented Jul 29, 2023

I believe I'm experience a similar issue except with complex types. In particular, the ValueError of classes X and Y have conflicting names appears. The format being, the first class scoped to the module in which the model was declared. For example,

<class 'my_web_service.models.OrderResponse'>

and the second to the spyne namespace

<class 'spyne.model.complex.OrderResponse'>

conflicting on the name

<class '{the namespace}OrderResponse>

as naturally both have the same base name, as they're the same class, and the namespace, for the same reason.

Ah, sorry. Investigating, the issue stems from something else. tl;dr, I had a WSDL, to be able to in-place swap this service as much as possible, I was fiddling with spyne to get as equivalent a WSDL as possible. One issue was response element name which is determined by the function name (which I wanted to keep distinct and in snake-case). I attempted to use the out_message_name parameter to override this, similar to how _in_message_name and _operation_name allow you to override the input.

However, overriding in this manner, when the class name of the return type matches what that message name would be results in a conflict.

For those who have the element sharing a name with a namespaced type, the work arounds are rename your function call to match. That won't run into the issue. However, if you're like me and wanted to keep the function name distinct and in snake-case, either override and re-implement the rpc method or fork spyne and edit this line:
https://github.com/arskom/spyne/blob/599d80f571f8b8a18d206c0bbb0953392a603e1c/spyne/decorator.py#L493C24-L493C24
to take operation_name instead of function_name. This too won't run into the collision issue.

I'm unsure if the latter is desired as PR, so I'll just leave the idea out here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants