Skip to content

Commit 235a1e0

Browse files
committed
fix(stream_io): Use a subclass instead of method wrappers for uploads
1 parent 09acd08 commit 235a1e0

File tree

1 file changed

+27
-27
lines changed

1 file changed

+27
-27
lines changed

tensorizer/stream_io.py

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1466,33 +1466,33 @@ def open_stream(
14661466
s3_signature_version,
14671467
)
14681468

1469-
# Always run the close + upload procedure
1470-
# before any code from Python's NamedTemporaryFile wrapper.
1471-
# It isn't safe to call a bound method from a weakref finalizer,
1472-
# but calling a weakref finalizer alongside a bound method
1473-
# creates no problems, other than that the code outside the
1474-
# finalizer is not guaranteed to be run at any point.
1475-
# In this case, the weakref finalizer performs all necessary
1476-
# cleanup itself, but the original NamedTemporaryFile methods
1477-
# are invoked as well, just in case.
1478-
wrapped_close = temp_file.close
1479-
1480-
def close_wrapper():
1481-
guaranteed_closer()
1482-
return wrapped_close()
1483-
1484-
# Python 3.12+ doesn't call NamedTemporaryFile.close() during
1485-
# .__exit__(), so it must be wrapped separately.
1486-
# Since guaranteed_closer is idempotent, it's fine to call it in
1487-
# both methods, even if both are called back-to-back.
1488-
wrapped_exit = temp_file.__exit__
1489-
1490-
def exit_wrapper(exc, value, tb):
1491-
guaranteed_closer()
1492-
return wrapped_exit(exc, value, tb)
1493-
1494-
temp_file.close = close_wrapper
1495-
temp_file.__exit__ = exit_wrapper
1469+
# Create a class dynamically to wrap methods, as __exit__ is always
1470+
# looked up on the class of an object even if a function with the
1471+
# same name exists in the instance dictionary.
1472+
# noinspection PyAbstractClass
1473+
class S3TemporaryFileWrapper(temp_file.__class__):
1474+
# Always run the close + upload procedure
1475+
# before any code from Python's NamedTemporaryFile wrapper.
1476+
# It isn't safe to call a bound method from a weakref finalizer,
1477+
# but calling a weakref finalizer alongside a bound method
1478+
# creates no problems, other than that the code outside the
1479+
# finalizer is not guaranteed to be run at any point.
1480+
# In this case, the weakref finalizer performs all necessary
1481+
# cleanup itself, but the original NamedTemporaryFile methods
1482+
# are invoked as well, just in case.
1483+
def close(self):
1484+
guaranteed_closer()
1485+
return super().close()
1486+
1487+
# Python 3.12+ doesn't call NamedTemporaryFile.close() during
1488+
# .__exit__(), so it must be wrapped separately.
1489+
# Since guaranteed_closer is idempotent, it's fine to call it in
1490+
# both methods, even if both are called back-to-back.
1491+
def __exit__(self, exc, value, tb):
1492+
guaranteed_closer()
1493+
return super().__exit__(exc, value, tb)
1494+
1495+
temp_file.__class__ = S3TemporaryFileWrapper
14961496

14971497
return temp_file
14981498
else:

0 commit comments

Comments
 (0)