Skip to content

Commit e6d9739

Browse files
committed
[device] Make data access read-only to avoid copy
1 parent a26a5fb commit e6d9739

File tree

3 files changed

+66
-18
lines changed

3 files changed

+66
-18
lines changed
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#!/usr/bin/env python3
2+
# -*- coding: utf-8 -*-
3+
4+
import copy
5+
6+
def copy_keys(src, *keys):
7+
dest = {};
8+
for key in keys:
9+
conv = lambda o: o
10+
if isinstance(key, tuple):
11+
key, conv = key
12+
if key in src:
13+
dest[key] = conv(src[key])
14+
return dest
15+
16+
def copy_deep(obj):
17+
return copy.deepcopy(obj)
18+
19+
20+
class ReadOnlyList(list):
21+
def __readonly__(self, *args, **kwargs):
22+
raise RuntimeError("You are trying to modify read-only DeviceFile data!")
23+
pop = __readonly__
24+
remove = __readonly__
25+
append = __readonly__
26+
clear = __readonly__
27+
extend = __readonly__
28+
insert = __readonly__
29+
reverse = __readonly__
30+
__copy__ = list.copy
31+
__deepcopy__ = copy._deepcopy_dispatch.get(list)
32+
del __readonly__
33+
34+
35+
class ReadOnlyDict(dict):
36+
def __readonly__(self, *args, **kwargs):
37+
raise RuntimeError("You are trying to modify read-only DeviceFile data!")
38+
__setitem__ = __readonly__
39+
__delitem__ = __readonly__
40+
pop = __readonly__
41+
popitem = __readonly__
42+
clear = __readonly__
43+
update = __readonly__
44+
setdefault = __readonly__
45+
__copy__ = dict.copy
46+
__deepcopy__ = copy._deepcopy_dispatch.get(dict)
47+
del __readonly__
48+
49+
50+
def read_only(obj):
51+
if isinstance(obj, dict):
52+
return ReadOnlyDict(obj)
53+
if isinstance(obj, list):
54+
return ReadOnlyList(obj)
55+
return obj

tools/device/modm_devices/device.py

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,26 +21,19 @@ def __init__(self,
2121
self.partname = identifier.string
2222
self.device_file = device_file
2323

24-
self._properties = None
25-
26-
def __parse_properties(self):
27-
"""
28-
Perform a lazy initialization of the driver property tree.
29-
"""
30-
if self._properties is None:
31-
self._properties = self.device_file.get_properties(self._identifier)
24+
self.__properties = None
3225

3326
@property
34-
def properties(self):
35-
self.__parse_properties()
36-
return copy.deepcopy(self._properties)
27+
def _properties(self):
28+
if self.__properties is None:
29+
self.__properties = self.device_file.get_properties(self._identifier)
30+
return self.__properties
3731

3832
@property
3933
def identifier(self):
40-
return self._identifier.copy()
34+
return self._identifier
4135

4236
def get_all_drivers(self, name):
43-
self.__parse_properties()
4437
parts = name.split(":")
4538
results = []
4639

@@ -58,7 +51,7 @@ def get_all_drivers(self, name):
5851
"The name must contain no or one ':' to "
5952
"separate type and name.".format(name))
6053

61-
return copy.deepcopy(results)
54+
return results
6255

6356
def get_driver(self, name):
6457
results = self.get_all_drivers(name)

tools/device/modm_devices/device_file.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,14 @@
66
# All rights reserved.
77

88
import lxml.etree
9+
import copy
910

1011
from collections import defaultdict
1112

1213
from .device import Device
1314
from .device_identifier import DeviceIdentifier
1415
from .device_identifier import MultiDeviceIdentifier
16+
from .access import read_only
1517

1618
from .exception import ParserException
1719

@@ -65,8 +67,6 @@ def is_valid(node, identifier: DeviceIdentifier):
6567

6668
def get_properties(self, identifier: DeviceIdentifier):
6769
class Converter:
68-
"""
69-
"""
7070
def __init__(self, identifier: DeviceIdentifier):
7171
self.identifier = identifier
7272

@@ -106,15 +106,15 @@ def to_dict(self, t):
106106
raise ParserException("Attribute '{}' cannot be a list!".format(k))
107107
k = k.replace(DeviceFile._PREFIX_ATTRIBUTE, '')
108108
v = v[0]
109-
dk[k] = v
109+
dk[k] = read_only(v)
110110
d = {t.tag: dk}
111111
if list(attrib.keys()) == ['value']:
112112
d[t.tag] = attrib['value']
113113
elif len(attrib):
114114
if any(k in d[t.tag] for k in attrib.keys()):
115115
raise ParserException("Node children are overwriting attribute '{}'!".format(k))
116116
d[t.tag].update(attrib.items())
117-
return d
117+
return read_only({k:read_only(v) for k,v in d.items()})
118118

119119
properties = Converter(identifier).to_dict(self.rootnode.find("device"))
120120
return properties["device"]

0 commit comments

Comments
 (0)