Skip to content

Commit 7293a37

Browse files
committed
Add LZMAFile wrapper for pickle protocol 5
1 parent 346cf16 commit 7293a37

File tree

1 file changed

+27
-9
lines changed

1 file changed

+27
-9
lines changed

pandas/compat/__init__.py

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,14 @@
1111

1212
import os
1313
import platform
14+
from pickle import PickleBuffer
1415
import sys
15-
from typing import TYPE_CHECKING
16+
17+
try:
18+
import lzma
19+
has_lzma = True
20+
except ImportError:
21+
has_lzma = False
1622

1723
from pandas._typing import F
1824
from pandas.compat.numpy import (
@@ -31,16 +37,30 @@
3137
pa_version_under9p0,
3238
)
3339

34-
if TYPE_CHECKING:
35-
import lzma
36-
3740
PY39 = sys.version_info >= (3, 9)
3841
PY310 = sys.version_info >= (3, 10)
3942
PY311 = sys.version_info >= (3, 11)
4043
PYPY = platform.python_implementation() == "PyPy"
4144
IS64 = sys.maxsize > 2**32
4245

4346

47+
if has_lzma:
48+
class _LZMAFile(lzma.LZMAFile):
49+
def write(self, b) -> None:
50+
if isinstance(b, PickleBuffer):
51+
# Workaround issue where `lzma.LZMAFile` expects `len`
52+
# to return the number of bytes in `b` by converting
53+
# `b` into something that meets that constraint with
54+
# minimal copying.
55+
try:
56+
# coerce to 1-D `uint8` C-contiguous `memoryview` zero-copy
57+
b = b.raw()
58+
except BufferError:
59+
# perform in-memory copy if buffer is not contiguous
60+
b = bytes(b)
61+
return super(_LZMAFile, self).write(b)
62+
63+
4464
def set_function_name(f: F, name: str, cls) -> F:
4565
"""
4666
Bind the name/qualname attributes of the function.
@@ -126,7 +146,7 @@ def is_ci_environment() -> bool:
126146
return os.environ.get("PANDAS_CI", "0") == "1"
127147

128148

129-
def get_lzma_file() -> type[lzma.LZMAFile]:
149+
def get_lzma_file() -> type[_LZMAFile]:
130150
"""
131151
Importing the `LZMAFile` class from the `lzma` module.
132152
@@ -140,15 +160,13 @@ def get_lzma_file() -> type[lzma.LZMAFile]:
140160
RuntimeError
141161
If the `lzma` module was not imported correctly, or didn't exist.
142162
"""
143-
try:
144-
import lzma
145-
except ImportError:
163+
if not has_lzma:
146164
raise RuntimeError(
147165
"lzma module not available. "
148166
"A Python re-install with the proper dependencies, "
149167
"might be required to solve this issue."
150168
)
151-
return lzma.LZMAFile
169+
return _LZMAFile
152170

153171

154172
__all__ = [

0 commit comments

Comments
 (0)