FreeOpcUa / python-opcua

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

ArrayDimensions has changed in v1.3 #1000

Open hsd-dev opened 4 years ago

hsd-dev commented 4 years ago

I am trying to use the Robotics specification from OPCUA foundation. When I try to generate the address spaces with generate_address_spaces.py script, I get the error:

Generating Python code ../opcua/server/standard_address_space/standard_address_space_part3.py for XML file new/Opc.Ua.NodeSet2.Part3.xml
Generating Python code ../opcua/server/standard_address_space/standard_address_space_part4.py for XML file new/Opc.Ua.NodeSet2.Part4.xml
Generating Python code ../opcua/server/standard_address_space/standard_address_space_part5.py for XML file new/Opc.Ua.NodeSet2.Part5.xml
Traceback (most recent call last):
  File "generate_address_space.py", line 350, in <module>
    c.run()
  File "generate_address_space.py", line 108, in run
    self.make_variable_code(node)
  File "generate_address_space.py", line 249, in make_variable_code
    self.make_common_variable_code(indent, obj)
  File "generate_address_space.py", line 199, in make_common_variable_code
    self.make_ext_obj_code(indent, ext)
  File "generate_address_space.py", line 239, in make_ext_obj_code
    val2 = _to_val([extobj.objname, k], k2, v2)
  File "generate_address_space.py", line 19, in _to_val
    cls = getattr(ua, _get_uatype_name(cls, o))
AttributeError: module 'opcua.ua' has no attribute 'UInt32'

The error occurs in Opc.Ua.NodeSet2.Part5.xml

  <ArrayDimensions>
    <UInt32>0</UInt32>
  </ArrayDimensions>

which was previously

<ArrayDimensions />

Also in NodeIds.csv

  <xs:simpleType name="ArrayDimensions">
    <xs:restriction base="xs:token">
      <xs:pattern value="(([0-9]+,)*[0-9]+)?" />
    </xs:restriction>
  </xs:simpleType>

which was previously

  <xs:simpleType name="ArrayDimensions">
    <xs:list>
      <xs:simpleType>
        <xs:restriction base="xs:token">
          <xs:pattern value="([0-9]*,|[0-9]*)*"></xs:pattern>
        </xs:restriction>
      </xs:simpleType>
    </xs:list>
  </xs:simpleType>

I am not sure if I am looking in the right direction. How to handle these changes?

oroulet commented 4 years ago

The parse need to be changed. Tried to look at it a few weeks ago and did not manage to find exactly where this is done. Also we need to stay backwards compatible

hsd-dev commented 4 years ago

Have you documented the process to create new address spaces? This is the one I found. Is that correct? I directly ran the generate_address_spaces.py script.

hsd-dev commented 4 years ago

Also https://github.com/FreeOpcUa/python-opcua/pull/576 seems to update the repo for 1.04?

hsd-dev commented 4 years ago

The error says there is not attribute UInt32 in opcua.ua. Do we have to add the attribute somewhere in uatypes.py. Seems like the attributes are defined as classes in it.

oroulet commented 4 years ago

the documented process seems fine. the issue (as far as I remember) is that the xml now looks like this.

<ArrayDimensions>
    <UInt32>0</UInt32>
  </ArrayDimensions>

While before itwas <ArrayDimensions>0</ArrayDimensions>

So the current code is trying to create an object of type UInt32 which does not exist as this should be registered as a number and just write code like : obj.ArrayDimentsions = 0 (you get an attribute error since the code is written similar to: gettatr(ua, myobj)) This is touchy to fix since the syntax without the datatype is still used at several other places.

Also to complicate things, the entire xml address space is now only one file while before it was several small files. This is a big issue on machine with little memory..

see my current (completely broken) code there: https://github.com/FreeOpcUa/opcua-asyncio/pull/173

Help welcome I have no time to look at this currently

oroulet commented 4 years ago

in fact the code changes in that merge request is very very small, I mainly spent time trying to understand where the issue was, so you are welcome to take over the merge request

hsd-dev commented 4 years ago

Actually the parser is not the problem. I wrote a test.xml

<?xml version="1.0" encoding="utf-8" ?>
<UANodeSet xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" LastModified="2018-02-09T00:00:00Z" xmlns="http://opcfoundation.org/UA/2011/03/UANodeSet.xsd">
  <Models>
    <Model ModelUri="http://opcfoundation.org/UA/" Version="1.02" PublicationDate="2018-02-09T00:00:00Z" />
  </Models>
  <UAVariable NodeId="i=11491" BrowseName="OutputArguments" ParentNodeId="i=11489" DataType="i=296" ValueRank="1" ArrayDimensions="0">
    <DisplayName>OutputArguments</DisplayName>
    <Value>
      <ListOfExtensionObject xmlns="http://opcfoundation.org/UA/2008/02/Types.xsd">
        <ExtensionObject>
          <TypeId>
            <Identifier>i=297</Identifier>
          </TypeId>
          <Body>
            <Argument>
              <Name>ServerHandles</Name>
              <DataType>
                <Identifier>i=7</Identifier>
              </DataType>
              <ValueRank>1</ValueRank>
              <ArrayDimensions>
                <UInt32>0</UInt32>
              </ArrayDimensions>
            </Argument>
          </Body>
        </ExtensionObject>
      </ListOfExtensionObject>
    </Value>
  </UAVariable>
</UANodeSet>

and run only xmlparser.py and print the val at https://github.com/FreeOpcUa/python-opcua/blob/4119e74be91091e7ae0f72dcfed24c5334d691df/opcua/common/xmlparser.py#L330 I get:

[('Name', 'ServerHandles'), ('DataType', [('Identifier', 'i=7')]), ('ValueRank', '1'), ('ArrayDimensions', [('UInt32', '0')])]

Also, if I print obj.dimensions at https://github.com/FreeOpcUa/python-opcua/blob/4119e74be91091e7ae0f72dcfed24c5334d691df/opcua/common/xmlparser.py#L178 I get:

key val: ArrayDimensions 0
[0]

Which is actually this line from the XML

<UAVariable NodeId="i=11491" BrowseName="OutputArguments" ParentNodeId="i=11489" DataType="i=296" ValueRank="1" ArrayDimensions="0">

Since the error happens during gettatr(ua, myobj), we might have to add a new class in uatypes.py.

oroulet commented 4 years ago

when I say the parser, in fact I mean the code generating objects right after parsing. No in that case you do not want to add a type in uatype. it already exists . you want to ignore the uint32 stuff since we do not care to generate python code, we want to use the value as int

hsd-dev commented 4 years ago

https://github.com/FreeOpcUa/python-opcua/pull/1003