Skip to content

Commit f687e2d

Browse files
authored
Use with contexts for opens (#356)
1 parent 61294f9 commit f687e2d

File tree

7 files changed

+48
-45
lines changed

7 files changed

+48
-45
lines changed

canopen/objectdictionary/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ def export_od(od, dest:Union[str,TextIO,None]=None, doc_type:Optional[str]=None)
4848
from . import eds
4949
return eds.export_dcf(od, dest)
5050

51+
# If dest is opened in this fn, it should be closed
52+
if type(dest) is str:
53+
dest.close()
54+
5155

5256
def import_od(
5357
source: Union[str, TextIO, None],

canopen/objectdictionary/eds.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,11 @@ def import_eds(source, node_id):
3333
except AttributeError:
3434
# Python 2
3535
eds.readfp(fp)
36-
fp.close()
36+
finally:
37+
# Only close object if opened in this fn
38+
if not hasattr(source, "read"):
39+
fp.close()
40+
3741
od = objectdictionary.ObjectDictionary()
3842

3943
if eds.has_section("FileInfo"):
@@ -181,8 +185,8 @@ def import_from_node(node_id, network):
181185
network.subscribe(0x580 + node_id, sdo_client.on_response)
182186
# Create file like object for Store EDS variable
183187
try:
184-
eds_fp = sdo_client.open(0x1021, 0, "rt")
185-
od = import_eds(eds_fp, node_id)
188+
with sdo_client.open(0x1021, 0, "rt") as eds_fp:
189+
od = import_eds(eds_fp, node_id)
186190
except Exception as e:
187191
logger.error("No object dictionary could be loaded for node %d: %s",
188192
node_id, e)

canopen/sdo/client.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -114,9 +114,9 @@ def upload(self, index: int, subindex: int) -> bytes:
114114
:raises canopen.SdoAbortedError:
115115
When node responds with an error.
116116
"""
117-
fp = self.open(index, subindex, buffering=0)
118-
size = fp.size
119-
data = fp.read()
117+
with self.open(index, subindex, buffering=0) as fp:
118+
size = fp.size
119+
data = fp.read()
120120
if size is None:
121121
# Node did not specify how many bytes to use
122122
# Try to find out using Object Dictionary
@@ -155,10 +155,9 @@ def download(
155155
:raises canopen.SdoAbortedError:
156156
When node responds with an error.
157157
"""
158-
fp = self.open(index, subindex, "wb", buffering=7, size=len(data),
159-
force_segment=force_segment)
160-
fp.write(data)
161-
fp.close()
158+
with self.open(index, subindex, "wb", buffering=7, size=len(data),
159+
force_segment=force_segment) as fp:
160+
fp.write(data)
162161

163162
def open(self, index, subindex=0, mode="rb", encoding="ascii",
164163
buffering=1024, size=None, block_transfer=False, force_segment=False, request_crc_support=True):

doc/sdo.rst

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -72,14 +72,11 @@ Variables can be opened as readable or writable file objects which can be useful
7272
when dealing with large amounts of data::
7373

7474
# Open the Store EDS variable as a file like object
75-
infile = node.sdo[0x1021].open('r', encoding='ascii')
76-
# Open a file for writing to
77-
outfile = open('out.eds', 'w', encoding='ascii')
78-
# Iteratively read lines from node and write to file
79-
outfile.writelines(infile)
80-
# Clean-up
81-
infile.close()
82-
outfile.close()
75+
with node.sdo[0x1021].open('r', encoding='ascii') as infile,
76+
open('out.eds', 'w', encoding='ascii') as outfile:
77+
78+
# Iteratively read lines from node and write to file
79+
outfile.writelines(infile)
8380

8481
Most APIs accepting file objects should also be able to accept this.
8582

@@ -88,17 +85,16 @@ server supports it. This is done through the file object interface::
8885

8986
FIRMWARE_PATH = '/path/to/firmware.bin'
9087
FILESIZE = os.path.getsize(FIRMWARE_PATH)
91-
infile = open(FIRMWARE_PATH, 'rb')
92-
outfile = node.sdo['Firmware'].open('wb', size=FILESIZE, block_transfer=True)
93-
94-
# Iteratively transfer data without having to read all into memory
95-
while True:
96-
data = infile.read(1024)
97-
if not data:
98-
break
99-
outfile.write(data)
100-
infile.close()
101-
outfile.close()
88+
89+
with open(FIRMWARE_PATH, 'rb') as infile,
90+
node.sdo['Firmware'].open('wb', size=FILESIZE, block_transfer=True) as outfile:
91+
92+
# Iteratively transfer data without having to read all into memory
93+
while True:
94+
data = infile.read(1024)
95+
if not data:
96+
break
97+
outfile.write(data)
10298

10399
.. warning::
104100
Block transfer is still in experimental stage!

test/test_eds.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ def test_load_nonexisting_file(self):
1515
canopen.import_od('/path/to/wrong_file.eds')
1616

1717
def test_load_file_object(self):
18-
od = canopen.import_od(open(EDS_PATH))
18+
with open(EDS_PATH) as fp:
19+
od = canopen.import_od(fp)
1920
self.assertTrue(len(od) > 0)
2021

2122
def test_variable(self):

test/test_local.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,17 +40,19 @@ def test_expedited_upload(self):
4040

4141
def test_block_upload_switch_to_expedite_upload(self):
4242
with self.assertRaises(canopen.SdoCommunicationError) as context:
43-
self.remote_node.sdo[0x1008].open('r', block_transfer=True)
43+
with self.remote_node.sdo[0x1008].open('r', block_transfer=True) as fp:
44+
pass
4445
# We get this since the sdo client don't support the switch
4546
# from block upload to expedite upload
4647
self.assertEqual("Unexpected response 0x41", str(context.exception))
4748

4849
def test_block_download_not_supported(self):
4950
data = b"TEST DEVICE"
5051
with self.assertRaises(canopen.SdoAbortedError) as context:
51-
self.remote_node.sdo[0x1008].open('wb',
52-
size=len(data),
53-
block_transfer=True)
52+
with self.remote_node.sdo[0x1008].open('wb',
53+
size=len(data),
54+
block_transfer=True) as fp:
55+
pass
5456
self.assertEqual(context.exception.code, 0x05040001)
5557

5658
def test_expedited_upload_default_value_visible_string(self):

test/test_sdo.py

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,9 @@ def test_block_download(self):
110110
(RX, b'\xa1\x00\x00\x00\x00\x00\x00\x00')
111111
]
112112
data = b'A really really long string...'
113-
fp = self.network[2].sdo['Writable string'].open(
114-
'wb', size=len(data), block_transfer=True)
115-
fp.write(data)
116-
fp.close()
113+
with self.network[2].sdo['Writable string'].open(
114+
'wb', size=len(data), block_transfer=True) as fp:
115+
fp.write(data)
117116

118117
def test_block_upload(self):
119118
self.data = [
@@ -128,9 +127,8 @@ def test_block_upload(self):
128127
(RX, b'\xc9\x40\xe1\x00\x00\x00\x00\x00'),
129128
(TX, b'\xa1\x00\x00\x00\x00\x00\x00\x00')
130129
]
131-
fp = self.network[2].sdo[0x1008].open('r', block_transfer=True)
132-
data = fp.read()
133-
fp.close()
130+
with self.network[2].sdo[0x1008].open('r', block_transfer=True) as fp:
131+
data = fp.read()
134132
self.assertEqual(data, 'Tiny Node - Mega Domains !')
135133

136134
def test_writable_file(self):
@@ -144,10 +142,9 @@ def test_writable_file(self):
144142
(TX, b'\x0f\x00\x00\x00\x00\x00\x00\x00'),
145143
(RX, b'\x20\x00\x20\x00\x00\x00\x00\x00')
146144
]
147-
fp = self.network[2].sdo['Writable string'].open('wb')
148-
fp.write(b'1234')
149-
fp.write(b'56789')
150-
fp.close()
145+
with self.network[2].sdo['Writable string'].open('wb') as fp:
146+
fp.write(b'1234')
147+
fp.write(b'56789')
151148
self.assertTrue(fp.closed)
152149
# Write on closed file
153150
with self.assertRaises(ValueError):

0 commit comments

Comments
 (0)