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
758d89c0
Commit
758d89c0
authored
Sep 29, 2022
by
Alexander Schrode
Committed by
oroulet
Oct 02, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
implement encode/decode
parent
d2b48b5a
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
43 additions
and
12 deletions
+43
-12
asyncua/ua/ua_binary.py
asyncua/ua/ua_binary.py
+30
-11
tests/custom_struct_recursive.xml
tests/custom_struct_recursive.xml
+1
-0
tests/test_common.py
tests/test_common.py
+12
-1
No files found.
asyncua/ua/ua_binary.py
View file @
758d89c0
...
...
@@ -5,6 +5,7 @@ Binary protocol specific functions and constants
import
functools
import
struct
import
logging
from
types
import
NoneType
from
typing
import
Any
,
Callable
import
typing
import
uuid
...
...
@@ -253,14 +254,19 @@ def _create_uatype_array_deserializer(vtype):
return
deserialize
def
field_serializer
(
ftype
)
->
Callable
[[
Any
],
bytes
]:
def
field_serializer
(
ftype
,
dataclazz
)
->
Callable
[[
Any
],
bytes
]:
is_optional
=
type_is_union
(
ftype
)
uatype
=
ftype
if
is_optional
:
uatype
=
types_from_union
(
uatype
)[
0
]
if
type_is_list
(
uatype
):
return
create_list_serializer
(
type_from_list
(
uatype
))
ft
=
type_from_list
(
uatype
)
return
create_list_serializer
(
ft
,
ft
==
dataclazz
)
else
:
if
ftype
==
dataclazz
:
if
is_optional
:
return
lambda
val
:
b''
if
val
is
None
else
create_type_serializer
(
uatype
)(
val
)
return
lambda
x
:
create_type_serializer
(
uatype
)(
x
)
serializer
=
create_type_serializer
(
uatype
)
if
is_optional
:
return
lambda
val
:
b''
if
val
is
None
else
serializer
(
val
)
...
...
@@ -281,7 +287,7 @@ def create_dataclass_serializer(dataclazz):
if
issubclass
(
dataclazz
,
ua
.
UaUnion
):
# Union is a class with Encoding and Value field
# the value is depended of encoding
encoding_funcs
=
[
field_serializer
(
t
)
for
t
in
dataclazz
.
_union_types
]
encoding_funcs
=
[
field_serializer
(
t
,
dataclazz
)
for
t
in
dataclazz
.
_union_types
]
def
union_serialize
(
obj
):
bin
=
Primitives
.
UInt32
.
pack
(
obj
.
Encoding
)
...
...
@@ -305,7 +311,7 @@ def create_dataclass_serializer(dataclazz):
enc
|=
enc_val
return
enc
encoding_functions
=
[(
f
.
name
,
field_serializer
(
f
.
type
))
for
f
in
data_fields
]
encoding_functions
=
[(
f
.
name
,
field_serializer
(
f
.
type
,
dataclazz
))
for
f
in
data_fields
]
def
serialize
(
obj
):
return
b''
.
join
(
...
...
@@ -361,7 +367,7 @@ def to_binary(uatype, val):
@
functools
.
lru_cache
(
maxsize
=
None
)
def
create_list_serializer
(
uatype
)
->
Callable
[[
Any
],
bytes
]:
def
create_list_serializer
(
uatype
,
recursive
:
bool
=
False
)
->
Callable
[[
Any
],
bytes
]:
"""
Given a type, return a function that takes a list of instances
of that type and serializes it.
...
...
@@ -369,9 +375,16 @@ def create_list_serializer(uatype) -> Callable[[Any], bytes]:
if
hasattr
(
Primitives1
,
uatype
.
__name__
):
data_type
=
getattr
(
Primitives1
,
uatype
.
__name__
)
return
data_type
.
pack_array
type_serializer
=
create_type_serializer
(
uatype
)
none_val
=
Primitives
.
Int32
.
pack
(
-
1
)
if
recursive
:
def
recursive_serialize
(
val
):
if
val
is
None
:
return
none_val
data_size
=
Primitives
.
Int32
.
pack
(
len
(
val
))
return
data_size
+
b''
.
join
(
create_type_serializer
(
uatype
)(
el
)
for
el
in
val
)
return
recursive_serialize
type_serializer
=
create_type_serializer
(
uatype
)
def
serialize
(
val
):
if
val
is
None
:
return
none_val
...
...
@@ -554,7 +567,13 @@ def extensionobject_to_binary(obj):
return
b''
.
join
(
packet
)
def
_create_list_deserializer
(
uatype
):
def
_create_list_deserializer
(
uatype
,
recursive
:
bool
=
False
):
if
recursive
:
def
_deserialize
(
data
):
size
=
Primitives
.
Int32
.
unpack
(
data
)
return
[
_create_type_deserializer
(
uatype
)(
data
)
for
_
in
range
(
size
)]
return
_deserialize
element_deserializer
=
_create_type_deserializer
(
uatype
)
def
_deserialize
(
data
):
...
...
@@ -564,7 +583,7 @@ def _create_list_deserializer(uatype):
@
functools
.
lru_cache
(
maxsize
=
None
)
def
_create_type_deserializer
(
uatype
):
def
_create_type_deserializer
(
uatype
,
dataclazz
=
NoneType
):
if
type_is_union
(
uatype
):
return
_create_type_deserializer
(
types_from_union
(
uatype
)[
0
])
if
type_is_list
(
uatype
):
...
...
@@ -573,7 +592,7 @@ def _create_type_deserializer(uatype):
vtype
=
getattr
(
ua
.
VariantType
,
utype
.
__name__
)
return
_create_uatype_array_deserializer
(
vtype
)
else
:
return
_create_list_deserializer
(
utype
)
return
_create_list_deserializer
(
utype
,
utype
==
dataclazz
)
if
hasattr
(
ua
.
VariantType
,
uatype
.
__name__
):
vtype
=
getattr
(
ua
.
VariantType
,
uatype
.
__name__
)
return
_create_uatype_deserializer
(
vtype
)
...
...
@@ -608,7 +627,7 @@ def _create_dataclass_deserializer(objtype):
if
issubclass
(
objtype
,
ua
.
UaUnion
):
# unions are just objects with encoding and value field
typefields
=
fields
(
objtype
)
field_deserializers
=
[
_create_type_deserializer
(
t
)
for
t
in
objtype
.
_union_types
]
field_deserializers
=
[
_create_type_deserializer
(
t
,
objtype
)
for
t
in
objtype
.
_union_types
]
byte_decode
=
next
(
_create_type_deserializer
(
f
.
type
)
for
f
in
typefields
if
f
.
name
==
"Encoding"
)
def
decode_union
(
data
):
...
...
@@ -640,7 +659,7 @@ def _create_dataclass_deserializer(objtype):
if
subtypes
:
deserialize_field
=
extensionobject_from_binary
else
:
deserialize_field
=
_create_type_deserializer
(
field_type
)
deserialize_field
=
_create_type_deserializer
(
field_type
,
objtype
)
field_deserializers
.
append
((
field
,
optional_enc_bit
,
deserialize_field
))
def
decode
(
data
):
...
...
tests/custom_struct_recursive.xml
View file @
758d89c0
...
...
@@ -21,6 +21,7 @@
</References>
<Definition
Name=
"1:MyParameterType"
>
<Field
DataType=
"MyParameterType"
ValueRank=
"1"
ArrayDimensions=
"0"
Name=
"Subparameters"
/>
<Field
Name=
"Value"
DataType=
"i=7"
/>
</Definition>
</UADataType>
...
...
tests/test_common.py
View file @
758d89c0
...
...
@@ -22,7 +22,7 @@ from asyncua.common.methods import call_method_full
from
asyncua.common.copy_node_util
import
copy_node
from
asyncua.common.instantiate_util
import
instantiate
from
asyncua.common.structures104
import
new_struct
,
new_enum
,
new_struct_field
from
asyncua.ua.ua_binary
import
struct_to_binary
,
struct_from_binary
pytestmark
=
pytest
.
mark
.
asyncio
...
...
@@ -1640,3 +1640,14 @@ async def test_custom_struct_with_strange_chars(opc):
var
=
await
opc
.
opc
.
nodes
.
objects
.
add_variable
(
idx
,
"my_siemens_struct"
,
ua
.
Variant
(
mystruct
,
ua
.
VariantType
.
ExtensionObject
))
val
=
await
var
.
read_value
()
assert
val
.
My_UInt32
==
[
78
,
79
]
async
def
test_custom_struct_recursive_serialize
(
opc
):
idx
=
4
nodes
=
await
opc
.
opc
.
import_xml
(
"tests/custom_struct_recursive.xml"
)
await
opc
.
opc
.
load_data_type_definitions
()
param
=
ua
.
MyParameterType
(
Value
=
2
)
param
.
Subparameters
.
append
(
ua
.
MyParameterType
(
Value
=
1
))
bin
=
struct_to_binary
(
param
)
res
=
struct_from_binary
(
ua
.
MyParameterType
,
ua
.
utils
.
Buffer
(
bin
))
assert
param
==
res
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