FreeOpcUa / python-opcua

LGPL Pure Python OPC-UA Client and Server
http://freeopcua.github.io/
GNU Lesser General Public License v3.0
1.35k stars 658 forks source link

[Server] Import XML - Importing method arguments #254

Closed maljac closed 8 years ago

maljac commented 8 years ago

Hi,

when importing a XML model via server.import_xml(...) which includes a UAVariable with DataType=Argument the following error is raised:

File "/home/jacobi/projects/opcua/python-opcua/opcua/common/xmlimporter.py", line 28, in import_xml
    self.add_variable(node)
  File "/home/jacobi/projects/opcua/python-opcua/opcua/common/xmlimporter.py", line 111, in add_variable
    attrs.Value = ua.Variant(obj.value, getattr(ua.VariantType, obj.valuetype))
  File "/usr/lib/python3.4/enum.py", line 255, in __getattr__
    raise AttributeError(name) from None

The error is introduced with commit 9398d46 which enables the import ListOfExtensionObjects. I can fix the import error by adding some values to the uatypes.VariantType enum:

class VariantType(Enum):
    ...
    Argument = 296

Now, if I browse the node in UaExpert and try to read the InputArguments node of the method, I get following execption in the server:

Exception raised while parsing message from client, closing
Traceback (most recent call last):
  File "/home/jacobi/projects/opcua/python-opcua/opcua/server/binary_server_asyncio.py", line 85, in _process_data
    ret = self.processor.process(hdr, buf)
  File "/home/jacobi/projects/opcua/python-opcua/opcua/server/uaprocessor.py", line 82, in process
    return self.process_message(msg.SecurityHeader(), msg.SequenceHeader(), msg.body())
  File "/home/jacobi/projects/opcua/python-opcua/opcua/server/uaprocessor.py", line 103, in process_message
    return self._process_message(typeid, requesthdr, algohdr, seqhdr, body)
  File "/home/jacobi/projects/opcua/python-opcua/opcua/server/uaprocessor.py", line 175, in _process_message
    self.send_response(requesthdr.RequestHandle, algohdr, seqhdr, response)
  File "/home/jacobi/projects/opcua/python-opcua/opcua/server/uaprocessor.py", line 41, in send_response
    data = self._connection.message_to_binary(response.to_binary(), message_type=msgtype, request_id=seqhdr.RequestId, algohdr=algohdr)
  File "/home/jacobi/projects/opcua/python-opcua/opcua/ua/uaprotocol_auto.py", line 7868, in to_binary
    packet.append(fieldname.to_binary())
  File "/home/jacobi/projects/opcua/python-opcua/opcua/ua/uatypes.py", line 1178, in to_binary
    packet.append(self.Value.to_binary())
  File "/home/jacobi/projects/opcua/python-opcua/opcua/ua/uatypes.py", line 1020, in to_binary
    b.append(pack_uatype_array(self.VariantType.name, flatten(self.Value)))
  File "/home/jacobi/projects/opcua/python-opcua/opcua/ua/uatypes.py", line 101, in pack_uatype_array
    b.append(pack_uatype(uatype, val))
  File "/home/jacobi/projects/opcua/python-opcua/opcua/ua/uatypes.py", line 130, in pack_uatype
    return value.to_binary()
AttributeError: 'dict' object has no attribute 'to_binary'

Any ideas?

The xml file to reproduce the result:

<UANodeSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:uax="http://opcfoundation.org/UA/2008/02/Types.xsd" xmlns="http://opcfoundation.org/UA/2011/03/UANodeSet.xsd" xmlns:s1="http://yourorganisation.org/extensionerror1/Types.xsd" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <NamespaceUris>
        <Uri>http://yourorganisation.org/extensionerror1/</Uri>
    </NamespaceUris>
    <Aliases>
        <Alias Alias="HasModellingRule">i=37</Alias>
        <Alias Alias="HasTypeDefinition">i=40</Alias>
        <Alias Alias="HasSubtype">i=45</Alias>
        <Alias Alias="HasProperty">i=46</Alias>
        <Alias Alias="HasComponent">i=47</Alias>
        <Alias Alias="Argument">i=296</Alias>
    </Aliases>
    <Extensions>
        <Extension>
            <ModelInfo Tool="UaModeler" Hash="HqP+z3HOAS5zZlvi3u3sHg==" Version="1.4.4"/>
        </Extension>
    </Extensions>
    <UAObjectType NodeId="ns=1;i=1002" BrowseName="1:MyObjectType">
        <DisplayName>MyObjectType</DisplayName>
        <References>
            <Reference ReferenceType="HasComponent">ns=1;i=7001</Reference>
            <Reference ReferenceType="HasSubtype" IsForward="false">i=58</Reference>
        </References>
    </UAObjectType>
    <UAMethod ParentNodeId="ns=1;i=1002" NodeId="ns=1;i=7001" BrowseName="1:MyMethod">
        <DisplayName>MyMethod</DisplayName>
        <References>
            <Reference ReferenceType="HasProperty">ns=1;i=6001</Reference>
            <Reference ReferenceType="HasModellingRule">i=78</Reference>
            <Reference ReferenceType="HasComponent" IsForward="false">ns=1;i=1002</Reference>
            <Reference ReferenceType="HasProperty">ns=1;i=6002</Reference>
        </References>
    </UAMethod>
    <UAVariable DataType="Argument" ParentNodeId="ns=1;i=7001" ValueRank="1" NodeId="ns=1;i=6001" ArrayDimensions="1" BrowseName="InputArguments">
        <DisplayName>InputArguments</DisplayName>
        <References>
            <Reference ReferenceType="HasProperty" IsForward="false">ns=1;i=7001</Reference>
            <Reference ReferenceType="HasModellingRule">i=78</Reference>
            <Reference ReferenceType="HasTypeDefinition">i=68</Reference>
        </References>
        <Value>
            <uax:ListOfExtensionObject>
                <uax:ExtensionObject>
                    <uax:TypeId>
                        <uax:Identifier>i=297</uax:Identifier>
                    </uax:TypeId>
                    <uax:Body>
                        <uax:Argument>
                            <uax:Name>Context</uax:Name>
                            <uax:DataType>
                                <uax:Identifier>i=12</uax:Identifier>
                            </uax:DataType>
                            <uax:ValueRank>-1</uax:ValueRank>
                            <uax:ArrayDimensions/>
                            <uax:Description/>
                        </uax:Argument>
                    </uax:Body>
                </uax:ExtensionObject>
            </uax:ListOfExtensionObject>
        </Value>
    </UAVariable>
    <UAVariable DataType="Argument" ParentNodeId="ns=1;i=7001" ValueRank="1" NodeId="ns=1;i=6002" ArrayDimensions="1" BrowseName="OutputArguments">
        <DisplayName>OutputArguments</DisplayName>
        <References>
            <Reference ReferenceType="HasModellingRule">i=78</Reference>
            <Reference ReferenceType="HasProperty" IsForward="false">ns=1;i=7001</Reference>
            <Reference ReferenceType="HasTypeDefinition">i=68</Reference>
        </References>
        <Value>
            <uax:ListOfExtensionObject>
                <uax:ExtensionObject>
                    <uax:TypeId>
                        <uax:Identifier>i=297</uax:Identifier>
                    </uax:TypeId>
                    <uax:Body>
                        <uax:Argument>
                            <uax:Name>Status</uax:Name>
                            <uax:DataType>
                                <uax:Identifier>i=6</uax:Identifier>
                            </uax:DataType>
                            <uax:ValueRank>-1</uax:ValueRank>
                            <uax:ArrayDimensions/>
                            <uax:Description/>
                        </uax:Argument>
                    </uax:Body>
                </uax:ExtensionObject>
            </uax:ListOfExtensionObject>
        </Value>
    </UAVariable>
</UANodeSet>
oroulet commented 8 years ago

I can fix the import error by adding some values to theuatypes.VariantType enum:

Do not do that. That enum should only be used for variants, not for node data types! There is something wrong here.. But I cannot have a look at this before a few days

On Wed, Jul 27, 2016, 08:49 maljac notifications@github.com wrote:

Hi,

when importing a XML model via server.import_xml(...) which includes a UAVariable with DataType=Argument the following error is raised:

File "/home/jacobi/projects/opcua/python-opcua/opcua/common/xmlimporter.py", line 28, in import_xml self.add_variable(node) File "/home/jacobi/projects/opcua/python-opcua/opcua/common/xmlimporter.py", line 111, in add_variable attrs.Value = ua.Variant(obj.value, getattr(ua.VariantType, obj.valuetype)) File "/usr/lib/python3.4/enum.py", line 255, in getattr raise AttributeError(name) from None

The error is introduced with commit 9398d46 https://github.com/FreeOpcUa/python-opcua/commit/9398d46547a263688aa1c0f5f28ce53e484b16ae which enables the import ListOfExtensionObjects. I can fix the import error by adding some values to the uatypes.VariantType enum:

class VariantType(Enum): ... Argument = 296

Now, if I browse the node in UaExpert and try to read the InputArguments node of the method, I get following execption in the server:

Exception raised while parsing message from client, closing Traceback (most recent call last): File "/home/jacobi/projects/opcua/python-opcua/opcua/server/binary_server_asyncio.py", line 85, in _process_data ret = self.processor.process(hdr, buf) File "/home/jacobi/projects/opcua/python-opcua/opcua/server/uaprocessor.py", line 82, in process return self.process_message(msg.SecurityHeader(), msg.SequenceHeader(), msg.body()) File "/home/jacobi/projects/opcua/python-opcua/opcua/server/uaprocessor.py", line 103, in process_message return self._process_message(typeid, requesthdr, algohdr, seqhdr, body) File "/home/jacobi/projects/opcua/python-opcua/opcua/server/uaprocessor.py", line 175, in _process_message self.send_response(requesthdr.RequestHandle, algohdr, seqhdr, response) File "/home/jacobi/projects/opcua/python-opcua/opcua/server/uaprocessor.py", line 41, in send_response data = self._connection.message_to_binary(response.to_binary(), message_type=msgtype, request_id=seqhdr.RequestId, algohdr=algohdr) File "/home/jacobi/projects/opcua/python-opcua/opcua/ua/uaprotocol_auto.py", line 7868, in to_binary packet.append(fieldname.to_binary()) File "/home/jacobi/projects/opcua/python-opcua/opcua/ua/uatypes.py", line 1178, in to_binary packet.append(self.Value.to_binary()) File "/home/jacobi/projects/opcua/python-opcua/opcua/ua/uatypes.py", line 1020, in to_binary b.append(pack_uatype_array(self.VariantType.name, flatten(self.Value))) File "/home/jacobi/projects/opcua/python-opcua/opcua/ua/uatypes.py", line 101, in pack_uatype_array b.append(pack_uatype(uatype, val)) File "/home/jacobi/projects/opcua/python-opcua/opcua/ua/uatypes.py", line 130, in pack_uatype return value.to_binary() AttributeError: 'dict' object has no attribute 'to_binary'

Any ideas?

The xml file to reproduce the result:

