Skip to content

Commit 5ad15f8

Browse files
authored
Ensure resource closure in all exceptional circumstances during construction (#35566) (#35587)
1 parent 37b2694 commit 5ad15f8

File tree

6 files changed

+25
-8
lines changed

6 files changed

+25
-8
lines changed

doc/source/whatsnew/v1.2.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,7 @@ MultiIndex
294294
I/O
295295
^^^
296296

297+
- :func:`read_sas` no longer leaks resources on failure (:issue:`35566`)
297298
- Bug in :meth:`to_csv` caused a ``ValueError`` when it was called with a filename in combination with ``mode`` containing a ``b`` (:issue:`35058`)
298299
- In :meth:`read_csv` `float_precision='round_trip'` now handles `decimal` and `thousands` parameters (:issue:`35365`)
299300
- :meth:`to_pickle` and :meth:`read_pickle` were closing user-provided file objects (:issue:`35679`)

pandas/io/sas/sas7bdat.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -142,8 +142,12 @@ def __init__(
142142
self._path_or_buf = open(self._path_or_buf, "rb")
143143
self.handle = self._path_or_buf
144144

145-
self._get_properties()
146-
self._parse_metadata()
145+
try:
146+
self._get_properties()
147+
self._parse_metadata()
148+
except Exception:
149+
self.close()
150+
raise
147151

148152
def column_data_lengths(self):
149153
"""Return a numpy int64 array of the column data lengths"""

pandas/io/sas/sas_xport.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,11 @@ def __init__(
264264
# should already be opened in binary mode in Python 3.
265265
self.filepath_or_buffer = filepath_or_buffer
266266

267-
self._read_header()
267+
try:
268+
self._read_header()
269+
except Exception:
270+
self.close()
271+
raise
268272

269273
def close(self):
270274
self.filepath_or_buffer.close()

pandas/io/sas/sasreader.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,8 @@ def read_sas(
136136
if iterator or chunksize:
137137
return reader
138138

139-
data = reader.read()
140-
141-
if ioargs.should_close:
142-
reader.close()
143-
return data
139+
try:
140+
return reader.read()
141+
finally:
142+
if ioargs.should_close:
143+
reader.close()
292 Bytes
Binary file not shown.

pandas/tests/io/sas/test_sas7bdat.py

+8
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,14 @@ def test_zero_variables(datapath):
217217
pd.read_sas(fname)
218218

219219

220+
def test_corrupt_read(datapath):
221+
# We don't really care about the exact failure, the important thing is
222+
# that the resource should be cleaned up afterwards (BUG #35566)
223+
fname = datapath("io", "sas", "data", "corrupt.sas7bdat")
224+
with pytest.raises(AttributeError):
225+
pd.read_sas(fname)
226+
227+
220228
def round_datetime_to_ms(ts):
221229
if isinstance(ts, datetime):
222230
return ts.replace(microsecond=int(round(ts.microsecond, -3) / 1000) * 1000)

0 commit comments

Comments
 (0)