Completed
Push — master ( 175840...68f055 )
by Olivier
03:53 queued 27s
created

EventResult.to_event_fields()   A

Complexity

Conditions 3

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 3
c 1
b 0
f 1
dl 0
loc 13
rs 9.4285
1
from opcua import ua
2
3
4
class EventResult(object):
5
    """
6
    To be sent to clients for every events from server
7
    """
8
9
    def __init__(self):
10
        self.server_handle = None
11
        self.select_clauses = None
12
        self.event_fields = None
13
        self.data_types = {}
14
        # save current attributes
15
        self.internal_properties = list(self.__dict__.keys())[:] + ["internal_properties"]
16
17
    def __str__(self):
18
        return "EventResult({})".format([str(k) + ":" + str(v) for k, v in self.__dict__.items() if k not in self.internal_properties])
19
    __repr__ = __str__
20
21
    def get_event_props_as_fields_dict(self):
22
        """
23
        convert all properties of the EventResult class to a dict of variants
24
        """
25
        field_vars = {}
26
        for key, value in vars(self).items():
27
            if not key.startswith("__") and key not in self.internal_properties:
28
                field_vars[key] = ua.Variant(value, self.data_types[key])
29
        return field_vars
30
31
    @staticmethod
32
    def from_field_dict(fields):
33
        """
34
        Create an Event object from a dict of name and variants
35
        """
36
        result = EventResult()
37
        for k, v in fields.items():
38
            setattr(result, k, v.Value)
39
            result.data_types[k] = v.VariantType
40
        return result
41
42
    def to_event_fields_using_subscription_fields(self, select_clauses):
43
        """
44
        Using a new select_clauses and the original select_clauses
45
        used during subscription, return a field list 
46
        """
47
        fields = []
48
        for sattr in select_clauses:
49
            for idx, o_sattr in enumerate(self.select_clauses):
50
                if sattr.BrowsePath == o_sattr.BrowsePath and sattr.AttributeId == o_sattr.AttributeId:
51
                    fields.append(self.event_fields[idx])
52
                    break
53
        return fields
54
55
    def to_event_fields(self, select_clauses):
56
        """
57
        return a field list using a select clause and the object properties
58
        """
59
        fields = []
60
        for sattr in select_clauses:
61
            if len(sattr.BrowsePath) == 0:
62
                name = sattr.AttributeId.name
63
            else:
64
                name = sattr.BrowsePath[0].Name
65
            field = getattr(self, name)
66
            fields.append(ua.Variant(field, self.data_types[name]))
67
        return fields
68
69
    @staticmethod
70
    def from_event_fields(select_clauses, fields):
71
        """
72
        Instanciate an Event object from a select_clauses and fields 
73
        """
74
        result = EventResult()
75
        result.select_clauses = select_clauses
76
        result.event_fields = fields
77
        for idx, sattr in enumerate(select_clauses):
78
            if len(sattr.BrowsePath) == 0:
79
                name = sattr.AttributeId.name
80
            else:
81
                name = sattr.BrowsePath[0].Name
82
            setattr(result, name, fields[idx].Value)
83
            result.data_types[name] = fields[idx].VariantType
84
        return result
85
86
87
def get_filter_from_event_type(eventtype):
88
    evfilter = ua.EventFilter()
89
    evfilter.SelectClauses = select_clauses_from_evtype(eventtype)
90
    evfilter.WhereClause = where_clause_from_evtype(eventtype)
91
    return evfilter
92
93
94
def select_clauses_from_evtype(evtype):
95
    clauses = []
96
    for prop in get_event_properties_from_type_node(evtype):
97
        op = ua.SimpleAttributeOperand()
98
        op.TypeDefinitionId = evtype.nodeid
99
        op.AttributeId = ua.AttributeIds.Value
100
        op.BrowsePath = [prop.get_browse_name()]
101
        clauses.append(op)
102
    return clauses
103
104
105
def where_clause_from_evtype(evtype):
106
    cf = ua.ContentFilter()
107
    el = ua.ContentFilterElement()
108
    # operands can be ElementOperand, LiteralOperand, AttributeOperand, SimpleAttribute
109
    op = ua.SimpleAttributeOperand()
110
    op.TypeDefinitionId = evtype.nodeid
111
    op.BrowsePath.append(ua.QualifiedName("EventType", 0))
112
    op.AttributeId = ua.AttributeIds.Value
113
    el.FilterOperands.append(op)
114
    for subtypeid in [st.nodeid for st in get_node_subtypes(evtype)]:
115
        op = ua.LiteralOperand()
116
        op.Value = ua.Variant(subtypeid)
117
        el.FilterOperands.append(op)
118
    el.FilterOperator = ua.FilterOperator.InList
119
120
    cf.Elements.append(el)
121
    return cf
122
123
124
def get_node_subtypes(node, nodes=None):
125
    if nodes is None:
126
        nodes = [node]
127
    for child in node.get_children(refs=ua.ObjectIds.HasSubtype):
128
        nodes.append(child)
129
        get_node_subtypes(child, nodes)
130
    return nodes
131
132
133
def get_event_properties_from_type_node(node):
134
    properties = []
135
    curr_node = node
136
137 View Code Duplication
    while True:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
138
        properties.extend(curr_node.get_properties())
139
140
        if curr_node.nodeid.Identifier == ua.ObjectIds.BaseEventType:
141
            break
142
143
        parents = curr_node.get_referenced_nodes(refs=ua.ObjectIds.HasSubtype, direction=ua.BrowseDirection.Inverse, includesubtypes=False)
144
        if len(parents) != 1:  # Something went wrong
145
            return None
146
        curr_node = parents[0]
147
148
    return properties
149
150
151