Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
O
opcua-asyncio
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Nikola Balog
opcua-asyncio
Commits
ab146464
Commit
ab146464
authored
Jan 06, 2021
by
oroulet
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
bugfix xml export import stucts
parent
bf1c3ee8
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
55 additions
and
23 deletions
+55
-23
asyncua/common/structures104.py
asyncua/common/structures104.py
+2
-1
asyncua/common/xmlexporter.py
asyncua/common/xmlexporter.py
+1
-2
asyncua/common/xmlimporter.py
asyncua/common/xmlimporter.py
+19
-13
asyncua/common/xmlparser.py
asyncua/common/xmlparser.py
+1
-1
asyncua/server/server.py
asyncua/server/server.py
+8
-1
tests/test_common.py
tests/test_common.py
+24
-5
No files found.
asyncua/common/structures104.py
View file @
ab146464
...
...
@@ -43,6 +43,7 @@ def new_struct_field(name, dtype, array=False, optional=False, description=""):
async
def
new_struct
(
server
,
idx
,
name
,
fields
):
"""
simple way to create a new structure
return the created data type node and the list of encoding nodes
"""
dtype
=
await
create_data_type
(
server
.
nodes
.
base_structure_type
,
idx
,
name
)
enc
=
await
create_encoding
(
dtype
,
idx
,
"Default Binary"
)
...
...
@@ -59,7 +60,7 @@ async def new_struct(server, idx, name, fields):
sdef
.
DefaultEncodingId
=
enc
.
nodeid
await
dtype
.
write_data_type_definition
(
sdef
)
return
dtype
return
dtype
,
[
enc
]
async
def
new_enum
(
server
,
idx
,
name
,
values
):
...
...
asyncua/common/xmlexporter.py
View file @
ab146464
...
...
@@ -142,7 +142,6 @@ class XmlExporter:
Returns:
"""
node_class
=
await
node
.
read_node_class
()
print
(
"EXPORT"
,
node
,
node_class
)
if
node_class
is
ua
.
NodeClass
.
Object
:
await
self
.
add_etree_object
(
node
)
...
...
@@ -319,7 +318,7 @@ class XmlExporter:
field_el
.
attrib
[
'Datatype'
]
=
field
.
DataType
.
to_string
()
if
field
.
ValueRank
!=
-
1
:
field_el
.
attrib
[
'ValueRank'
]
=
str
(
int
(
field
.
ValueRank
))
if
field
.
ArrayDimensions
!=
""
:
if
field
.
ArrayDimensions
:
field_el
.
attrib
[
'ArrayDimensions'
]
=
", "
.
join
([
str
(
i
)
for
i
in
field
.
ArrayDimensions
])
if
field
.
IsOptional
:
field_el
.
attrib
[
'IsOptional'
]
=
"true"
...
...
asyncua/common/xmlimporter.py
View file @
ab146464
...
...
@@ -20,20 +20,26 @@ class XmlImporter:
def
__init__
(
self
,
server
):
self
.
parser
=
None
self
.
server
=
server
self
.
namespaces
:
Dict
[
int
,
int
]
=
{}
#Dict[IndexInXml, IndexInServer]
self
.
namespaces
:
Dict
[
int
,
int
]
=
{}
#
Dict[IndexInXml, IndexInServer]
self
.
aliases
:
Dict
[
str
,
ua
.
NodeId
]
=
{}
self
.
refs
=
None
async
def
_map_namespaces
(
self
,
namespaces_uris
):
async
def
_map_namespaces
(
self
):
"""
creates a mapping between the namespaces in the xml file and in the server.
if not present the namespace is registered.
"""
namespaces
=
{}
for
ns_index
,
ns_uri
in
enumerate
(
namespaces_uris
):
ns_server_index
=
await
self
.
server
.
register_namespace
(
ns_uri
)
namespaces
[
ns_index
+
1
]
=
ns_server_index
return
namespaces
xml_uris
=
self
.
parser
.
get_used_namespaces
()
server_uris
=
await
self
.
server
.
get_namespace_array
()
namespaces_map
=
{}
for
ns_index
,
ns_uri
in
enumerate
(
xml_uris
):
ns_index
+=
1
# since namespaces start at 1 in xml files
if
ns_uri
in
server_uris
:
namespaces_map
[
ns_index
]
=
server_uris
.
index
(
ns_uri
)
else
:
ns_server_index
=
await
self
.
server
.
register_namespace
(
ns_uri
)
namespaces_map
[
ns_index
]
=
ns_server_index
return
namespaces_map
def
_map_aliases
(
self
,
aliases
:
dict
):
"""
...
...
@@ -44,7 +50,6 @@ class XmlImporter:
aliases_mapped
[
alias
]
=
self
.
_to_migrated_nodeid
(
node_id
)
return
aliases_mapped
async
def
_get_existing_model_in_namespace
(
self
):
server_model_list
=
[]
server_namespaces_node
=
await
self
.
server
.
nodes
.
namespaces
.
get_children
()
...
...
@@ -85,7 +90,7 @@ class XmlImporter:
self
.
parser
=
XMLParser
()
await
self
.
_check_required_models
(
xmlpath
,
xmlstring
)
await
self
.
parser
.
parse
(
xmlpath
,
xmlstring
)
self
.
namespaces
=
await
self
.
_map_namespaces
(
self
.
parser
.
get_used_namespaces
()
)
self
.
namespaces
=
await
self
.
_map_namespaces
()
_logger
.
info
(
"namespace map: %s"
,
self
.
namespaces
)
self
.
aliases
=
self
.
_map_aliases
(
self
.
parser
.
get_aliases
())
self
.
refs
=
[]
...
...
@@ -509,13 +514,14 @@ class XmlImporter:
sdef
=
ua
.
StructureDefinition
()
if
obj
.
parent
:
sdef
.
BaseDataType
=
obj
.
parent
for
data
in
obj
.
refs
:
if
data
.
reftype
==
self
.
server
.
nodes
.
HasEncoding
.
nodeid
:
#
looks likebinary encodingisthe firt one...can someone confirm?
sdef
.
DefaultEncodingId
=
data
.
target
for
ref
data
in
obj
.
refs
:
if
ref
data
.
reftype
==
self
.
server
.
nodes
.
HasEncoding
.
nodeid
:
#
supposing that default encoding is the first one...
sdef
.
DefaultEncodingId
=
ref
data
.
target
break
optional
=
False
for
field
in
obj
.
definitions
:
print
(
"IMPORT FIEL"
,
field
.
name
,
field
.
datatype
)
f
=
ua
.
StructureField
()
f
.
Name
=
field
.
name
f
.
DataType
=
field
.
datatype
...
...
asyncua/common/xmlparser.py
View file @
ab146464
...
...
@@ -69,7 +69,7 @@ class NodeData:
class
Field
:
def
__init__
(
self
,
data
):
self
.
datatype
=
data
.
get
(
"Data
T
ype"
,
""
)
self
.
datatype
=
data
.
get
(
"Data
t
ype"
,
""
)
self
.
name
=
data
.
get
(
"Name"
)
self
.
dname
=
data
.
get
(
"DisplayName"
,
""
)
self
.
optional
=
bool
(
data
.
get
(
"IsOptional"
,
False
))
...
...
asyncua/server/server.py
View file @
ab146464
...
...
@@ -546,8 +546,15 @@ class Server:
"""
Export defined nodes to xml
"""
uris
=
await
self
.
get_namespace_array
()
uris_to_export
=
{}
for
node
in
nodes
:
idx
=
node
.
nodeid
.
NamespaceIndex
if
idx
not
in
uris_to_export
and
idx
<
len
(
uris
):
uris_to_export
[
idx
]
=
uris
[
idx
]
exp
=
XmlExporter
(
self
)
await
exp
.
build_etree
(
nodes
)
await
exp
.
build_etree
(
nodes
,
uris_to_export
)
await
exp
.
write_xml
(
path
)
async
def
export_xml_by_ns
(
self
,
path
:
str
,
namespaces
:
list
=
None
):
...
...
tests/test_common.py
View file @
ab146464
...
...
@@ -1179,7 +1179,7 @@ async def test_custom_struct_with_optional_fields(opc):
async
def
test_custom_struct_of_struct
(
opc
):
idx
=
4
dtype
=
await
new_struct
(
opc
.
opc
,
idx
,
"MySubStruct2"
,
[
dtype
,
encs
=
await
new_struct
(
opc
.
opc
,
idx
,
"MySubStruct2"
,
[
new_struct_field
(
"MyBool"
,
ua
.
VariantType
.
Boolean
),
new_struct_field
(
"MyUInt32"
,
ua
.
VariantType
.
UInt32
),
])
...
...
@@ -1202,7 +1202,7 @@ async def test_custom_struct_of_struct(opc):
async
def
test_custom_list_of_struct
(
opc
):
idx
=
4
dtype
=
await
new_struct
(
opc
.
opc
,
idx
,
"MySubStruct3"
,
[
dtype
,
encs
=
await
new_struct
(
opc
.
opc
,
idx
,
"MySubStruct3"
,
[
new_struct_field
(
"MyBool"
,
ua
.
VariantType
.
Boolean
),
new_struct_field
(
"MyUInt32"
,
ua
.
VariantType
.
UInt32
),
])
...
...
@@ -1263,12 +1263,12 @@ async def test_two_times_enum(opc):
async
def
test_custom_struct_export
(
opc
):
idx
=
4
dtype
=
await
new_struct
(
opc
.
opc
,
idx
,
"MyMyStructExport"
,
[
dtype
,
encs
=
await
new_struct
(
opc
.
opc
,
idx
,
"MyMyStructExport"
,
[
new_struct_field
(
"MyBool"
,
ua
.
VariantType
.
Boolean
),
new_struct_field
(
"MyUInt32"
,
ua
.
VariantType
.
UInt32
,
array
=
True
),
])
await
opc
.
opc
.
export_xml
([
dtype
],
"custom_struct_export.xml"
)
await
opc
.
opc
.
export_xml
([
dtype
,
*
encs
],
"custom_struct_export.xml"
)
async
def
test_custom_enum_export
(
opc
):
...
...
@@ -1279,6 +1279,25 @@ async def test_custom_enum_export(opc):
"toto"
,
"tutu"
,
])
path
=
"custom_enum_export.xml"
await
opc
.
opc
.
export_xml
([
dtype
],
path
)
await
opc
.
opc
.
export_xml
([
dtype
],
"custom_enum_export.xml"
)
async
def
test_custom_enum_import
(
opc
):
nodes
=
await
opc
.
opc
.
import_xml
(
"tests/custom_enum.xml"
)
nodes
=
[
opc
.
opc
.
get_node
(
node
)
for
node
in
nodes
]
# FIXME why does it return nodeids and not nodes?
node
=
nodes
[
0
]
sdef
=
await
node
.
read_data_type_definition
()
assert
sdef
.
Fields
[
0
].
Name
==
"titi"
await
opc
.
opc
.
export_xml
(
nodes
,
"tests/custom_enum_v2.xml"
)
async
def
test_custom_struct_import
(
opc
):
nodes
=
await
opc
.
opc
.
import_xml
(
"tests/custom_struct.xml"
)
nodes
=
[
opc
.
opc
.
get_node
(
node
)
for
node
in
nodes
]
# FIXME why does it return nodeids and not nodes?
node
=
nodes
[
0
]
#FIXME: make that more robust
sdef
=
await
node
.
read_data_type_definition
()
assert
sdef
.
StructureType
==
ua
.
StructureType
.
Structure
assert
sdef
.
Fields
[
0
].
Name
==
"MyBool"
await
opc
.
opc
.
export_xml
(
nodes
,
"tests/custom_struct_v2.xml"
)
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment