polars-runtime-compat 1.34.0b2__cp39-abi3-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of polars-runtime-compat might be problematic. Click here for more details.
- _polars_runtime_compat/.gitkeep +0 -0
- _polars_runtime_compat/_polars_runtime_compat.pyd +0 -0
- polars/__init__.py +528 -0
- polars/_cpu_check.py +265 -0
- polars/_dependencies.py +355 -0
- polars/_plr.py +99 -0
- polars/_plr.pyi +2496 -0
- polars/_reexport.py +23 -0
- polars/_typing.py +478 -0
- polars/_utils/__init__.py +37 -0
- polars/_utils/async_.py +102 -0
- polars/_utils/cache.py +176 -0
- polars/_utils/cloud.py +40 -0
- polars/_utils/constants.py +29 -0
- polars/_utils/construction/__init__.py +46 -0
- polars/_utils/construction/dataframe.py +1397 -0
- polars/_utils/construction/other.py +72 -0
- polars/_utils/construction/series.py +560 -0
- polars/_utils/construction/utils.py +118 -0
- polars/_utils/convert.py +224 -0
- polars/_utils/deprecation.py +406 -0
- polars/_utils/getitem.py +457 -0
- polars/_utils/logging.py +11 -0
- polars/_utils/nest_asyncio.py +264 -0
- polars/_utils/parquet.py +15 -0
- polars/_utils/parse/__init__.py +12 -0
- polars/_utils/parse/expr.py +242 -0
- polars/_utils/polars_version.py +19 -0
- polars/_utils/pycapsule.py +53 -0
- polars/_utils/scan.py +27 -0
- polars/_utils/serde.py +63 -0
- polars/_utils/slice.py +215 -0
- polars/_utils/udfs.py +1251 -0
- polars/_utils/unstable.py +63 -0
- polars/_utils/various.py +782 -0
- polars/_utils/wrap.py +25 -0
- polars/api.py +370 -0
- polars/catalog/__init__.py +0 -0
- polars/catalog/unity/__init__.py +19 -0
- polars/catalog/unity/client.py +733 -0
- polars/catalog/unity/models.py +152 -0
- polars/config.py +1571 -0
- polars/convert/__init__.py +25 -0
- polars/convert/general.py +1046 -0
- polars/convert/normalize.py +261 -0
- polars/dataframe/__init__.py +5 -0
- polars/dataframe/_html.py +186 -0
- polars/dataframe/frame.py +12582 -0
- polars/dataframe/group_by.py +1067 -0
- polars/dataframe/plotting.py +257 -0
- polars/datatype_expr/__init__.py +5 -0
- polars/datatype_expr/array.py +56 -0
- polars/datatype_expr/datatype_expr.py +304 -0
- polars/datatype_expr/list.py +18 -0
- polars/datatype_expr/struct.py +69 -0
- polars/datatypes/__init__.py +122 -0
- polars/datatypes/_parse.py +195 -0
- polars/datatypes/_utils.py +48 -0
- polars/datatypes/classes.py +1213 -0
- polars/datatypes/constants.py +11 -0
- polars/datatypes/constructor.py +172 -0
- polars/datatypes/convert.py +366 -0
- polars/datatypes/group.py +130 -0
- polars/exceptions.py +230 -0
- polars/expr/__init__.py +7 -0
- polars/expr/array.py +964 -0
- polars/expr/binary.py +346 -0
- polars/expr/categorical.py +306 -0
- polars/expr/datetime.py +2620 -0
- polars/expr/expr.py +11272 -0
- polars/expr/list.py +1408 -0
- polars/expr/meta.py +444 -0
- polars/expr/name.py +321 -0
- polars/expr/string.py +3045 -0
- polars/expr/struct.py +357 -0
- polars/expr/whenthen.py +185 -0
- polars/functions/__init__.py +193 -0
- polars/functions/aggregation/__init__.py +33 -0
- polars/functions/aggregation/horizontal.py +298 -0
- polars/functions/aggregation/vertical.py +341 -0
- polars/functions/as_datatype.py +848 -0
- polars/functions/business.py +138 -0
- polars/functions/col.py +384 -0
- polars/functions/datatype.py +121 -0
- polars/functions/eager.py +524 -0
- polars/functions/escape_regex.py +29 -0
- polars/functions/lazy.py +2751 -0
- polars/functions/len.py +68 -0
- polars/functions/lit.py +210 -0
- polars/functions/random.py +22 -0
- polars/functions/range/__init__.py +19 -0
- polars/functions/range/_utils.py +15 -0
- polars/functions/range/date_range.py +303 -0
- polars/functions/range/datetime_range.py +370 -0
- polars/functions/range/int_range.py +348 -0
- polars/functions/range/linear_space.py +311 -0
- polars/functions/range/time_range.py +287 -0
- polars/functions/repeat.py +301 -0
- polars/functions/whenthen.py +353 -0
- polars/interchange/__init__.py +10 -0
- polars/interchange/buffer.py +77 -0
- polars/interchange/column.py +190 -0
- polars/interchange/dataframe.py +230 -0
- polars/interchange/from_dataframe.py +328 -0
- polars/interchange/protocol.py +303 -0
- polars/interchange/utils.py +170 -0
- polars/io/__init__.py +64 -0
- polars/io/_utils.py +317 -0
- polars/io/avro.py +49 -0
- polars/io/clipboard.py +36 -0
- polars/io/cloud/__init__.py +17 -0
- polars/io/cloud/_utils.py +80 -0
- polars/io/cloud/credential_provider/__init__.py +17 -0
- polars/io/cloud/credential_provider/_builder.py +520 -0
- polars/io/cloud/credential_provider/_providers.py +618 -0
- polars/io/csv/__init__.py +9 -0
- polars/io/csv/_utils.py +38 -0
- polars/io/csv/batched_reader.py +142 -0
- polars/io/csv/functions.py +1495 -0
- polars/io/database/__init__.py +6 -0
- polars/io/database/_arrow_registry.py +70 -0
- polars/io/database/_cursor_proxies.py +147 -0
- polars/io/database/_executor.py +578 -0
- polars/io/database/_inference.py +314 -0
- polars/io/database/_utils.py +144 -0
- polars/io/database/functions.py +516 -0
- polars/io/delta.py +499 -0
- polars/io/iceberg/__init__.py +3 -0
- polars/io/iceberg/_utils.py +697 -0
- polars/io/iceberg/dataset.py +556 -0
- polars/io/iceberg/functions.py +151 -0
- polars/io/ipc/__init__.py +8 -0
- polars/io/ipc/functions.py +514 -0
- polars/io/json/__init__.py +3 -0
- polars/io/json/read.py +101 -0
- polars/io/ndjson.py +332 -0
- polars/io/parquet/__init__.py +17 -0
- polars/io/parquet/field_overwrites.py +140 -0
- polars/io/parquet/functions.py +722 -0
- polars/io/partition.py +491 -0
- polars/io/plugins.py +187 -0
- polars/io/pyarrow_dataset/__init__.py +5 -0
- polars/io/pyarrow_dataset/anonymous_scan.py +109 -0
- polars/io/pyarrow_dataset/functions.py +79 -0
- polars/io/scan_options/__init__.py +5 -0
- polars/io/scan_options/_options.py +59 -0
- polars/io/scan_options/cast_options.py +126 -0
- polars/io/spreadsheet/__init__.py +6 -0
- polars/io/spreadsheet/_utils.py +52 -0
- polars/io/spreadsheet/_write_utils.py +647 -0
- polars/io/spreadsheet/functions.py +1323 -0
- polars/lazyframe/__init__.py +9 -0
- polars/lazyframe/engine_config.py +61 -0
- polars/lazyframe/frame.py +8564 -0
- polars/lazyframe/group_by.py +669 -0
- polars/lazyframe/in_process.py +42 -0
- polars/lazyframe/opt_flags.py +333 -0
- polars/meta/__init__.py +14 -0
- polars/meta/build.py +33 -0
- polars/meta/index_type.py +27 -0
- polars/meta/thread_pool.py +50 -0
- polars/meta/versions.py +120 -0
- polars/ml/__init__.py +0 -0
- polars/ml/torch.py +213 -0
- polars/ml/utilities.py +30 -0
- polars/plugins.py +155 -0
- polars/py.typed +0 -0
- polars/pyproject.toml +96 -0
- polars/schema.py +265 -0
- polars/selectors.py +3117 -0
- polars/series/__init__.py +5 -0
- polars/series/array.py +776 -0
- polars/series/binary.py +254 -0
- polars/series/categorical.py +246 -0
- polars/series/datetime.py +2275 -0
- polars/series/list.py +1087 -0
- polars/series/plotting.py +191 -0
- polars/series/series.py +9197 -0
- polars/series/string.py +2367 -0
- polars/series/struct.py +154 -0
- polars/series/utils.py +191 -0
- polars/sql/__init__.py +7 -0
- polars/sql/context.py +677 -0
- polars/sql/functions.py +139 -0
- polars/string_cache.py +185 -0
- polars/testing/__init__.py +13 -0
- polars/testing/asserts/__init__.py +9 -0
- polars/testing/asserts/frame.py +231 -0
- polars/testing/asserts/series.py +219 -0
- polars/testing/asserts/utils.py +12 -0
- polars/testing/parametric/__init__.py +33 -0
- polars/testing/parametric/profiles.py +107 -0
- polars/testing/parametric/strategies/__init__.py +22 -0
- polars/testing/parametric/strategies/_utils.py +14 -0
- polars/testing/parametric/strategies/core.py +615 -0
- polars/testing/parametric/strategies/data.py +452 -0
- polars/testing/parametric/strategies/dtype.py +436 -0
- polars/testing/parametric/strategies/legacy.py +169 -0
- polars/type_aliases.py +24 -0
- polars_runtime_compat-1.34.0b2.dist-info/METADATA +190 -0
- polars_runtime_compat-1.34.0b2.dist-info/RECORD +203 -0
- polars_runtime_compat-1.34.0b2.dist-info/WHEEL +4 -0
- polars_runtime_compat-1.34.0b2.dist-info/licenses/LICENSE +20 -0
polars/_cpu_check.py
ADDED
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
# Vendored parts of the code from https://github.com/flababah/cpuid.py,
|
|
2
|
+
# so we replicate its copyright license.
|
|
3
|
+
|
|
4
|
+
# Copyright (c) 2014 Anders Høst
|
|
5
|
+
#
|
|
6
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
7
|
+
# this software and associated documentation files (the "Software"), to deal in
|
|
8
|
+
# the Software without restriction, including without limitation the rights to
|
|
9
|
+
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
10
|
+
# the Software, and to permit persons to whom the Software is furnished to do so,
|
|
11
|
+
# subject to the following conditions:
|
|
12
|
+
#
|
|
13
|
+
# The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
# copies or substantial portions of the Software.
|
|
15
|
+
#
|
|
16
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
18
|
+
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
19
|
+
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
20
|
+
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
21
|
+
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
|
|
26
|
+
import ctypes
|
|
27
|
+
import os
|
|
28
|
+
from ctypes import CFUNCTYPE, POINTER, c_long, c_size_t, c_uint32, c_ulong, c_void_p
|
|
29
|
+
from typing import ClassVar
|
|
30
|
+
|
|
31
|
+
"""
|
|
32
|
+
Determine whether Polars can be run on the current CPU.
|
|
33
|
+
|
|
34
|
+
This must be done in pure Python, before the Polars binary is imported. If we
|
|
35
|
+
were to try it on the Rust side the compiler could emit illegal instructions
|
|
36
|
+
before/during the CPU feature check code.
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
_IS_WINDOWS = os.name == "nt"
|
|
40
|
+
_IS_64BIT = ctypes.sizeof(ctypes.c_void_p) == 8
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def get_runtime_repr() -> str:
|
|
44
|
+
import polars._plr as plr
|
|
45
|
+
|
|
46
|
+
return plr.RUNTIME_REPR
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _open_posix_libc() -> ctypes.CDLL:
|
|
50
|
+
# Avoid importing ctypes.util if possible.
|
|
51
|
+
try:
|
|
52
|
+
if os.uname().sysname == "Darwin":
|
|
53
|
+
return ctypes.CDLL("libc.dylib", use_errno=True)
|
|
54
|
+
else:
|
|
55
|
+
return ctypes.CDLL("libc.so.6", use_errno=True)
|
|
56
|
+
except Exception:
|
|
57
|
+
from ctypes import util as ctutil
|
|
58
|
+
|
|
59
|
+
return ctypes.CDLL(ctutil.find_library("c"), use_errno=True)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
# Posix x86_64:
|
|
63
|
+
# Three first call registers : RDI, RSI, RDX
|
|
64
|
+
# Volatile registers : RAX, RCX, RDX, RSI, RDI, R8-11
|
|
65
|
+
|
|
66
|
+
# Windows x86_64:
|
|
67
|
+
# Three first call registers : RCX, RDX, R8
|
|
68
|
+
# Volatile registers : RAX, RCX, RDX, R8-11
|
|
69
|
+
|
|
70
|
+
# cdecl 32 bit:
|
|
71
|
+
# Three first call registers : Stack (%esp)
|
|
72
|
+
# Volatile registers : EAX, ECX, EDX
|
|
73
|
+
|
|
74
|
+
# fmt: off
|
|
75
|
+
_POSIX_64_OPC = [
|
|
76
|
+
0x53, # push %rbx
|
|
77
|
+
0x89, 0xf0, # mov %esi,%eax
|
|
78
|
+
0x89, 0xd1, # mov %edx,%ecx
|
|
79
|
+
0x0f, 0xa2, # cpuid
|
|
80
|
+
0x89, 0x07, # mov %eax,(%rdi)
|
|
81
|
+
0x89, 0x5f, 0x04, # mov %ebx,0x4(%rdi)
|
|
82
|
+
0x89, 0x4f, 0x08, # mov %ecx,0x8(%rdi)
|
|
83
|
+
0x89, 0x57, 0x0c, # mov %edx,0xc(%rdi)
|
|
84
|
+
0x5b, # pop %rbx
|
|
85
|
+
0xc3 # retq
|
|
86
|
+
]
|
|
87
|
+
|
|
88
|
+
_WINDOWS_64_OPC = [
|
|
89
|
+
0x53, # push %rbx
|
|
90
|
+
0x89, 0xd0, # mov %edx,%eax
|
|
91
|
+
0x49, 0x89, 0xc9, # mov %rcx,%r9
|
|
92
|
+
0x44, 0x89, 0xc1, # mov %r8d,%ecx
|
|
93
|
+
0x0f, 0xa2, # cpuid
|
|
94
|
+
0x41, 0x89, 0x01, # mov %eax,(%r9)
|
|
95
|
+
0x41, 0x89, 0x59, 0x04, # mov %ebx,0x4(%r9)
|
|
96
|
+
0x41, 0x89, 0x49, 0x08, # mov %ecx,0x8(%r9)
|
|
97
|
+
0x41, 0x89, 0x51, 0x0c, # mov %edx,0xc(%r9)
|
|
98
|
+
0x5b, # pop %rbx
|
|
99
|
+
0xc3 # retq
|
|
100
|
+
]
|
|
101
|
+
|
|
102
|
+
_CDECL_32_OPC = [
|
|
103
|
+
0x53, # push %ebx
|
|
104
|
+
0x57, # push %edi
|
|
105
|
+
0x8b, 0x7c, 0x24, 0x0c, # mov 0xc(%esp),%edi
|
|
106
|
+
0x8b, 0x44, 0x24, 0x10, # mov 0x10(%esp),%eax
|
|
107
|
+
0x8b, 0x4c, 0x24, 0x14, # mov 0x14(%esp),%ecx
|
|
108
|
+
0x0f, 0xa2, # cpuid
|
|
109
|
+
0x89, 0x07, # mov %eax,(%edi)
|
|
110
|
+
0x89, 0x5f, 0x04, # mov %ebx,0x4(%edi)
|
|
111
|
+
0x89, 0x4f, 0x08, # mov %ecx,0x8(%edi)
|
|
112
|
+
0x89, 0x57, 0x0c, # mov %edx,0xc(%edi)
|
|
113
|
+
0x5f, # pop %edi
|
|
114
|
+
0x5b, # pop %ebx
|
|
115
|
+
0xc3 # ret
|
|
116
|
+
]
|
|
117
|
+
# fmt: on
|
|
118
|
+
|
|
119
|
+
# From memoryapi.h
|
|
120
|
+
_MEM_COMMIT = 0x1000
|
|
121
|
+
_MEM_RESERVE = 0x2000
|
|
122
|
+
_MEM_RELEASE = 0x8000
|
|
123
|
+
_PAGE_EXECUTE_READWRITE = 0x40
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
class CPUID_struct(ctypes.Structure):
|
|
127
|
+
_fields_: ClassVar[list[tuple[str, type]]] = [
|
|
128
|
+
(r, c_uint32) for r in ("eax", "ebx", "ecx", "edx")
|
|
129
|
+
]
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
class CPUID:
|
|
133
|
+
def __init__(self) -> None:
|
|
134
|
+
if _IS_WINDOWS:
|
|
135
|
+
if _IS_64BIT:
|
|
136
|
+
# VirtualAlloc seems to fail under some weird
|
|
137
|
+
# circumstances when ctypes.windll.kernel32 is
|
|
138
|
+
# used under 64 bit Python. CDLL fixes this.
|
|
139
|
+
self.win = ctypes.CDLL("kernel32.dll")
|
|
140
|
+
opc = _WINDOWS_64_OPC
|
|
141
|
+
else:
|
|
142
|
+
# Here ctypes.windll.kernel32 is needed to get the
|
|
143
|
+
# right DLL. Otherwise it will fail when running
|
|
144
|
+
# 32 bit Python on 64 bit Windows.
|
|
145
|
+
self.win = ctypes.windll.kernel32 # type: ignore[attr-defined]
|
|
146
|
+
opc = _CDECL_32_OPC
|
|
147
|
+
else:
|
|
148
|
+
opc = _POSIX_64_OPC if _IS_64BIT else _CDECL_32_OPC
|
|
149
|
+
|
|
150
|
+
size = len(opc)
|
|
151
|
+
code = (ctypes.c_ubyte * size)(*opc)
|
|
152
|
+
|
|
153
|
+
if _IS_WINDOWS:
|
|
154
|
+
self.win.VirtualAlloc.restype = c_void_p
|
|
155
|
+
self.win.VirtualAlloc.argtypes = [
|
|
156
|
+
ctypes.c_void_p,
|
|
157
|
+
ctypes.c_size_t,
|
|
158
|
+
ctypes.c_ulong,
|
|
159
|
+
ctypes.c_ulong,
|
|
160
|
+
]
|
|
161
|
+
self.addr = self.win.VirtualAlloc(
|
|
162
|
+
None, size, _MEM_COMMIT | _MEM_RESERVE, _PAGE_EXECUTE_READWRITE
|
|
163
|
+
)
|
|
164
|
+
if not self.addr:
|
|
165
|
+
msg = "could not allocate memory for CPUID check"
|
|
166
|
+
raise MemoryError(msg)
|
|
167
|
+
ctypes.memmove(self.addr, code, size)
|
|
168
|
+
else:
|
|
169
|
+
import mmap # Only import if necessary.
|
|
170
|
+
|
|
171
|
+
# On some platforms PROT_WRITE + PROT_EXEC is forbidden, so we first
|
|
172
|
+
# only write and then mprotect into PROT_EXEC.
|
|
173
|
+
libc = _open_posix_libc()
|
|
174
|
+
mprotect = libc.mprotect
|
|
175
|
+
mprotect.argtypes = (ctypes.c_void_p, ctypes.c_size_t, ctypes.c_int)
|
|
176
|
+
mprotect.restype = ctypes.c_int
|
|
177
|
+
|
|
178
|
+
self.mmap = mmap.mmap(
|
|
179
|
+
-1,
|
|
180
|
+
size,
|
|
181
|
+
mmap.MAP_PRIVATE | mmap.MAP_ANONYMOUS,
|
|
182
|
+
mmap.PROT_READ | mmap.PROT_WRITE,
|
|
183
|
+
)
|
|
184
|
+
self.addr = ctypes.addressof(ctypes.c_void_p.from_buffer(self.mmap))
|
|
185
|
+
self.mmap.write(code)
|
|
186
|
+
|
|
187
|
+
if mprotect(self.addr, size, mmap.PROT_READ | mmap.PROT_EXEC) != 0:
|
|
188
|
+
msg = "could not execute mprotect for CPUID check"
|
|
189
|
+
raise RuntimeError(msg)
|
|
190
|
+
|
|
191
|
+
func_type = CFUNCTYPE(None, POINTER(CPUID_struct), c_uint32, c_uint32)
|
|
192
|
+
self.func_ptr = func_type(self.addr)
|
|
193
|
+
|
|
194
|
+
def __call__(self, eax: int, ecx: int = 0) -> CPUID_struct:
|
|
195
|
+
struct = CPUID_struct()
|
|
196
|
+
self.func_ptr(struct, eax, ecx)
|
|
197
|
+
return struct
|
|
198
|
+
|
|
199
|
+
def __del__(self) -> None:
|
|
200
|
+
if _IS_WINDOWS:
|
|
201
|
+
self.win.VirtualFree.restype = c_long
|
|
202
|
+
self.win.VirtualFree.argtypes = [c_void_p, c_size_t, c_ulong]
|
|
203
|
+
self.win.VirtualFree(self.addr, 0, _MEM_RELEASE)
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def _read_cpu_flags() -> dict[str, bool]:
|
|
207
|
+
# CPU flags from https://en.wikipedia.org/wiki/CPUID
|
|
208
|
+
cpuid = CPUID()
|
|
209
|
+
cpuid1 = cpuid(1, 0)
|
|
210
|
+
cpuid7 = cpuid(7, 0)
|
|
211
|
+
cpuid81h = cpuid(0x80000001, 0)
|
|
212
|
+
|
|
213
|
+
return {
|
|
214
|
+
"sse3": bool(cpuid1.ecx & (1 << 0)),
|
|
215
|
+
"ssse3": bool(cpuid1.ecx & (1 << 9)),
|
|
216
|
+
"fma": bool(cpuid1.ecx & (1 << 12)),
|
|
217
|
+
"cmpxchg16b": bool(cpuid1.ecx & (1 << 13)),
|
|
218
|
+
"sse4.1": bool(cpuid1.ecx & (1 << 19)),
|
|
219
|
+
"sse4.2": bool(cpuid1.ecx & (1 << 20)),
|
|
220
|
+
"movbe": bool(cpuid1.ecx & (1 << 22)),
|
|
221
|
+
"popcnt": bool(cpuid1.ecx & (1 << 23)),
|
|
222
|
+
"pclmulqdq": bool(cpuid1.ecx & (1 << 1)),
|
|
223
|
+
"avx": bool(cpuid1.ecx & (1 << 28)),
|
|
224
|
+
"bmi1": bool(cpuid7.ebx & (1 << 3)),
|
|
225
|
+
"bmi2": bool(cpuid7.ebx & (1 << 8)),
|
|
226
|
+
"avx2": bool(cpuid7.ebx & (1 << 5)),
|
|
227
|
+
"lzcnt": bool(cpuid81h.ecx & (1 << 5)),
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
def check_cpu_flags(feature_flags: str) -> None:
|
|
232
|
+
if not feature_flags or os.environ.get("POLARS_SKIP_CPU_CHECK"):
|
|
233
|
+
return
|
|
234
|
+
|
|
235
|
+
expected_cpu_flags = [f.lstrip("+") for f in feature_flags.split(",")]
|
|
236
|
+
supported_cpu_flags = _read_cpu_flags()
|
|
237
|
+
|
|
238
|
+
missing_features = []
|
|
239
|
+
for f in expected_cpu_flags:
|
|
240
|
+
if f not in supported_cpu_flags:
|
|
241
|
+
msg = f"unknown feature flag: {f!r}"
|
|
242
|
+
raise RuntimeError(msg)
|
|
243
|
+
|
|
244
|
+
if not supported_cpu_flags[f]:
|
|
245
|
+
missing_features.append(f)
|
|
246
|
+
|
|
247
|
+
if missing_features:
|
|
248
|
+
import warnings # Only import if necessary.
|
|
249
|
+
|
|
250
|
+
warnings.warn(
|
|
251
|
+
f"""Missing required CPU features.
|
|
252
|
+
|
|
253
|
+
The following required CPU features were not detected:
|
|
254
|
+
{", ".join(missing_features)}
|
|
255
|
+
Continuing to use this version of Polars on this processor will likely result in a crash.
|
|
256
|
+
Install the `polars-lts-cpu` package instead of `polars` to run Polars with better compatibility.
|
|
257
|
+
|
|
258
|
+
Hint: If you are on an Apple ARM machine (e.g. M1) this is likely due to running Python under Rosetta.
|
|
259
|
+
It is recommended to install a native version of Python that does not run under Rosetta x86-64 emulation.
|
|
260
|
+
|
|
261
|
+
If you believe this warning to be a false positive, you can set the `POLARS_SKIP_CPU_CHECK` environment variable to bypass this check.
|
|
262
|
+
""",
|
|
263
|
+
RuntimeWarning,
|
|
264
|
+
stacklevel=1,
|
|
265
|
+
)
|
polars/_dependencies.py
ADDED
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
import sys
|
|
5
|
+
from collections.abc import Hashable
|
|
6
|
+
from functools import cache
|
|
7
|
+
from importlib import import_module
|
|
8
|
+
from importlib.util import find_spec
|
|
9
|
+
from types import ModuleType
|
|
10
|
+
from typing import TYPE_CHECKING, Any, ClassVar, cast
|
|
11
|
+
|
|
12
|
+
_ALTAIR_AVAILABLE = True
|
|
13
|
+
_DELTALAKE_AVAILABLE = True
|
|
14
|
+
_FSSPEC_AVAILABLE = True
|
|
15
|
+
_GEVENT_AVAILABLE = True
|
|
16
|
+
_GREAT_TABLES_AVAILABLE = True
|
|
17
|
+
_HYPOTHESIS_AVAILABLE = True
|
|
18
|
+
_NUMPY_AVAILABLE = True
|
|
19
|
+
_PANDAS_AVAILABLE = True
|
|
20
|
+
_POLARS_CLOUD_AVAILABLE = True
|
|
21
|
+
_PYARROW_AVAILABLE = True
|
|
22
|
+
_PYDANTIC_AVAILABLE = True
|
|
23
|
+
_PYICEBERG_AVAILABLE = True
|
|
24
|
+
_TORCH_AVAILABLE = True
|
|
25
|
+
_PYTZ_AVAILABLE = True
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class _LazyModule(ModuleType):
|
|
29
|
+
"""
|
|
30
|
+
Module that can act both as a lazy-loader and as a proxy.
|
|
31
|
+
|
|
32
|
+
Notes
|
|
33
|
+
-----
|
|
34
|
+
We do NOT register this module with `sys.modules` so as not to cause
|
|
35
|
+
confusion in the global environment. This way we have a valid proxy
|
|
36
|
+
module for our own use, but it lives *exclusively* within polars.
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
__lazy__ = True
|
|
40
|
+
|
|
41
|
+
_mod_pfx: ClassVar[dict[str, str]] = {
|
|
42
|
+
"numpy": "np.",
|
|
43
|
+
"pandas": "pd.",
|
|
44
|
+
"pyarrow": "pa.",
|
|
45
|
+
"polars_cloud": "pc.",
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
def __init__(
|
|
49
|
+
self,
|
|
50
|
+
module_name: str,
|
|
51
|
+
*,
|
|
52
|
+
module_available: bool,
|
|
53
|
+
) -> None:
|
|
54
|
+
"""
|
|
55
|
+
Initialise lazy-loading proxy module.
|
|
56
|
+
|
|
57
|
+
Parameters
|
|
58
|
+
----------
|
|
59
|
+
module_name : str
|
|
60
|
+
the name of the module to lazy-load (if available).
|
|
61
|
+
|
|
62
|
+
module_available : bool
|
|
63
|
+
indicate if the referenced module is actually available (we will proxy it
|
|
64
|
+
in both cases, but raise a helpful error when invoked if it doesn't exist).
|
|
65
|
+
"""
|
|
66
|
+
self._module_available = module_available
|
|
67
|
+
self._module_name = module_name
|
|
68
|
+
self._globals = globals()
|
|
69
|
+
super().__init__(module_name)
|
|
70
|
+
|
|
71
|
+
def _import(self) -> ModuleType:
|
|
72
|
+
# import the referenced module, replacing the proxy in this module's globals
|
|
73
|
+
module = import_module(self.__name__)
|
|
74
|
+
self._globals[self._module_name] = module
|
|
75
|
+
self.__dict__.update(module.__dict__)
|
|
76
|
+
return module
|
|
77
|
+
|
|
78
|
+
def __getattr__(self, name: str) -> Any:
|
|
79
|
+
# have "hasattr('__wrapped__')" return False without triggering import
|
|
80
|
+
# (it's for decorators, not modules, but keeps "make doctest" happy)
|
|
81
|
+
if name == "__wrapped__":
|
|
82
|
+
msg = f"{self._module_name!r} object has no attribute {name!r}"
|
|
83
|
+
raise AttributeError(msg)
|
|
84
|
+
|
|
85
|
+
# accessing the proxy module's attributes triggers import of the real thing
|
|
86
|
+
if self._module_available:
|
|
87
|
+
# import the module and return the requested attribute
|
|
88
|
+
module = self._import()
|
|
89
|
+
return getattr(module, name)
|
|
90
|
+
|
|
91
|
+
# user has not installed the proxied/lazy module
|
|
92
|
+
elif name == "__name__":
|
|
93
|
+
return self._module_name
|
|
94
|
+
elif re.match(r"^__\w+__$", name) and name != "__version__":
|
|
95
|
+
# allow some minimal introspection on private module
|
|
96
|
+
# attrs to avoid unnecessary error-handling elsewhere
|
|
97
|
+
return None
|
|
98
|
+
else:
|
|
99
|
+
# all other attribute access raises a helpful exception
|
|
100
|
+
pfx = self._mod_pfx.get(self._module_name, "")
|
|
101
|
+
msg = f"{pfx}{name} requires {self._module_name!r} module to be installed"
|
|
102
|
+
raise ModuleNotFoundError(msg) from None
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def _lazy_import(module_name: str) -> tuple[ModuleType, bool]:
|
|
106
|
+
"""
|
|
107
|
+
Lazy import the given module; avoids up-front import costs.
|
|
108
|
+
|
|
109
|
+
Parameters
|
|
110
|
+
----------
|
|
111
|
+
module_name : str
|
|
112
|
+
name of the module to import, eg: "pyarrow".
|
|
113
|
+
|
|
114
|
+
Notes
|
|
115
|
+
-----
|
|
116
|
+
If the requested module is not available (eg: has not been installed), a proxy
|
|
117
|
+
module is created in its place, which raises an exception on any attribute
|
|
118
|
+
access. This allows for import and use as normal, without requiring explicit
|
|
119
|
+
guard conditions - if the module is never used, no exception occurs; if it
|
|
120
|
+
is, then a helpful exception is raised.
|
|
121
|
+
|
|
122
|
+
Returns
|
|
123
|
+
-------
|
|
124
|
+
tuple of (Module, bool)
|
|
125
|
+
A lazy-loading module and a boolean indicating if the requested/underlying
|
|
126
|
+
module exists (if not, the returned module is a proxy).
|
|
127
|
+
"""
|
|
128
|
+
# check if module is LOADED
|
|
129
|
+
if module_name in sys.modules:
|
|
130
|
+
return sys.modules[module_name], True
|
|
131
|
+
|
|
132
|
+
# check if module is AVAILABLE
|
|
133
|
+
try:
|
|
134
|
+
module_spec = find_spec(module_name)
|
|
135
|
+
module_available = not (module_spec is None or module_spec.loader is None)
|
|
136
|
+
except ModuleNotFoundError:
|
|
137
|
+
module_available = False
|
|
138
|
+
|
|
139
|
+
# create lazy/proxy module that imports the real one on first use
|
|
140
|
+
# (or raises an explanatory ModuleNotFoundError if not available)
|
|
141
|
+
return (
|
|
142
|
+
_LazyModule(
|
|
143
|
+
module_name=module_name,
|
|
144
|
+
module_available=module_available,
|
|
145
|
+
),
|
|
146
|
+
module_available,
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
if TYPE_CHECKING:
|
|
151
|
+
import dataclasses
|
|
152
|
+
import html
|
|
153
|
+
import json
|
|
154
|
+
import pickle
|
|
155
|
+
import subprocess
|
|
156
|
+
|
|
157
|
+
import altair
|
|
158
|
+
import boto3
|
|
159
|
+
import deltalake
|
|
160
|
+
import fsspec
|
|
161
|
+
import gevent
|
|
162
|
+
import great_tables
|
|
163
|
+
import hypothesis
|
|
164
|
+
import numpy
|
|
165
|
+
import pandas
|
|
166
|
+
import polars_cloud
|
|
167
|
+
import pyarrow
|
|
168
|
+
import pydantic
|
|
169
|
+
import pyiceberg
|
|
170
|
+
import pyiceberg.schema
|
|
171
|
+
import pytz
|
|
172
|
+
import torch
|
|
173
|
+
|
|
174
|
+
else:
|
|
175
|
+
# infrequently-used builtins
|
|
176
|
+
dataclasses, _ = _lazy_import("dataclasses")
|
|
177
|
+
html, _ = _lazy_import("html")
|
|
178
|
+
json, _ = _lazy_import("json")
|
|
179
|
+
pickle, _ = _lazy_import("pickle")
|
|
180
|
+
subprocess, _ = _lazy_import("subprocess")
|
|
181
|
+
|
|
182
|
+
# heavy/optional third party libs
|
|
183
|
+
altair, _ALTAIR_AVAILABLE = _lazy_import("altair")
|
|
184
|
+
boto3, _BOTO3_AVAILABLE = _lazy_import("boto3")
|
|
185
|
+
deltalake, _DELTALAKE_AVAILABLE = _lazy_import("deltalake")
|
|
186
|
+
fsspec, _FSSPEC_AVAILABLE = _lazy_import("fsspec")
|
|
187
|
+
gevent, _GEVENT_AVAILABLE = _lazy_import("gevent")
|
|
188
|
+
great_tables, _GREAT_TABLES_AVAILABLE = _lazy_import("great_tables")
|
|
189
|
+
hypothesis, _HYPOTHESIS_AVAILABLE = _lazy_import("hypothesis")
|
|
190
|
+
numpy, _NUMPY_AVAILABLE = _lazy_import("numpy")
|
|
191
|
+
pandas, _PANDAS_AVAILABLE = _lazy_import("pandas")
|
|
192
|
+
polars_cloud, _POLARS_CLOUD_AVAILABLE = _lazy_import("polars_cloud")
|
|
193
|
+
pyarrow, _PYARROW_AVAILABLE = _lazy_import("pyarrow")
|
|
194
|
+
pydantic, _PYDANTIC_AVAILABLE = _lazy_import("pydantic")
|
|
195
|
+
pyiceberg, _PYICEBERG_AVAILABLE = _lazy_import("pyiceberg")
|
|
196
|
+
torch, _TORCH_AVAILABLE = _lazy_import("torch")
|
|
197
|
+
pytz, _PYTZ_AVAILABLE = _lazy_import("pytz")
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
@cache
|
|
201
|
+
def _might_be(cls: type, type_: str) -> bool:
|
|
202
|
+
# infer whether the given class "might" be associated with the given
|
|
203
|
+
# module (in which case it's reasonable to do a real isinstance check;
|
|
204
|
+
# we defer that so as not to unnecessarily trigger module import)
|
|
205
|
+
try:
|
|
206
|
+
return any(f"{type_}." in str(o) for o in cls.mro())
|
|
207
|
+
except TypeError:
|
|
208
|
+
return False
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def _check_for_numpy(obj: Any, *, check_type: bool = True) -> bool:
|
|
212
|
+
return _NUMPY_AVAILABLE and _might_be(
|
|
213
|
+
cast(Hashable, type(obj) if check_type else obj), "numpy"
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def _check_for_pandas(obj: Any, *, check_type: bool = True) -> bool:
|
|
218
|
+
return _PANDAS_AVAILABLE and _might_be(
|
|
219
|
+
cast(Hashable, type(obj) if check_type else obj), "pandas"
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def _check_for_pyarrow(obj: Any, *, check_type: bool = True) -> bool:
|
|
224
|
+
return _PYARROW_AVAILABLE and _might_be(
|
|
225
|
+
cast(Hashable, type(obj) if check_type else obj), "pyarrow"
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def _check_for_pydantic(obj: Any, *, check_type: bool = True) -> bool:
|
|
230
|
+
return _PYDANTIC_AVAILABLE and _might_be(
|
|
231
|
+
cast(Hashable, type(obj) if check_type else obj), "pydantic"
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def _check_for_torch(obj: Any, *, check_type: bool = True) -> bool:
|
|
236
|
+
return _TORCH_AVAILABLE and _might_be(
|
|
237
|
+
cast(Hashable, type(obj) if check_type else obj), "torch"
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
def _check_for_pytz(obj: Any, *, check_type: bool = True) -> bool:
|
|
242
|
+
return _PYTZ_AVAILABLE and _might_be(
|
|
243
|
+
cast(Hashable, type(obj) if check_type else obj), "pytz"
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
def import_optional(
|
|
248
|
+
module_name: str,
|
|
249
|
+
err_prefix: str = "required package",
|
|
250
|
+
err_suffix: str = "not found",
|
|
251
|
+
min_version: str | tuple[int, ...] | None = None,
|
|
252
|
+
min_err_prefix: str = "requires",
|
|
253
|
+
install_message: str | None = None,
|
|
254
|
+
) -> Any:
|
|
255
|
+
"""
|
|
256
|
+
Import an optional dependency, returning the module.
|
|
257
|
+
|
|
258
|
+
Parameters
|
|
259
|
+
----------
|
|
260
|
+
module_name : str
|
|
261
|
+
Name of the dependency to import.
|
|
262
|
+
err_prefix : str, optional
|
|
263
|
+
Error prefix to use in the raised exception (appears before the module name).
|
|
264
|
+
err_suffix: str, optional
|
|
265
|
+
Error suffix to use in the raised exception (follows the module name).
|
|
266
|
+
min_version : {str, tuple[int]}, optional
|
|
267
|
+
If a minimum module version is required, specify it here.
|
|
268
|
+
min_err_prefix : str, optional
|
|
269
|
+
Override the standard "requires" prefix for the minimum version error message.
|
|
270
|
+
install_message : str, optional
|
|
271
|
+
Override the standard "Please install it using..." exception message fragment.
|
|
272
|
+
|
|
273
|
+
Examples
|
|
274
|
+
--------
|
|
275
|
+
>>> from polars._dependencies import import_optional
|
|
276
|
+
>>> import_optional(
|
|
277
|
+
... "definitely_a_real_module",
|
|
278
|
+
... err_prefix="super-important package",
|
|
279
|
+
... ) # doctest: +SKIP
|
|
280
|
+
ImportError: super-important package 'definitely_a_real_module' not installed.
|
|
281
|
+
Please install it using the command `pip install definitely_a_real_module`.
|
|
282
|
+
"""
|
|
283
|
+
from polars._utils.various import parse_version
|
|
284
|
+
from polars.exceptions import ModuleUpgradeRequiredError
|
|
285
|
+
|
|
286
|
+
module_root = module_name.split(".", 1)[0]
|
|
287
|
+
try:
|
|
288
|
+
module = import_module(module_name)
|
|
289
|
+
except ImportError:
|
|
290
|
+
prefix = f"{err_prefix.strip(' ')} " if err_prefix else ""
|
|
291
|
+
suffix = f" {err_suffix.strip(' ')}" if err_suffix else ""
|
|
292
|
+
err_message = f"{prefix}'{module_name}'{suffix}.\n" + (
|
|
293
|
+
install_message
|
|
294
|
+
or f"Please install using the command `pip install {module_root}`."
|
|
295
|
+
)
|
|
296
|
+
raise ModuleNotFoundError(err_message) from None
|
|
297
|
+
|
|
298
|
+
if min_version:
|
|
299
|
+
min_version = parse_version(min_version)
|
|
300
|
+
mod_version = parse_version(module.__version__)
|
|
301
|
+
if mod_version < min_version:
|
|
302
|
+
msg = (
|
|
303
|
+
f"{min_err_prefix} {module_root} "
|
|
304
|
+
f"{'.'.join(str(v) for v in min_version)} or higher"
|
|
305
|
+
f" (found {'.'.join(str(v) for v in mod_version)})"
|
|
306
|
+
)
|
|
307
|
+
raise ModuleUpgradeRequiredError(msg)
|
|
308
|
+
|
|
309
|
+
return module
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
__all__ = [
|
|
313
|
+
# lazy-load rarely-used/heavy builtins (for fast startup)
|
|
314
|
+
"dataclasses",
|
|
315
|
+
"html",
|
|
316
|
+
"json",
|
|
317
|
+
"pickle",
|
|
318
|
+
"subprocess",
|
|
319
|
+
# lazy-load third party libs
|
|
320
|
+
"altair",
|
|
321
|
+
"boto3",
|
|
322
|
+
"deltalake",
|
|
323
|
+
"fsspec",
|
|
324
|
+
"gevent",
|
|
325
|
+
"great_tables",
|
|
326
|
+
"numpy",
|
|
327
|
+
"pandas",
|
|
328
|
+
"polars_cloud",
|
|
329
|
+
"pydantic",
|
|
330
|
+
"pyiceberg",
|
|
331
|
+
"pyarrow",
|
|
332
|
+
"torch",
|
|
333
|
+
"pytz",
|
|
334
|
+
# lazy utilities
|
|
335
|
+
"_check_for_numpy",
|
|
336
|
+
"_check_for_pandas",
|
|
337
|
+
"_check_for_pyarrow",
|
|
338
|
+
"_check_for_pydantic",
|
|
339
|
+
"_check_for_torch",
|
|
340
|
+
"_check_for_pytz",
|
|
341
|
+
# exported flags/guards
|
|
342
|
+
"_ALTAIR_AVAILABLE",
|
|
343
|
+
"_DELTALAKE_AVAILABLE",
|
|
344
|
+
"_FSSPEC_AVAILABLE",
|
|
345
|
+
"_GEVENT_AVAILABLE",
|
|
346
|
+
"_GREAT_TABLES_AVAILABLE",
|
|
347
|
+
"_HYPOTHESIS_AVAILABLE",
|
|
348
|
+
"_NUMPY_AVAILABLE",
|
|
349
|
+
"_PANDAS_AVAILABLE",
|
|
350
|
+
"_POLARS_CLOUD_AVAILABLE",
|
|
351
|
+
"_PYARROW_AVAILABLE",
|
|
352
|
+
"_PYDANTIC_AVAILABLE",
|
|
353
|
+
"_PYICEBERG_AVAILABLE",
|
|
354
|
+
"_TORCH_AVAILABLE",
|
|
355
|
+
]
|