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
d5bacbc8
Commit
d5bacbc8
authored
Dec 17, 2022
by
Kolja Brix
Committed by
oroulet
Jan 01, 2023
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix some more typos.
parent
888462e1
Changes
32
Hide whitespace changes
Inline
Side-by-side
Showing
32 changed files
with
105 additions
and
106 deletions
+105
-106
README.md
README.md
+1
-1
asyncua/client/client.py
asyncua/client/client.py
+5
-5
asyncua/client/ua_client.py
asyncua/client/ua_client.py
+9
-9
asyncua/client/ua_file_transfer.py
asyncua/client/ua_file_transfer.py
+1
-1
asyncua/common/statemachine.py
asyncua/common/statemachine.py
+4
-4
asyncua/common/structures.py
asyncua/common/structures.py
+4
-4
asyncua/common/structures104.py
asyncua/common/structures104.py
+4
-4
asyncua/common/ua_utils.py
asyncua/common/ua_utils.py
+9
-9
asyncua/common/xmlexporter.py
asyncua/common/xmlexporter.py
+4
-4
asyncua/common/xmlimporter.py
asyncua/common/xmlimporter.py
+2
-2
asyncua/common/xmlparser.py
asyncua/common/xmlparser.py
+2
-2
asyncua/crypto/permission_rules.py
asyncua/crypto/permission_rules.py
+0
-1
asyncua/crypto/security_policies.py
asyncua/crypto/security_policies.py
+2
-2
asyncua/server/internal_server.py
asyncua/server/internal_server.py
+2
-2
asyncua/server/server.py
asyncua/server/server.py
+5
-5
asyncua/server/uaprocessor.py
asyncua/server/uaprocessor.py
+1
-1
asyncua/tools.py
asyncua/tools.py
+1
-1
asyncua/ua/ua_binary.py
asyncua/ua/ua_binary.py
+2
-2
asyncua/ua/uaprotocol_hand.py
asyncua/ua/uaprotocol_hand.py
+6
-6
asyncua/ua/uatypes.py
asyncua/ua/uatypes.py
+16
-16
examples/server-limits.py
examples/server-limits.py
+2
-2
examples/server-methods.py
examples/server-methods.py
+2
-2
examples/server-minimal.py
examples/server-minimal.py
+1
-1
examples/server-ua-python-mirror.py
examples/server-ua-python-mirror.py
+3
-3
examples/server-virtual-network.py
examples/server-virtual-network.py
+1
-1
examples/statemachine-example.py
examples/statemachine-example.py
+3
-3
examples/sync/client-example.py
examples/sync/client-example.py
+1
-1
examples/sync/client_to_prosys.py
examples/sync/client_to_prosys.py
+2
-2
examples/sync/server-example.py
examples/sync/server-example.py
+5
-5
examples/sync/server-minimal.py
examples/sync/server-minimal.py
+3
-3
release.py
release.py
+1
-1
schemas/generate_model_from_nodeset.py
schemas/generate_model_from_nodeset.py
+1
-1
No files found.
README.md
View file @
d5bacbc8
...
...
@@ -53,7 +53,7 @@ async with Client(url='opc.tcp://localhost:4840/freeopcua/server/') as client:
value
=
await
node
.
read_value
()
```
Of course you can also call the
`connect`
,
`disconnect`
methods yourself if you do not want to use the context manager.
Of course
,
you can also call the
`connect`
,
`disconnect`
methods yourself if you do not want to use the context manager.
See the example folder and the code for more information on the client API.
...
...
asyncua/client/client.py
View file @
d5bacbc8
...
...
@@ -123,8 +123,8 @@ class Client:
def
set_locale
(
self
,
locale
:
List
[
str
])
->
None
:
"""
Sets the prefred locales of the client, the server chooses which locale he can provide.
Normal
y the first matching locale in the list will be chos
sen, by the server.
Sets the pref
er
red locales of the client, the server chooses which locale he can provide.
Normal
ly the first matching locale in the list will be cho
sen, by the server.
Call this before connect()
"""
self
.
_locale
=
locale
...
...
@@ -390,7 +390,7 @@ class Client:
async
def
create_session
(
self
):
"""
send a CreateSessionRequest to server with reasonable parameters.
If you want
o modify settings look at code of this
methods
If you want
to modify settings look at code of these
methods
and make your own
"""
self
.
_closing
=
False
...
...
@@ -467,8 +467,8 @@ class Client:
async
def
_renew_channel_loop
(
self
):
"""
Renew the SecureChannel before the SecureChannelTimeout will happen.
In theory
we could do that only if no session activity
but it does not cost much.
.
In theory
, we could do that only if no session activity,
but it does not cost much.
"""
try
:
# Part4 5.5.2.1:
...
...
asyncua/client/ua_client.py
View file @
d5bacbc8
...
...
@@ -47,7 +47,7 @@ class UASocketProtocol(asyncio.Protocol):
# needed to pass params from asynchronous request to synchronous data receive callback, as well as
# passing back the processed response to the request so that it can return it.
self
.
_open_secure_channel_exchange
:
Union
[
ua
.
OpenSecureChannelResponse
,
ua
.
OpenSecureChannelParameters
,
None
]
=
None
# Hook for upper
layer tasks before a request is send
(optional)
# Hook for upper
layer tasks before a request is sent
(optional)
self
.
pre_request_hook
:
Optional
[
Callable
[[],
Awaitable
[
None
]]]
=
None
def
connection_made
(
self
,
transport
:
asyncio
.
Transport
):
# type: ignore
...
...
@@ -153,8 +153,8 @@ class UASocketProtocol(asyncio.Protocol):
"""
timeout
=
self
.
timeout
if
timeout
is
None
else
timeout
if
self
.
pre_request_hook
:
# This will propaga
de exceptions from background tasks to the lib
ary user before calling a request which will
# timeout then.
# This will propaga
te exceptions from background tasks to the libr
ary user before calling a request which will
# time
out then.
await
self
.
pre_request_hook
()
try
:
data
=
await
asyncio
.
wait_for
(
self
.
_send_request
(
request
,
timeout
,
message_type
),
timeout
if
timeout
else
None
)
...
...
@@ -230,7 +230,7 @@ class UASocketProtocol(asyncio.Protocol):
async
def
close_secure_channel
(
self
):
"""
Close secure channel.
It seems to trigger a shutdown of socket in most servers, so be prepare to reconnect.
It seems to trigger a shutdown of socket in most servers, so be prepare
d
to reconnect.
OPC UA specs Part 6, 7.1.4 say that Server does not send a CloseSecureChannel response
and should just close socket.
"""
...
...
@@ -310,7 +310,7 @@ class UaClient(AbstractSession):
async
def
close_secure_channel
(
self
):
"""
close secure channel. It seems to trigger a shutdown of socket
in most servers, so be prepare to reconnect
in most servers, so be prepare
d
to reconnect
"""
if
not
self
.
protocol
or
self
.
protocol
.
state
==
UASocketProtocol
.
CLOSED
:
self
.
logger
.
warning
(
"close_secure_channel was called but connection is closed"
)
...
...
@@ -485,7 +485,7 @@ class UaClient(AbstractSession):
response
.
Parameters
.
SubscriptionId
)
if
not
self
.
_publish_task
or
self
.
_publish_task
.
done
():
# Start the publish loop if it is not yet running
# Start the publish
ing
loop if it is not yet running
# The current strategy is to have only one open publish request per UaClient. This might not be enough
# in high latency networks or in case many subscriptions are created. A Set of Tasks of `_publish_loop`
# could be used if necessary.
...
...
@@ -494,7 +494,7 @@ class UaClient(AbstractSession):
async
def
inform_subscriptions
(
self
,
status
:
ua
.
StatusCode
):
"""
Inform all current subscriptions with a status code. This calls the handlers status_change_notification
Inform all current subscriptions with a status code. This calls the handler
'
s status_change_notification
"""
status_message
=
ua
.
StatusChangeNotification
(
Status
=
status
)
notification_message
=
ua
.
NotificationMessage
(
NotificationData
=
[
status_message
])
...
...
@@ -570,7 +570,7 @@ class UaClient(AbstractSession):
continue
except
BadNoSubscription
:
# See Spec. Part 5, 13.8.1
# BadNoSubscription is expected to be received after deleting the last subscription.
# We use this as a signal to exit this task and stop sending PublishRequests. This is easier th
e
n
# We use this as a signal to exit this task and stop sending PublishRequests. This is easier th
a
n
# checking if there are no more subscriptions registered in this client (). A Publish response
# could still arrive before the DeleteSubscription response.
#
...
...
@@ -780,6 +780,6 @@ class UaClient(AbstractSession):
return
response
.
Parameters
.
Results
async
def
transfer_subscriptions
(
self
,
params
:
ua
.
TransferSubscriptionsParameters
)
->
List
[
ua
.
TransferResult
]:
# Subscriptions aren't bound to a Session and can be transfered!
# Subscriptions aren't bound to a Session and can be transfer
r
ed!
# https://reference.opcfoundation.org/Core/Part4/v104/5.13.7/
raise
NotImplementedError
asyncua/client/ua_file_transfer.py
View file @
d5bacbc8
...
...
@@ -89,7 +89,7 @@ class UaFile:
It is server-dependent whether the written data are persistently
stored if the session is ended without calling the Close Method with the fileHandle.
Writing an empty or null ByteString returns a Good result code without any
a
ffect on the file.
e
ffect on the file.
"""
_logger
.
debug
(
"Request to write to file %s"
,
self
.
_file_node
)
if
self
.
_write_node
is
None
:
...
...
asyncua/common/statemachine.py
View file @
d5bacbc8
...
...
@@ -48,7 +48,7 @@ class State:
class
Transition
:
'''
Helperclass for Transitions (TransitionVariableType)
Helper
class for Transitions (TransitionVariableType)
https://reference.opcfoundation.org/v104/Core/docs/Part5/B.4.4/
name: type string will be converted automatically to qualifiedname
-> Name is a QualifiedName which uniquely identifies a transition within the StateMachineType.
...
...
@@ -57,7 +57,7 @@ class Transition:
transitiontime: TransitionTime specifies when the transition occurred.
effectivetransitiontime: EffectiveTransitionTime specifies the time when the current state or one of its substates was entered.
If, for example, a StateA is active and – while active – switches several times between its substates SubA and SubB,
then the TransitionTime stays at the point in time whe
re StateA became active whereas the EffectiveTransitionTime changes
then the TransitionTime stays at the point in time whe
n StateA became active whereas the EffectiveTransitionTime changes
with each change of a substate.
'''
def
__init__
(
self
,
id
,
name
:
str
=
None
,
number
:
int
=
None
,
node
:
Node
=
None
):
...
...
@@ -153,7 +153,7 @@ class StateMachine(object):
elif
dn
.
Text
==
"EffectiveDisplayName"
:
self
.
_current_state_effective_display_name_node
=
await
self
.
_current_state_node
.
get_child
([
"EffectiveDisplayName"
])
else
:
_logger
.
warning
(
f"
{
await
statemachine
.
read_browse_name
()
}
CurrentState Unknown propert
ie
:
{
dn
.
Text
}
"
)
_logger
.
warning
(
f"
{
await
statemachine
.
read_browse_name
()
}
CurrentState Unknown propert
y
:
{
dn
.
Text
}
"
)
if
self
.
_optionals
:
self
.
_last_transition_node
=
await
statemachine
.
get_child
([
"LastTransition"
])
last_transition_props
=
await
self
.
_last_transition_node
.
get_properties
()
...
...
@@ -168,7 +168,7 @@ class StateMachine(object):
elif
dn
.
Text
==
"TransitionTime"
:
self
.
_last_transition_transitiontime_node
=
await
self
.
_last_transition_node
.
get_child
([
"TransitionTime"
])
else
:
_logger
.
warning
(
f"
{
await
statemachine
.
read_browse_name
()
}
LastTransition Unknown propert
ie
:
{
dn
.
Text
}
"
)
_logger
.
warning
(
f"
{
await
statemachine
.
read_browse_name
()
}
LastTransition Unknown propert
y
:
{
dn
.
Text
}
"
)
self
.
_evgen
=
await
self
.
_server
.
get_event_generator
(
self
.
evtype
,
self
.
_state_machine_node
)
async
def
change_state
(
self
,
state
:
State
,
transition
:
Transition
=
None
,
event_msg
:
Union
[
str
,
ua
.
LocalizedText
]
=
None
,
severity
:
int
=
500
):
...
...
asyncua/common/structures.py
View file @
d5bacbc8
...
...
@@ -228,10 +228,10 @@ from asyncua import ua
async
def
load_type_definitions
(
server
,
nodes
=
None
):
"""
Download xml from given variable node defining custom structures.
If no node is given, attemps to import variables from all nodes under
If no node is given, attemp
t
s to import variables from all nodes under
"0:OPC Binary"
the code is generated and imported on the fly. If you know the structures
are not going to be modified it might be inter
r
esting to copy the generated files
are not going to be modified it might be interesting to copy the generated files
and include them in you code
"""
if
nodes
is
None
:
...
...
@@ -251,7 +251,7 @@ async def load_type_definitions(server, nodes=None):
generator
.
get_python_classes
(
structs_dict
)
# same but using a file that is imported. This can be useful for debugging library
# name = node.read_browse_name().Name
# Make sure structure names do not contain charaters that cannot be used in Python class file names
# Make sure structure names do not contain chara
c
ters that cannot be used in Python class file names
# name = clean_name(name)
# name = "structures_" + node.read_browse_name().Name
# generator.save_and_import(name + ".py", append_to=structs_dict)
...
...
@@ -268,7 +268,7 @@ async def load_type_definitions(server, nodes=None):
continue
nodeid
=
ref_desc_list
[
0
].
NodeId
ua
.
register_extension_object
(
name
,
nodeid
,
structs_dict
[
name
])
# save the typeid if user want to create static file for type definit
n
ion
# save the typeid if user want to create static file for type definition
generator
.
set_typeid
(
name
,
nodeid
.
to_string
())
for
key
,
val
in
structs_dict
.
items
():
...
...
asyncua/common/structures104.py
View file @
d5bacbc8
...
...
@@ -120,7 +120,7 @@ async def new_enum(
def
clean_name
(
name
):
"""
Remove characters that might be present in OPC UA structures
but cannot be part of
of
Python class names
but cannot be part of Python class names
"""
if
keyword
.
iskeyword
(
name
):
return
name
+
"_"
...
...
@@ -383,7 +383,7 @@ async def _recursive_parse_basedatatypes(server, base_node, parent_datatype, new
for desc in await base_node.get_children_descriptions(refs=ua.ObjectIds.HasSubtype):
name = clean_name(desc.BrowseName.Name)
if parent_datatype not in '
Number
':
# Don'
t
insert
Number
alias
,
they
should
be
al
lready
insert
because
they
have
to
be
basetypes
al
lready
# Don'
t
insert
Number
alias
,
they
should
be
al
ready
insert
because
they
have
to
be
basetypes
a
lready
if
not
hasattr
(
ua
,
name
):
env
=
make_basetype_code
(
name
,
parent_datatype
)
ua
.
register_basetype
(
name
,
desc
.
NodeId
,
env
[
name
])
...
...
@@ -421,7 +421,7 @@ async def _load_base_datatypes(server: Union["Server", "Client"]) -> Any:
async
def
load_data_type_definitions
(
server
:
Union
[
"Server"
,
"Client"
],
base_node
:
Node
=
None
,
overwrite_existing
=
False
)
->
Dict
:
"""
Read DataTypeDefi
tion attribute on all Structure and Enumeration
defined
Read DataTypeDefi
nition attribute on all Structure and Enumeration
defined
on server and generate Python objects in ua namespace to be used to talk with server
"""
new_objects
=
await
_load_base_datatypes
(
server
)
# we need to load all basedatatypes alias first
...
...
@@ -510,7 +510,7 @@ async def load_enums(server: Union["Server", "Client"], base_node: Node = None,
name
=
clean_name
(
desc
.
BrowseName
.
Name
)
if
hasattr
(
ua
,
name
):
continue
logger
.
info
(
"Registring Enum %s %s OptionSet=%s"
,
desc
.
NodeId
,
name
,
option_set
)
logger
.
info
(
"Regist
e
ring Enum %s %s OptionSet=%s"
,
desc
.
NodeId
,
name
,
option_set
)
edef
=
await
_read_data_type_definition
(
server
,
desc
)
if
not
edef
:
continue
...
...
asyncua/common/ua_utils.py
View file @
d5bacbc8
"""
Useful
l method
and classes not belonging anywhere and depending on asyncua library
Useful
methods
and classes not belonging anywhere and depending on asyncua library
"""
import
uuid
...
...
@@ -16,7 +16,7 @@ logger = logging.getLogger('__name__')
def
value_to_datavalue
(
val
,
varianttype
=
None
):
"""
convert anyting to a DataValue using varianttype
convert anyt
h
ing to a DataValue using varianttype
"""
if
isinstance
(
val
,
ua
.
DataValue
):
return
val
...
...
@@ -31,7 +31,7 @@ def val_to_string(val, truncate=False):
which should be easy to understand for human
easy to modify, and not too hard to parse back ....not easy
meant for UI or command lines
if truncate is true then huge strings or bytes are tuncated
if truncate is true then huge strings or bytes are t
r
uncated
"""
if
isinstance
(
val
,
(
list
,
tuple
)):
...
...
@@ -172,7 +172,7 @@ async def get_node_subtypes(node, nodes=None):
async
def
get_node_supertypes
(
node
,
includeitself
=
False
,
skipbase
=
True
):
"""
return get all subtype parents of node recursive
:param node: can be a ua.Node or ua.NodeId
:param node: can be a
n
ua.Node or ua.NodeId
:param includeitself: include also node to the list
:param skipbase don't include the toplevel one
:returns list of ua.Node, top parent first
...
...
@@ -216,7 +216,7 @@ async def is_child_present(node, browsename):
return if a browsename is present a child from the provide node
:param node: node wherein to find the browsename
:param browsename: browsename to search
:returns return
e
True if the browsename is present else False
:returns return
s
True if the browsename is present else False
"""
child_descs
=
await
node
.
get_children_descriptions
()
for
child_desc
in
child_descs
:
...
...
@@ -232,7 +232,7 @@ async def data_type_to_variant_type(dtype_node):
"""
base
=
await
get_base_data_type
(
dtype_node
)
if
base
.
nodeid
.
Identifier
==
29
:
# we have an enumeration, value is a Int32
# we have an enumeration, value is a
n
Int32
return
ua
.
VariantType
.
Int32
elif
base
.
nodeid
.
Identifier
in
[
24
,
26
,
27
,
28
]:
# BaseDataType, Number, Integer, UInteger -> Variant
...
...
@@ -277,10 +277,10 @@ async def get_nodes_of_namespace(server, namespaces=None):
elif
isinstance
(
namespaces
,
(
str
,
int
)):
namespaces
=
[
namespaces
]
# make sure all namespace are indexes (if needed convert strings to indexes)
# make sure all namespace are indexes (if needed
,
convert strings to indexes)
namespace_indexes
=
[
n
if
isinstance
(
n
,
int
)
else
ns_available
.
index
(
n
)
for
n
in
namespaces
]
# filter node
is based on the provide
namespaces and convert the nodeid to a node
# filter node
is based on the provided
namespaces and convert the nodeid to a node
nodes
=
[
server
.
get_node
(
nodeid
)
for
nodeid
in
server
.
iserver
.
aspace
.
keys
()
if
nodeid
.
NamespaceIndex
!=
0
and
nodeid
.
NamespaceIndex
in
namespace_indexes
...
...
@@ -297,7 +297,7 @@ def get_default_value(uatype):
def
data_type_to_string
(
dtype
):
# we could just display browse name of node but it requires a query
# we could just display browse name of node
,
but it requires a query
if
dtype
.
NamespaceIndex
==
0
and
dtype
.
Identifier
in
ua
.
ObjectIdNames
:
string
=
ua
.
ObjectIdNames
[
dtype
.
Identifier
]
else
:
...
...
asyncua/common/xmlexporter.py
View file @
d5bacbc8
...
...
@@ -322,7 +322,7 @@ class XmlExporter:
elif
isinstance
(
sdef
,
ua
.
EnumDefinition
):
self
.
_enum_fields_to_etree
(
sdef_el
,
sdef
)
else
:
self
.
logger
.
warning
(
"Unknown DataTypeSpecification elemnt: %s"
,
sdef
)
self
.
logger
.
warning
(
"Unknown DataTypeSpecification elem
e
nt: %s"
,
sdef
)
def
_structure_fields_to_etree
(
self
,
sdef_el
,
sdef
):
for
field
in
sdef
.
Fields
:
...
...
@@ -447,7 +447,7 @@ class XmlExporter:
if
isinstance
(
val
,
(
list
,
tuple
)):
if
dtype
.
NamespaceIndex
==
0
and
dtype
.
Identifier
<=
21
:
elname
=
"uax:ListOf"
+
type_name
else
:
# this is an exten
t
ionObject:
else
:
# this is an exten
s
ionObject:
elname
=
"uax:ListOfExtensionObject"
list_el
=
Et
.
SubElement
(
el
,
elname
)
...
...
@@ -489,9 +489,9 @@ class XmlExporter:
async
def
_all_fields_to_etree
(
self
,
struct_el
,
val
):
# TODO: adding the 'ua' module to the globals to resolve the type hints might not be enough.
# its possible that the type annotations also refere to classes defined in other modules.
# it
i
s possible that the type annotations also refere to classes defined in other modules.
for
field
in
fields_with_resolved_types
(
val
,
globalns
=
{
"ua"
:
ua
}):
# FIXME; what happend if we have a custom type which is not part of ObjectIds???
# FIXME; what happen
e
d if we have a custom type which is not part of ObjectIds???
if
field
.
name
==
"Encoding"
:
continue
type_name
=
type_string_from_type
(
field
.
type
)
...
...
asyncua/common/xmlimporter.py
View file @
d5bacbc8
...
...
@@ -21,7 +21,7 @@ class XmlImporter:
def
__init__
(
self
,
server
,
strict_mode
=
True
):
'''
strict_mode: stop on a
error, if False only a
error message is logged,
strict_mode: stop on a
n error, if False only an
error message is logged,
but the import continues
'''
self
.
parser
=
None
...
...
@@ -279,7 +279,7 @@ class XmlImporter:
def
_migrate_ns
(
self
,
obj
:
Union
[
ua
.
NodeId
,
ua
.
QualifiedName
])
->
Union
[
ua
.
NodeId
,
ua
.
QualifiedName
]:
"""
Check if the index of nodeid or browsename given in the xml model file
must be converted to a already existing namespace id based on the files
must be converted to a
n
already existing namespace id based on the files
namespace uri
:returns: NodeId (str)
...
...
asyncua/common/xmlparser.py
View file @
d5bacbc8
...
...
@@ -352,8 +352,8 @@ class XMLParser:
def
_parse_list_of_extension_object
(
self
,
el
):
"""
Parse a uax:ListOfExtensionObject Value
Return a
n
list of ExtObj
Parse a
n
uax:ListOfExtensionObject Value
Return a list of ExtObj
"""
value
=
[]
for
extension_object
in
el
:
...
...
asyncua/crypto/permission_rules.py
View file @
d5bacbc8
...
...
@@ -66,4 +66,3 @@ class SimpleRoleRuleset(PermissionRuleset):
return
True
else
:
return
False
asyncua/crypto/security_policies.py
View file @
d5bacbc8
...
...
@@ -538,7 +538,7 @@ class SecurityPolicyBasic128Rsa15(SecurityPolicy):
- CertificateSignatureAlgorithm - Sha1
If a certificate or any certificate in the chain is not signed with
a hash that is Sha1 or stronger th
e
n the certificate shall be rejected.
a hash that is Sha1 or stronger th
a
n the certificate shall be rejected.
"""
URI
=
"http://opcfoundation.org/UA/SecurityPolicy#Basic128Rsa15"
...
...
@@ -626,7 +626,7 @@ class SecurityPolicyBasic256(SecurityPolicy):
- CertificateSignatureAlgorithm - Sha1
If a certificate or any certificate in the chain is not signed with
a hash that is Sha1 or stronger th
e
n the certificate shall be rejected.
a hash that is Sha1 or stronger th
a
n the certificate shall be rejected.
"""
URI
=
"http://opcfoundation.org/UA/SecurityPolicy#Basic256"
...
...
asyncua/server/internal_server.py
View file @
d5bacbc8
...
...
@@ -49,7 +49,7 @@ class InternalServer:
self
.
endpoints
=
[]
self
.
_channel_id_counter
=
5
self
.
allow_remote_admin
=
True
self
.
disabled_clock
=
False
# for debugging we may want to disable clock that writes too much in log
self
.
disabled_clock
=
False
# for debugging
,
we may want to disable clock that writes too much in log
self
.
_known_servers
=
{}
# used if we are a discovery server
self
.
certificate
=
None
self
.
private_key
=
None
...
...
@@ -297,7 +297,7 @@ class InternalServer:
async
def
write_attribute_value
(
self
,
nodeid
,
datavalue
,
attr
=
ua
.
AttributeIds
.
Value
):
"""
directly write datavalue to the Attribute, bypassing some checks and structure creation
directly write datavalue to the Attribute, bypassing some checks and structure creation
,
so it is a little faster
"""
await
self
.
aspace
.
write_attribute_value
(
nodeid
,
attr
,
datavalue
)
...
...
asyncua/server/server.py
View file @
d5bacbc8
...
...
@@ -52,11 +52,11 @@ class Server:
All methods are threadsafe
If you need more flexibility you call directly the Ua Service methods
on the iserver
or iserver.isession object members.
on the iserver or iserver.isession object members.
During startup the standard address space will be constructed, which may be
time-consuming when running a server on a less powerful device (e.g. a
Raspberry Pi). In order to improve startup performance, a optional path to a
Raspberry Pi). In order to improve startup performance, a
n
optional path to a
cache file can be passed to the server constructor.
If the parameter is defined, the address space will be loaded from the
cache file or the file will be created if it does not exist yet.
...
...
@@ -106,7 +106,7 @@ class Server:
self
.
_permission_ruleset
=
None
self
.
_policyIDs
=
[
"Anonymous"
,
"Basic256Sha256"
,
"Username"
,
"Aes128Sha256RsaOaep"
]
self
.
certificate
=
None
# Use acce
c
table limits
# Use acce
p
table limits
buffer_sz
=
65535
max_msg_sz
=
100
*
1024
*
1024
# 100mb
self
.
limits
=
TransportLimits
(
...
...
@@ -234,7 +234,7 @@ class Server:
async
def
set_application_uri
(
self
,
uri
:
str
):
"""
Set application/server URI.
This uri is supposed to be unique. If you inten
t
to register
This uri is supposed to be unique. If you inten
d
to register
your server to a discovery server, it really should be unique in
your system!
default is : "urn:freeopcua:python:server"
...
...
@@ -728,7 +728,7 @@ class Server:
async
def
write_attribute_value
(
self
,
nodeid
,
datavalue
,
attr
=
ua
.
AttributeIds
.
Value
):
"""
directly write datavalue to the Attribute, bypas
ing some checks and structure creation
directly write datavalue to the Attribute, bypas
sing some checks and structure creation,
so it is a little faster
"""
return
await
self
.
iserver
.
write_attribute_value
(
nodeid
,
datavalue
,
attr
)
...
...
asyncua/server/uaprocessor.py
View file @
d5bacbc8
...
...
@@ -259,7 +259,7 @@ class UaProcessor:
self
.
send_response
(
requesthdr
.
RequestHandle
,
seqhdr
,
response
)
return
False
else
:
# All services that requ
ere a
active session
# All services that requ
ire an
active session
if
not
self
.
session
:
_logger
.
info
(
"Request service that need a session (%s)"
,
user
)
raise
ServiceError
(
ua
.
StatusCodes
.
BadSessionIdInvalid
)
...
...
asyncua/tools.py
View file @
d5bacbc8
...
...
@@ -602,7 +602,7 @@ async def _uaserver():
description
=
"Run an example OPC-UA server. By importing xml definition and using uawrite "
" command line, it is even possible to expose real data using this server"
)
# we set
up a server, this is a bit different from other tool
so we do not reuse common arguments
# we set
up a server, this is a bit different from other tool,
so we do not reuse common arguments
parser
.
add_argument
(
"-u"
,
"--url"
,
...
...
asyncua/ua/ua_binary.py
View file @
d5bacbc8
...
...
@@ -278,14 +278,14 @@ def create_dataclass_serializer(dataclazz):
"""Given a dataclass, return a function that serializes instances of this dataclass"""
data_fields
=
fields
(
dataclazz
)
# TODO: adding the 'ua' module to the globals to resolve the type hints might not be enough.
# its possible that the type annotations also refere to classes defined in other modules.
# it
i
s possible that the type annotations also refere to classes defined in other modules.
resolved_fieldtypes
=
typing
.
get_type_hints
(
dataclazz
,
{
'ua'
:
ua
})
for
f
in
data_fields
:
f
.
type
=
resolved_fieldtypes
[
f
.
name
]
if
issubclass
(
dataclazz
,
ua
.
UaUnion
):
# Union is a class with Encoding and Value field
# the value
is depended of
encoding
# the value
depends on
encoding
encoding_funcs
=
[
field_serializer
(
t
,
dataclazz
)
for
t
in
dataclazz
.
_union_types
]
def
union_serialize
(
obj
):
...
...
asyncua/ua/uaprotocol_hand.py
View file @
d5bacbc8
...
...
@@ -13,9 +13,9 @@ OPC_TCP_SCHEME = 'opc.tcp'
@
dataclass
class
Hello
:
ProtocolVersion
:
uatypes
.
UInt32
=
0
# the following values couldbe set to 0 (meaning no limits)
# unfortuna
l
tely many servers do not support it
# even newer version of prosys
are broken
# the following values could
be set to 0 (meaning no limits)
# unfortunately many servers do not support it
# even newer version of prosys
is broken,
# so we set then to a high value known to work most places
ReceiveBufferSize
:
uatypes
.
UInt32
=
2
**
31
-
1
SendBufferSize
:
uatypes
.
UInt32
=
2
**
31
-
1
...
...
@@ -111,7 +111,7 @@ class SequenceHeader:
class
CryptographyNone
:
"""
Base class for symmetric/asymmetric cryp
r
ography
Base class for symmetric/asymmetric cryp
t
ography
"""
def
__init__
(
self
):
pass
...
...
@@ -275,7 +275,7 @@ class ReferenceTypeAttributes(auto.ReferenceTypeAttributes):
# FIXME: changes in that class donnot seem to be part of spec as of 1.04
#not sure what the spec expect, maybe DataTypeDefinition must be set using an extra call...
#
not sure what the spec expect, maybe DataTypeDefinition must be set using an extra call...
# maybe it will be part of spec in 1.05??? no ideas
@
dataclass
class
DataTypeAttributes
(
auto
.
DataTypeAttributes
):
...
...
@@ -285,7 +285,7 @@ class DataTypeAttributes(auto.DataTypeAttributes):
self
.
SpecifiedAttributes
=
ana
.
DisplayName
|
ana
.
Description
|
ana
.
WriteMask
|
ana
.
UserWriteMask
|
ana
.
IsAbstract
|
ana
.
DataTypeDefinition
# we now need to register DataTypeAttributes since we added a new attri
t
bute
# we now need to register DataTypeAttributes since we added a new attribute
nid
=
uatypes
.
FourByteNodeId
(
auto
.
ObjectIds
.
DataTypeAttributes_Encoding_DefaultBinary
)
uatypes
.
extension_objects_by_typeid
[
nid
]
=
DataTypeAttributes
uatypes
.
extension_object_typeids
[
'DataTypeAttributes'
]
=
nid
...
...
asyncua/ua/uatypes.py
View file @
d5bacbc8
...
...
@@ -149,7 +149,7 @@ class Null: # Null(NoneType) is not supported in Python
pass
class
String
:
# Passing None as arg will result in unepected behaviour so disabling
class
String
:
# Passing None as arg will result in une
x
pected behaviour so disabling
pass
...
...
@@ -206,7 +206,7 @@ class ValueRank(IntEnum):
"""
Defines dimensions of a variable.
This enum does not support all cases since ValueRank support any n>0
but since it is an IntEnum it can be replace by a normal int
but since it is an IntEnum it can be replace
d
by a normal int
"""
ScalarOrOneDimension
=
-
3
...
...
@@ -405,7 +405,7 @@ class NodeId:
Args:
identifier: The identifier might be an int, a string, bytes or a Guid
namespaceidx(int): The index of the namespace
nodeidtype(NodeIdType): The type of the nodeid if it cannot be guess or you want something
nodeidtype(NodeIdType): The type of the nodeid if it cannot be guess
ed,
or you want something
special like twobyte nodeid or fourbytenodeid
...
...
@@ -644,10 +644,10 @@ class QualifiedName:
object
.
__setattr__
(
self
,
"NamespaceIndex"
,
NamespaceIndex
)
if
isinstance
(
self
.
NamespaceIndex
,
str
)
and
isinstance
(
self
.
Name
,
int
):
# originally the order or argument was inversed, try to support it
logger
.
warning
(
"QualifiedName are str, int, while int, str is expected, swit
hc
ing"
)
logger
.
warning
(
"QualifiedName are str, int, while int, str is expected, swit
ch
ing"
)
if
not
isinstance
(
self
.
NamespaceIndex
,
int
)
or
not
isinstance
(
self
.
Name
,
(
str
,
type
(
None
))):
raise
ValueError
(
f"QualifiedName constructor
e
args have wrong types,
{
self
}
"
)
raise
ValueError
(
f"QualifiedName constructor args have wrong types,
{
self
}
"
)
def
to_string
(
self
):
return
f"
{
self
.
NamespaceIndex
}
:
{
self
.
Name
}
"
...
...
@@ -677,7 +677,7 @@ class LocalizedText:
Text
:
Optional
[
String
]
=
None
def
__init__
(
self
,
Text
=
None
,
Locale
=
None
):
# need to write init method since args ar inverted in original implementat
a
ion
# need to write init method since args ar inverted in original implementation
object
.
__setattr__
(
self
,
"Text"
,
Text
)
object
.
__setattr__
(
self
,
"Locale"
,
Locale
)
...
...
@@ -820,7 +820,7 @@ class Variant:
"""
Create an OPC-UA Variant object.
if no argument a Null Variant is created.
if not variant type is given, attemps to guess type from python type
if not variant type is given, attemp
t
s to guess type from python type
if a variant is given as value, the new objects becomes a copy of the argument
:ivar Value:
...
...
@@ -828,9 +828,9 @@ class Variant:
:ivar VariantType:
:vartype VariantType: VariantType
:ivar Dimension:
:vartype Dimensions: The length of each dimension
s
. Make the variant a Matrix
:vartype Dimensions: The length of each dimension. Make the variant a Matrix
:ivar is_array:
:vartype is_array: If the variant is an array. Always True if Dimension is specifi
ci
ed
:vartype is_array: If the variant is an array. Always True if Dimension is specified
"""
# FIXME: typing is wrong here
...
...
@@ -965,7 +965,7 @@ def get_shape(mylist):
return dims
# For completness, these datatypes are abstract!
# For complet
e
ness, these datatypes are abstract!
# If they are used in structs, abstract types are either Variant or ExtensionObjects.
# If they only contain basic types (int16, float, double..) they are Variants
UInteger = Variant
...
...
@@ -1087,7 +1087,7 @@ def get_default_value(vtype):
if vtype == VariantType.Guid:
return uuid.uuid4()
if vtype == VariantType.XmlElement:
return None # Not sure this is correct
return None # Not sure
if
this is correct
if vtype == VariantType.NodeId:
return NodeId()
if vtype == VariantType.ExpandedNodeId:
...
...
@@ -1114,9 +1114,9 @@ basetype_datatypes = {}
# register of alias of basetypes
def register_basetype(name, nodeid, class_type):
"""
Register a new al
l
ias of basetypes for automatic decoding and make them available in ua module
Register a new alias of basetypes for automatic decoding and make them available in ua module
"""
logger.info("
registring
new
basetype
alias
:
%
s
%
s
%
s
", name, nodeid, class_type)
logger.info("
regist
e
ring
new
basetype
alias
:
%
s
%
s
%
s
", name, nodeid, class_type)
basetype_by_datatype[nodeid] = name
basetype_datatypes[class_type] = nodeid
import asyncua.ua
...
...
@@ -1133,7 +1133,7 @@ def register_enum(name, nodeid, class_type):
"""
Register a new enum for automatic decoding and make them available in ua module
"""
logger.info("
registring
new
enum
:
%
s
%
s
%
s
", name, nodeid, class_type)
logger.info("
regist
e
ring
new
enum
:
%
s
%
s
%
s
", name, nodeid, class_type)
enums_by_datatype[nodeid] = class_type
enums_datatypes[class_type] = nodeid
import asyncua.ua
...
...
@@ -1141,7 +1141,7 @@ def register_enum(name, nodeid, class_type):
setattr(asyncua.ua, name, class_type)
# These diction
n
aries are used to register extensions classes for automatic
# These dictionaries are used to register extensions classes for automatic
# decoding and encoding
extension_objects_by_datatype = {} # Dict[Datatype, type]
extension_objects_by_typeid = {} # Dict[EncodingId, type]
...
...
@@ -1154,7 +1154,7 @@ def register_extension_object(name, encoding_nodeid, class_type, datatype_nodeid
Register a new extension object for automatic decoding and make them available in ua module
"""
logger.info(
"
registring
new
extension
object
:
%
s
%
s
%
s
%
s
",
"
regist
e
ring
new
extension
object
:
%
s
%
s
%
s
%
s
",
name,
encoding_nodeid,
class_type,
...
...
examples/server-limits.py
View file @
d5bacbc8
...
...
@@ -24,12 +24,12 @@ async def main():
await
server
.
init
()
server
.
set_endpoint
(
"opc.tcp://0.0.0.0:4840/freeopcua/server/"
)
# setup our own namespace, not really necessary but should as spec
# set
up our own namespace, not really necessary but should as spec
uri
=
"http://examples.freeopcua.github.io"
idx
=
await
server
.
register_namespace
(
uri
)
# populating our address space
# setup a variable far too big for our limits
# set
up a variable far too big for our limits
test_string
=
b'a'
*
(
100
*
1024
*
1024
)
test_string
=
b'a'
*
100
*
1024
print
(
"LENGTH VAR"
,
len
(
test_string
))
...
...
examples/server-methods.py
View file @
d5bacbc8
...
...
@@ -53,14 +53,14 @@ async def main():
# logger = logging.getLogger("asyncua.subscription_service")
# logger.setLevel(logging.DEBUG)
# now setup our server
# now set
up our server
server
=
Server
()
await
server
.
init
()
# server.set_endpoint("opc.tcp://localhost:4840/freeopcua/server/")
server
.
set_endpoint
(
"opc.tcp://0.0.0.0:4840/freeopcua/server/"
)
server
.
set_server_name
(
"FreeOpcUa Example Server"
)
# setup our own namespace
# set
up our own namespace
uri
=
"http://examples.freeopcua.github.io"
idx
=
await
server
.
register_namespace
(
uri
)
...
...
examples/server-minimal.py
View file @
d5bacbc8
...
...
@@ -17,7 +17,7 @@ async def main():
await
server
.
init
()
server
.
set_endpoint
(
"opc.tcp://0.0.0.0:4840/freeopcua/server/"
)
# setup our own namespace, not really necessary but should as spec
# set
up our own namespace, not really necessary but should as spec
uri
=
"http://examples.freeopcua.github.io"
idx
=
await
server
.
register_namespace
(
uri
)
...
...
examples/server-ua-python-mirror.py
View file @
d5bacbc8
...
...
@@ -11,7 +11,7 @@ from asyncua import ua, Server
# The advantage of this is that the software can be designed in a tool like UA Modeler. Then with minimal setup, a
# python program will import the XML and mirror all the objects in the software design. After this mirroring is achieved
# the user can focus on programming in python knowing that all
all
data from UA clients will reach the python object,
# the user can focus on programming in python knowing that all data from UA clients will reach the python object,
# and all data that needs to be output to the server can be published from the python object.
#
# Be aware that subscription calls are asynchronous.
...
...
@@ -72,7 +72,7 @@ class UaObject(object):
class
MyObj
(
UaObject
):
"""
Definition of OPC UA object which represents a object to be mirrored in python
Definition of OPC UA object which represents a
n
object to be mirrored in python
This class mirrors it's UA counterpart and semi-configures itself according to the UA model (generally from XML)
"""
def
__init__
(
self
,
asyncua_server
,
ua_node
):
...
...
@@ -102,7 +102,7 @@ if __name__ == "__main__":
server
=
Server
()
server
.
set_endpoint
(
"opc.tcp://0.0.0.0:4840/freeopcua/server/"
)
# setup our own namespace, not really necessary but should as spec
# set
up our own namespace, not really necessary but should as spec
uri
=
"http://examples.freeopcua.github.io"
idx
=
server
.
register_namespace
(
uri
)
...
...
examples/server-virtual-network.py
View file @
d5bacbc8
...
...
@@ -28,7 +28,7 @@ async def main():
await
server
.
init
()
server
.
set_endpoint
(
'opc.tcp://example-endpoint.freeopcua.github.com:32000/freeopcua/server/'
)
# setup our own namespace, not really necessary but should as spec
# set
up our own namespace, not really necessary but should as spec
uri
=
'http://examples.freeopcua.github.io'
idx
=
await
server
.
register_namespace
(
uri
)
...
...
examples/statemachine-example.py
View file @
d5bacbc8
...
...
@@ -13,7 +13,7 @@ if __name__ == "__main__":
server
.
set_endpoint
(
"opc.tcp://0.0.0.0:4840/freeopcua/server/"
)
idx
=
await
server
.
register_namespace
(
"http://examples.freeopcua.github.io"
)
# get a instance of the StateMachine-Class def "__init__(self, server=None, parent=None, idx=None, name=None):"
# get a
n
instance of the StateMachine-Class def "__init__(self, server=None, parent=None, idx=None, name=None):"
mystatemachine
=
StateMachine
(
server
,
server
.
nodes
.
objects
,
idx
,
"StateMachine"
)
# call statemachine.install() to instantiate the statemachinetype (with or without optional nodes)
await
mystatemachine
.
install
(
optionals
=
True
)
...
...
@@ -22,7 +22,7 @@ if __name__ == "__main__":
# if the state node already exist for example from xml model you can assign it here: node=<StateNode>
state1
=
State
(
"State-Id-1"
,
"Idle"
,
1
)
# adds the state (StateType) to the statemachine childs - this is optional!
await
mystatemachine
.
add_state
(
state1
,
state_type
=
ua
.
NodeId
(
2309
,
0
))
#this is a init state -> InitialStateType: ua.NodeId(2309, 0)
await
mystatemachine
.
add_state
(
state1
,
state_type
=
ua
.
NodeId
(
2309
,
0
))
#this is a
n
init state -> InitialStateType: ua.NodeId(2309, 0)
state2
=
State
(
"State-Id-2"
,
"Loading"
,
2
)
await
mystatemachine
.
add_state
(
state2
)
state3
=
State
(
"State-Id-3"
,
"Initializing"
,
3
)
...
...
@@ -32,7 +32,7 @@ if __name__ == "__main__":
state5
=
State
(
"State-Id-5"
,
"Finished"
,
5
)
await
mystatemachine
.
add_state
(
state5
)
# set
up your transition helperclass
# set
up your transition helperclass
# if the transition node already exist for example from xml model you can assign it here: node=<TransitionNode>
trans1
=
Transition
(
"Transition-Id-1"
,
"to Idle"
,
1
)
# adds the transition (TransitionType) to the statemachine childs - this is optional!
...
...
examples/sync/client-example.py
View file @
d5bacbc8
...
...
@@ -59,7 +59,7 @@ if __name__ == "__main__":
#var.write_value(ua.Variant([23], ua.VariantType.Int64)) #set node value using explicit data type
#var.write_value(3.9) # set node value using implicit data type
# gett
t
ing our namespace idx
# getting our namespace idx
uri
=
"http://examples.freeopcua.github.io"
idx
=
client
.
get_namespace_index
(
uri
)
...
...
examples/sync/client_to_prosys.py
View file @
d5bacbc8
...
...
@@ -24,8 +24,8 @@ if __name__ == "__main__":
with
Client
(
"opc.tcp://localhost:53530/OPCUA/SimulationServer/"
)
as
client
:
root
=
client
.
nodes
.
root
print
(
"Root is"
,
root
)
print
(
"child
s
of root are: "
,
root
.
get_children
())
print
(
"child
ren
of root are: "
,
root
.
get_children
())
print
(
"name of root is"
,
root
.
read_browse_name
())
objects
=
client
.
nodes
.
objects
print
(
"child
s
og objects are: "
,
objects
.
get_children
())
print
(
"child
ren
og objects are: "
,
objects
.
get_children
())
embed
()
examples/sync/server-example.py
View file @
d5bacbc8
...
...
@@ -83,7 +83,7 @@ if __name__ == "__main__":
#logger = logging.getLogger("opcua.uaprocessor")
# logger.setLevel(logging.DEBUG)
with
ThreadLoop
()
as
tloop
:
# now setup our server
# now set
up our server
server
=
Server
(
tloop
=
tloop
)
#server.disable_clock()
#server.set_endpoint("opc.tcp://localhost:4840/freeopcua/server/")
...
...
@@ -95,7 +95,7 @@ if __name__ == "__main__":
ua
.
SecurityPolicyType
.
Basic256Sha256_SignAndEncrypt
,
ua
.
SecurityPolicyType
.
Basic256Sha256_Sign
])
# setup our own namespace
# set
up our own namespace
uri
=
"http://examples.freeopcua.github.io"
idx
=
server
.
register_namespace
(
uri
)
print
(
"IDX"
,
idx
)
...
...
@@ -142,7 +142,7 @@ if __name__ == "__main__":
# starting!
with
server
:
print
(
"Available loggers are: "
,
logging
.
Logger
.
manager
.
loggerDict
.
keys
())
vup
=
VarUpdater
(
mysin
)
# just
a stupide class update
a variable
vup
=
VarUpdater
(
mysin
)
# just
a stupid class updating
a variable
vup
.
start
()
# enable following if you want to subscribe to nodes on server side
...
...
@@ -151,12 +151,12 @@ if __name__ == "__main__":
#handle = sub.subscribe_data_change(myvar)
# trigger event, all subscribed clients wil receive it
var
=
myarrayvar
.
read_value
()
# return a ref to value in db server side! not a copy!
var
=
copy
.
copy
(
var
)
# WARNING: we need to copy before writ
ting again
otherwise no data change event will be generated
var
=
copy
.
copy
(
var
)
# WARNING: we need to copy before writ
ing again,
otherwise no data change event will be generated
var
.
append
(
9.3
)
myarrayvar
.
write_value
(
var
)
mydevice_var
.
write_value
(
"Running"
)
myevgen
.
trigger
(
message
=
"This is BaseEvent"
)
server
.
write_attribute_value
(
myvar
.
nodeid
,
ua
.
DataValue
(
9.9
))
# Server side write method which is a b
u
t faster than using write
server
.
write_attribute_value
(
myvar
.
nodeid
,
ua
.
DataValue
(
9.9
))
# Server side write method which is a b
i
t faster than using write
embed
()
vup
.
stop
()
examples/sync/server-minimal.py
View file @
d5bacbc8
...
...
@@ -7,11 +7,11 @@ from asyncua.sync import Server
if
__name__
==
"__main__"
:
# setup our server
# set
up our server
server
=
Server
()
server
.
set_endpoint
(
"opc.tcp://0.0.0.0:4840/freeopcua/server/"
)
# setup our own namespace, not really necessary but should as spec
# set
up our own namespace, not really necessary but should as spec
uri
=
"http://examples.freeopcua.github.io"
idx
=
server
.
register_namespace
(
uri
)
...
...
@@ -30,5 +30,5 @@ if __name__ == "__main__":
count
+=
0.1
myvar
.
write_value
(
count
)
finally
:
#close connection, remove sub
cs
riptions, etc
#close connection, remove sub
sc
riptions, etc
server
.
stop
()
release.py
View file @
d5bacbc8
...
...
@@ -21,7 +21,7 @@ def bump_version():
def
release
():
v
=
bump_version
()
ans
=
input
(
"version bumped, commiting?(Y/n)"
)
ans
=
input
(
"version bumped, commit
t
ing?(Y/n)"
)
if
ans
in
(
""
,
"y"
,
"yes"
):
os
.
system
(
"git add setup.py"
)
os
.
system
(
f"git commit -m 'new release v
{
v
}
'"
)
...
...
schemas/generate_model_from_nodeset.py
View file @
d5bacbc8
...
...
@@ -13,7 +13,7 @@ _logger = getLogger(__name__)
IgnoredEnums
=
[]
IgnoredStructs
=
[]
# by default
we split requests and respon
s in header and parameters, but some are so simple we do not split them
# by default
, we split requests and response
s in header and parameters, but some are so simple we do not split them
NoSplitStruct
=
[
"GetEndpointsResponse"
,
"CloseSessionRequest"
,
...
...
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