http://yourorganisation.org/extensionerror1/ i=37 i=40 i=45 i=46 i=47 i=296 MyObjectType ns=1;i=7001 i=58 MyMethod ns=1;i=6001 i=78 ns=1;i=1002 ns=1;i=6002 InputArguments ns=1;i=7001 i=78 i=68 uax:ListOfExtensionObject uax:ExtensionObject uax:TypeId uax:Identifieri=297/uax:Identifier /uax:TypeId uax:Body uax:Argument uax:NameContext/uax:Name uax:DataType uax:Identifieri=12/uax:Identifier /uax:DataType uax:ValueRank-1/uax:ValueRank uax:ArrayDimensions/ uax:Description/ /uax:Argument /uax:Body /uax:ExtensionObject /uax:ListOfExtensionObject OutputArguments i=78 ns=1;i=7001 i=68 uax:ListOfExtensionObject uax:ExtensionObject uax:TypeId uax:Identifieri=297/uax:Identifier /uax:TypeId uax:Body uax:Argument uax:NameStatus/uax:Name uax:DataType uax:Identifieri=6/uax:Identifier /uax:DataType uax:ValueRank-1/uax:ValueRank uax:ArrayDimensions/ uax:Description/ /uax:Argument /uax:Body /uax:ExtensionObject /uax:ListOfExtensionObject

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/FreeOpcUa/python-opcua/issues/254, or mute the thread https://github.com/notifications/unsubscribe-auth/ACcfzvw7mfo3Ntt9ooApa-GmTB0uBZndks5qZv9mgaJpZM4JV4xv .

zerox1212 commented 8 years ago

Importing UA methods with XML probably isn't tested. I'm not sure if it's even supported by the importer...

maljac commented 8 years ago

Seems to be supported: xmlimporter.py :

elif node.nodetype == 'UAMethod':
                self.add_method(node)

Its not the method itself, the arguments for the method (in, out) produce the error.

It s probably a special case of UAVariable, since the XML lools like this:

<UAVariable DataType="Argument"

maljac commented 8 years ago

If one of you guys could give me a hint where to look I would propose a PR.

zerox1212 commented 8 years ago

I tested your problem and it's obvious what is happening. The importer is trying to make a Variable that isn't a Variant which breaks the creation of the node.

I think we need a special case for this so that if the Variable is an Argument it parses the extension object. Perhaps you can look at how UA Enums are implemented to figure out how to do it.

If you look at the code the TODO tells you that a special case is needed:

if obj.value is not None:
            #TODO: If non variant based types grow move it to a seperate function 
            if obj.valuetype == 'ListOfLocalizedText':
                attrs.Value = ua.Variant([ua.LocalizedText(txt) for txt in obj.value], None)
            elif obj.valuetype == 'EnumValueType':
                values = []
                for ev in obj.value:
                    enum_value = ua.EnumValueType()
                    enum_value.DisplayName = ua.LocalizedText(ev['DisplayName'])
                    enum_value.Description = ua.LocalizedText(ev['Description'])
                    enum_value.Value = int(ev['Value'])
                    values.append(enum_value)
                attrs.Value = values
            else:
                attrs.Value = ua.Variant(obj.value, getattr(ua.VariantType, obj.valuetype))

#TODO: If non variant based types grow move it to a seperate function

maljac commented 8 years ago

Since the UML is created by UAModeler and the comparison with companion specs show same XML, we can assume that this is a special case. Anyway, I will check the spec as you suggested. Am 28.07.2016 17:58 schrieb "Andrew" notifications@github.com:

I tested your problem and it's obvious what is happening. The importer is trying to make a Variable that isn't a Variant which breaks the creation of the node.

Either the XML is wrong, or there is some special way to handle this that we must look for in the OPC UA spec.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/FreeOpcUa/python-opcua/issues/254#issuecomment-235940084, or mute the thread https://github.com/notifications/unsubscribe-auth/AJ_RGoJtXWTQuf46OomLza0d0RDgjVfyks5qaNGKgaJpZM4JV4xv .

zerox1212 commented 8 years ago

You are fast. You quoted my response before I edited lol. Please read again.

maljac commented 8 years ago

Haha, okay. Thanks for the hint. I ll give it a try.