Add files using upload-large-folder tool
Browse files- LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/fsspec/__init__.py +71 -0
- LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/fsspec/asyn.py +1127 -0
- LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/fsspec/fuse.py +324 -0
- LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/fsspec/generic.py +396 -0
- LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/fsspec/mapping.py +251 -0
- LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/fsspec/utils.py +748 -0
- LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/numpy/ma/API_CHANGES.txt +135 -0
- LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/numpy/ma/LICENSE +24 -0
- LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/numpy/ma/README.rst +236 -0
- LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/numpy/ma/__init__.py +54 -0
- LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/numpy/ma/__init__.pyi +234 -0
- LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/numpy/ma/core.py +0 -0
- LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/numpy/ma/core.pyi +471 -0
- LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/numpy/ma/extras.py +2133 -0
- LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/numpy/ma/extras.pyi +85 -0
- LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/numpy/ma/mrecords.py +783 -0
- LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/numpy/ma/mrecords.pyi +90 -0
- LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/numpy/ma/setup.py +12 -0
- LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/models/qwen3_vl_moe/configuration_qwen3_vl_moe.py +194 -0
- LTA_openwebtext_dualt/mini_owt_logdirichlet/logs/infer_not5_bottleneck128_170k_decode32_ema_20260611/lr2e3.log +29 -0
LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/fsspec/__init__.py
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from . import caching
|
| 2 |
+
from ._version import __version__ # noqa: F401
|
| 3 |
+
from .callbacks import Callback
|
| 4 |
+
from .compression import available_compressions
|
| 5 |
+
from .core import get_fs_token_paths, open, open_files, open_local, url_to_fs
|
| 6 |
+
from .exceptions import FSTimeoutError
|
| 7 |
+
from .mapping import FSMap, get_mapper
|
| 8 |
+
from .registry import (
|
| 9 |
+
available_protocols,
|
| 10 |
+
filesystem,
|
| 11 |
+
get_filesystem_class,
|
| 12 |
+
register_implementation,
|
| 13 |
+
registry,
|
| 14 |
+
)
|
| 15 |
+
from .spec import AbstractFileSystem
|
| 16 |
+
|
| 17 |
+
__all__ = [
|
| 18 |
+
"AbstractFileSystem",
|
| 19 |
+
"FSTimeoutError",
|
| 20 |
+
"FSMap",
|
| 21 |
+
"filesystem",
|
| 22 |
+
"register_implementation",
|
| 23 |
+
"get_filesystem_class",
|
| 24 |
+
"get_fs_token_paths",
|
| 25 |
+
"get_mapper",
|
| 26 |
+
"open",
|
| 27 |
+
"open_files",
|
| 28 |
+
"open_local",
|
| 29 |
+
"registry",
|
| 30 |
+
"caching",
|
| 31 |
+
"Callback",
|
| 32 |
+
"available_protocols",
|
| 33 |
+
"available_compressions",
|
| 34 |
+
"url_to_fs",
|
| 35 |
+
]
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
def process_entries():
|
| 39 |
+
try:
|
| 40 |
+
from importlib.metadata import entry_points
|
| 41 |
+
except ImportError:
|
| 42 |
+
return
|
| 43 |
+
if entry_points is not None:
|
| 44 |
+
try:
|
| 45 |
+
eps = entry_points()
|
| 46 |
+
except TypeError:
|
| 47 |
+
pass # importlib-metadata < 0.8
|
| 48 |
+
else:
|
| 49 |
+
if hasattr(eps, "select"): # Python 3.10+ / importlib_metadata >= 3.9.0
|
| 50 |
+
specs = eps.select(group="fsspec.specs")
|
| 51 |
+
else:
|
| 52 |
+
specs = eps.get("fsspec.specs", [])
|
| 53 |
+
registered_names = {}
|
| 54 |
+
for spec in specs:
|
| 55 |
+
err_msg = f"Unable to load filesystem from {spec}"
|
| 56 |
+
name = spec.name
|
| 57 |
+
if name in registered_names:
|
| 58 |
+
continue
|
| 59 |
+
registered_names[name] = True
|
| 60 |
+
register_implementation(
|
| 61 |
+
name,
|
| 62 |
+
spec.value.replace(":", "."),
|
| 63 |
+
errtxt=err_msg,
|
| 64 |
+
# We take our implementations as the ones to overload with if
|
| 65 |
+
# for some reason we encounter some, may be the same, already
|
| 66 |
+
# registered
|
| 67 |
+
clobber=True,
|
| 68 |
+
)
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
process_entries()
|
LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/fsspec/asyn.py
ADDED
|
@@ -0,0 +1,1127 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import asyncio
|
| 2 |
+
import asyncio.events
|
| 3 |
+
import functools
|
| 4 |
+
import inspect
|
| 5 |
+
import io
|
| 6 |
+
import numbers
|
| 7 |
+
import os
|
| 8 |
+
import re
|
| 9 |
+
import threading
|
| 10 |
+
from collections.abc import Iterable
|
| 11 |
+
from glob import has_magic
|
| 12 |
+
from typing import TYPE_CHECKING
|
| 13 |
+
|
| 14 |
+
from .callbacks import DEFAULT_CALLBACK
|
| 15 |
+
from .exceptions import FSTimeoutError
|
| 16 |
+
from .implementations.local import LocalFileSystem, make_path_posix, trailing_sep
|
| 17 |
+
from .spec import AbstractBufferedFile, AbstractFileSystem
|
| 18 |
+
from .utils import glob_translate, is_exception, other_paths
|
| 19 |
+
|
| 20 |
+
private = re.compile("_[^_]")
|
| 21 |
+
iothread = [None] # dedicated fsspec IO thread
|
| 22 |
+
loop = [None] # global event loop for any non-async instance
|
| 23 |
+
_lock = None # global lock placeholder
|
| 24 |
+
get_running_loop = asyncio.get_running_loop
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
def get_lock():
|
| 28 |
+
"""Allocate or return a threading lock.
|
| 29 |
+
|
| 30 |
+
The lock is allocated on first use to allow setting one lock per forked process.
|
| 31 |
+
"""
|
| 32 |
+
global _lock
|
| 33 |
+
if not _lock:
|
| 34 |
+
_lock = threading.Lock()
|
| 35 |
+
return _lock
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
def reset_lock():
|
| 39 |
+
"""Reset the global lock.
|
| 40 |
+
|
| 41 |
+
This should be called only on the init of a forked process to reset the lock to
|
| 42 |
+
None, enabling the new forked process to get a new lock.
|
| 43 |
+
"""
|
| 44 |
+
global _lock
|
| 45 |
+
|
| 46 |
+
iothread[0] = None
|
| 47 |
+
loop[0] = None
|
| 48 |
+
_lock = None
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
async def _runner(event, coro, result, timeout=None):
|
| 52 |
+
timeout = timeout if timeout else None # convert 0 or 0.0 to None
|
| 53 |
+
if timeout is not None:
|
| 54 |
+
coro = asyncio.wait_for(coro, timeout=timeout)
|
| 55 |
+
try:
|
| 56 |
+
result[0] = await coro
|
| 57 |
+
except Exception as ex:
|
| 58 |
+
result[0] = ex
|
| 59 |
+
finally:
|
| 60 |
+
event.set()
|
| 61 |
+
|
| 62 |
+
|
| 63 |
+
def sync(loop, func, *args, timeout=None, **kwargs):
|
| 64 |
+
"""
|
| 65 |
+
Make loop run coroutine until it returns. Runs in other thread
|
| 66 |
+
|
| 67 |
+
Examples
|
| 68 |
+
--------
|
| 69 |
+
>>> fsspec.asyn.sync(fsspec.asyn.get_loop(), func, *args,
|
| 70 |
+
timeout=timeout, **kwargs)
|
| 71 |
+
"""
|
| 72 |
+
timeout = timeout if timeout else None # convert 0 or 0.0 to None
|
| 73 |
+
# NB: if the loop is not running *yet*, it is OK to submit work
|
| 74 |
+
# and we will wait for it
|
| 75 |
+
if loop is None or loop.is_closed():
|
| 76 |
+
raise RuntimeError("Loop is not running")
|
| 77 |
+
try:
|
| 78 |
+
loop0 = asyncio.events.get_running_loop()
|
| 79 |
+
if loop0 is loop:
|
| 80 |
+
raise NotImplementedError("Calling sync() from within a running loop")
|
| 81 |
+
except NotImplementedError:
|
| 82 |
+
raise
|
| 83 |
+
except RuntimeError:
|
| 84 |
+
pass
|
| 85 |
+
coro = func(*args, **kwargs)
|
| 86 |
+
result = [None]
|
| 87 |
+
event = threading.Event()
|
| 88 |
+
asyncio.run_coroutine_threadsafe(_runner(event, coro, result, timeout), loop)
|
| 89 |
+
while True:
|
| 90 |
+
# this loops allows thread to get interrupted
|
| 91 |
+
if event.wait(1):
|
| 92 |
+
break
|
| 93 |
+
if timeout is not None:
|
| 94 |
+
timeout -= 1
|
| 95 |
+
if timeout < 0:
|
| 96 |
+
raise FSTimeoutError
|
| 97 |
+
|
| 98 |
+
return_result = result[0]
|
| 99 |
+
if isinstance(return_result, asyncio.TimeoutError):
|
| 100 |
+
# suppress asyncio.TimeoutError, raise FSTimeoutError
|
| 101 |
+
raise FSTimeoutError from return_result
|
| 102 |
+
elif isinstance(return_result, BaseException):
|
| 103 |
+
raise return_result
|
| 104 |
+
else:
|
| 105 |
+
return return_result
|
| 106 |
+
|
| 107 |
+
|
| 108 |
+
def sync_wrapper(func, obj=None):
|
| 109 |
+
"""Given a function, make so can be called in blocking contexts
|
| 110 |
+
|
| 111 |
+
Leave obj=None if defining within a class. Pass the instance if attaching
|
| 112 |
+
as an attribute of the instance.
|
| 113 |
+
"""
|
| 114 |
+
|
| 115 |
+
@functools.wraps(func)
|
| 116 |
+
def wrapper(*args, **kwargs):
|
| 117 |
+
self = obj or args[0]
|
| 118 |
+
return sync(self.loop, func, *args, **kwargs)
|
| 119 |
+
|
| 120 |
+
return wrapper
|
| 121 |
+
|
| 122 |
+
|
| 123 |
+
def get_loop():
|
| 124 |
+
"""Create or return the default fsspec IO loop
|
| 125 |
+
|
| 126 |
+
The loop will be running on a separate thread.
|
| 127 |
+
"""
|
| 128 |
+
if loop[0] is None:
|
| 129 |
+
with get_lock():
|
| 130 |
+
# repeat the check just in case the loop got filled between the
|
| 131 |
+
# previous two calls from another thread
|
| 132 |
+
if loop[0] is None:
|
| 133 |
+
loop[0] = asyncio.new_event_loop()
|
| 134 |
+
th = threading.Thread(target=loop[0].run_forever, name="fsspecIO")
|
| 135 |
+
th.daemon = True
|
| 136 |
+
th.start()
|
| 137 |
+
iothread[0] = th
|
| 138 |
+
return loop[0]
|
| 139 |
+
|
| 140 |
+
|
| 141 |
+
def reset_after_fork():
|
| 142 |
+
global lock
|
| 143 |
+
loop[0] = None
|
| 144 |
+
iothread[0] = None
|
| 145 |
+
lock = None
|
| 146 |
+
|
| 147 |
+
|
| 148 |
+
if hasattr(os, "register_at_fork"):
|
| 149 |
+
# should be posix; this will do nothing for spawn or forkserver subprocesses
|
| 150 |
+
os.register_at_fork(after_in_child=reset_after_fork)
|
| 151 |
+
|
| 152 |
+
|
| 153 |
+
if TYPE_CHECKING:
|
| 154 |
+
import resource
|
| 155 |
+
|
| 156 |
+
ResourceError = resource.error
|
| 157 |
+
else:
|
| 158 |
+
try:
|
| 159 |
+
import resource
|
| 160 |
+
except ImportError:
|
| 161 |
+
resource = None
|
| 162 |
+
ResourceError = OSError
|
| 163 |
+
else:
|
| 164 |
+
ResourceError = getattr(resource, "error", OSError)
|
| 165 |
+
|
| 166 |
+
_DEFAULT_BATCH_SIZE = 128
|
| 167 |
+
_NOFILES_DEFAULT_BATCH_SIZE = 1280
|
| 168 |
+
|
| 169 |
+
|
| 170 |
+
def _get_batch_size(nofiles=False):
|
| 171 |
+
from fsspec.config import conf
|
| 172 |
+
|
| 173 |
+
if nofiles:
|
| 174 |
+
if "nofiles_gather_batch_size" in conf:
|
| 175 |
+
return conf["nofiles_gather_batch_size"]
|
| 176 |
+
else:
|
| 177 |
+
if "gather_batch_size" in conf:
|
| 178 |
+
return conf["gather_batch_size"]
|
| 179 |
+
if nofiles:
|
| 180 |
+
return _NOFILES_DEFAULT_BATCH_SIZE
|
| 181 |
+
if resource is None:
|
| 182 |
+
return _DEFAULT_BATCH_SIZE
|
| 183 |
+
|
| 184 |
+
try:
|
| 185 |
+
soft_limit, _ = resource.getrlimit(resource.RLIMIT_NOFILE)
|
| 186 |
+
except (ImportError, ValueError, ResourceError):
|
| 187 |
+
return _DEFAULT_BATCH_SIZE
|
| 188 |
+
|
| 189 |
+
if soft_limit == resource.RLIM_INFINITY:
|
| 190 |
+
return -1
|
| 191 |
+
else:
|
| 192 |
+
return soft_limit // 8
|
| 193 |
+
|
| 194 |
+
|
| 195 |
+
def running_async() -> bool:
|
| 196 |
+
"""Being executed by an event loop?"""
|
| 197 |
+
try:
|
| 198 |
+
asyncio.get_running_loop()
|
| 199 |
+
return True
|
| 200 |
+
except RuntimeError:
|
| 201 |
+
return False
|
| 202 |
+
|
| 203 |
+
|
| 204 |
+
async def _run_coros_in_chunks(
|
| 205 |
+
coros,
|
| 206 |
+
batch_size=None,
|
| 207 |
+
callback=DEFAULT_CALLBACK,
|
| 208 |
+
timeout=None,
|
| 209 |
+
return_exceptions=False,
|
| 210 |
+
nofiles=False,
|
| 211 |
+
):
|
| 212 |
+
"""Run the given coroutines in chunks.
|
| 213 |
+
|
| 214 |
+
Parameters
|
| 215 |
+
----------
|
| 216 |
+
coros: list of coroutines to run
|
| 217 |
+
batch_size: int or None
|
| 218 |
+
Number of coroutines to submit/wait on simultaneously.
|
| 219 |
+
If -1, then it will not be any throttling. If
|
| 220 |
+
None, it will be inferred from _get_batch_size()
|
| 221 |
+
callback: fsspec.callbacks.Callback instance
|
| 222 |
+
Gets a relative_update when each coroutine completes
|
| 223 |
+
timeout: number or None
|
| 224 |
+
If given, each coroutine times out after this time. Note that, since
|
| 225 |
+
there are multiple batches, the total run time of this function will in
|
| 226 |
+
general be longer
|
| 227 |
+
return_exceptions: bool
|
| 228 |
+
Same meaning as in asyncio.gather
|
| 229 |
+
nofiles: bool
|
| 230 |
+
If inferring the batch_size, does this operation involve local files?
|
| 231 |
+
If yes, you normally expect smaller batches.
|
| 232 |
+
"""
|
| 233 |
+
|
| 234 |
+
if batch_size is None:
|
| 235 |
+
batch_size = _get_batch_size(nofiles=nofiles)
|
| 236 |
+
|
| 237 |
+
if batch_size == -1:
|
| 238 |
+
batch_size = len(coros)
|
| 239 |
+
|
| 240 |
+
assert batch_size > 0
|
| 241 |
+
|
| 242 |
+
async def _run_coro(coro, i):
|
| 243 |
+
try:
|
| 244 |
+
return await asyncio.wait_for(coro, timeout=timeout), i
|
| 245 |
+
except Exception as e:
|
| 246 |
+
if not return_exceptions:
|
| 247 |
+
raise
|
| 248 |
+
return e, i
|
| 249 |
+
finally:
|
| 250 |
+
callback.relative_update(1)
|
| 251 |
+
|
| 252 |
+
i = 0
|
| 253 |
+
n = len(coros)
|
| 254 |
+
results = [None] * n
|
| 255 |
+
pending = set()
|
| 256 |
+
|
| 257 |
+
while pending or i < n:
|
| 258 |
+
while len(pending) < batch_size and i < n:
|
| 259 |
+
pending.add(asyncio.ensure_future(_run_coro(coros[i], i)))
|
| 260 |
+
i += 1
|
| 261 |
+
|
| 262 |
+
if not pending:
|
| 263 |
+
break
|
| 264 |
+
|
| 265 |
+
done, pending = await asyncio.wait(pending, return_when=asyncio.FIRST_COMPLETED)
|
| 266 |
+
first_exc = None
|
| 267 |
+
while done:
|
| 268 |
+
task = done.pop()
|
| 269 |
+
try:
|
| 270 |
+
result, k = await task
|
| 271 |
+
results[k] = result
|
| 272 |
+
except Exception as exc:
|
| 273 |
+
if first_exc is None:
|
| 274 |
+
first_exc = exc
|
| 275 |
+
|
| 276 |
+
if first_exc is not None:
|
| 277 |
+
for task in pending:
|
| 278 |
+
task.cancel()
|
| 279 |
+
if pending:
|
| 280 |
+
await asyncio.gather(*pending, return_exceptions=True)
|
| 281 |
+
raise first_exc
|
| 282 |
+
|
| 283 |
+
return results
|
| 284 |
+
|
| 285 |
+
|
| 286 |
+
# these methods should be implemented as async by any async-able backend
|
| 287 |
+
async_methods = [
|
| 288 |
+
"_ls",
|
| 289 |
+
"_cat_file",
|
| 290 |
+
"_get_file",
|
| 291 |
+
"_put_file",
|
| 292 |
+
"_rm_file",
|
| 293 |
+
"_cp_file",
|
| 294 |
+
"_pipe_file",
|
| 295 |
+
"_expand_path",
|
| 296 |
+
"_info",
|
| 297 |
+
"_isfile",
|
| 298 |
+
"_isdir",
|
| 299 |
+
"_exists",
|
| 300 |
+
"_walk",
|
| 301 |
+
"_glob",
|
| 302 |
+
"_find",
|
| 303 |
+
"_du",
|
| 304 |
+
"_size",
|
| 305 |
+
"_mkdir",
|
| 306 |
+
"_makedirs",
|
| 307 |
+
]
|
| 308 |
+
|
| 309 |
+
|
| 310 |
+
class AsyncFileSystem(AbstractFileSystem):
|
| 311 |
+
"""Async file operations, default implementations
|
| 312 |
+
|
| 313 |
+
Passes bulk operations to asyncio.gather for concurrent operation.
|
| 314 |
+
|
| 315 |
+
Implementations that have concurrent batch operations and/or async methods
|
| 316 |
+
should inherit from this class instead of AbstractFileSystem. Docstrings are
|
| 317 |
+
copied from the un-underscored method in AbstractFileSystem, if not given.
|
| 318 |
+
"""
|
| 319 |
+
|
| 320 |
+
# note that methods do not have docstring here; they will be copied
|
| 321 |
+
# for _* methods and inferred for overridden methods.
|
| 322 |
+
|
| 323 |
+
async_impl = True
|
| 324 |
+
mirror_sync_methods = True
|
| 325 |
+
disable_throttling = False
|
| 326 |
+
|
| 327 |
+
def __init__(self, *args, asynchronous=False, loop=None, batch_size=None, **kwargs):
|
| 328 |
+
self.asynchronous = asynchronous
|
| 329 |
+
self._pid = os.getpid()
|
| 330 |
+
if not asynchronous:
|
| 331 |
+
self._loop = loop or get_loop()
|
| 332 |
+
else:
|
| 333 |
+
self._loop = None
|
| 334 |
+
self.batch_size = batch_size
|
| 335 |
+
super().__init__(*args, **kwargs)
|
| 336 |
+
|
| 337 |
+
@property
|
| 338 |
+
def loop(self):
|
| 339 |
+
if self._pid != os.getpid():
|
| 340 |
+
raise RuntimeError("This class is not fork-safe")
|
| 341 |
+
return self._loop
|
| 342 |
+
|
| 343 |
+
async def _rm_file(self, path, **kwargs):
|
| 344 |
+
if (
|
| 345 |
+
inspect.iscoroutinefunction(self._rm)
|
| 346 |
+
and type(self)._rm is not AsyncFileSystem._rm
|
| 347 |
+
):
|
| 348 |
+
return await self._rm(path, recursive=False, batch_size=1, **kwargs)
|
| 349 |
+
raise NotImplementedError
|
| 350 |
+
|
| 351 |
+
async def _rm(self, path, recursive=False, batch_size=None, **kwargs):
|
| 352 |
+
# TODO: implement on_error
|
| 353 |
+
batch_size = batch_size or self.batch_size
|
| 354 |
+
path = await self._expand_path(path, recursive=recursive)
|
| 355 |
+
return await _run_coros_in_chunks(
|
| 356 |
+
[self._rm_file(p, **kwargs) for p in reversed(path)],
|
| 357 |
+
batch_size=batch_size,
|
| 358 |
+
nofiles=True,
|
| 359 |
+
)
|
| 360 |
+
|
| 361 |
+
async def _cp_file(self, path1, path2, **kwargs):
|
| 362 |
+
raise NotImplementedError
|
| 363 |
+
|
| 364 |
+
async def _mv_file(self, path1, path2):
|
| 365 |
+
await self._cp_file(path1, path2)
|
| 366 |
+
await self._rm_file(path1)
|
| 367 |
+
|
| 368 |
+
async def _copy(
|
| 369 |
+
self,
|
| 370 |
+
path1,
|
| 371 |
+
path2,
|
| 372 |
+
recursive=False,
|
| 373 |
+
on_error=None,
|
| 374 |
+
maxdepth=None,
|
| 375 |
+
batch_size=None,
|
| 376 |
+
**kwargs,
|
| 377 |
+
):
|
| 378 |
+
if on_error is None and recursive:
|
| 379 |
+
on_error = "ignore"
|
| 380 |
+
elif on_error is None:
|
| 381 |
+
on_error = "raise"
|
| 382 |
+
|
| 383 |
+
if isinstance(path1, list) and isinstance(path2, list):
|
| 384 |
+
# No need to expand paths when both source and destination
|
| 385 |
+
# are provided as lists
|
| 386 |
+
paths1 = path1
|
| 387 |
+
paths2 = path2
|
| 388 |
+
else:
|
| 389 |
+
source_is_str = isinstance(path1, str)
|
| 390 |
+
paths1 = await self._expand_path(
|
| 391 |
+
path1, maxdepth=maxdepth, recursive=recursive
|
| 392 |
+
)
|
| 393 |
+
if source_is_str and (not recursive or maxdepth is not None):
|
| 394 |
+
# Non-recursive glob does not copy directories
|
| 395 |
+
paths1 = [
|
| 396 |
+
p for p in paths1 if not (trailing_sep(p) or await self._isdir(p))
|
| 397 |
+
]
|
| 398 |
+
if not paths1:
|
| 399 |
+
return
|
| 400 |
+
|
| 401 |
+
source_is_file = len(paths1) == 1
|
| 402 |
+
dest_is_dir = isinstance(path2, str) and (
|
| 403 |
+
trailing_sep(path2) or await self._isdir(path2)
|
| 404 |
+
)
|
| 405 |
+
|
| 406 |
+
exists = source_is_str and (
|
| 407 |
+
(has_magic(path1) and source_is_file)
|
| 408 |
+
or (not has_magic(path1) and dest_is_dir and not trailing_sep(path1))
|
| 409 |
+
)
|
| 410 |
+
paths2 = other_paths(
|
| 411 |
+
paths1,
|
| 412 |
+
path2,
|
| 413 |
+
exists=exists,
|
| 414 |
+
flatten=not source_is_str,
|
| 415 |
+
)
|
| 416 |
+
|
| 417 |
+
batch_size = batch_size or self.batch_size
|
| 418 |
+
coros = [self._cp_file(p1, p2, **kwargs) for p1, p2 in zip(paths1, paths2)]
|
| 419 |
+
result = await _run_coros_in_chunks(
|
| 420 |
+
coros, batch_size=batch_size, return_exceptions=True, nofiles=True
|
| 421 |
+
)
|
| 422 |
+
|
| 423 |
+
for ex in filter(is_exception, result):
|
| 424 |
+
if on_error == "ignore" and isinstance(ex, FileNotFoundError):
|
| 425 |
+
continue
|
| 426 |
+
raise ex
|
| 427 |
+
|
| 428 |
+
async def _pipe_file(self, path, value, mode="overwrite", **kwargs):
|
| 429 |
+
raise NotImplementedError
|
| 430 |
+
|
| 431 |
+
async def _pipe(self, path, value=None, batch_size=None, **kwargs):
|
| 432 |
+
if isinstance(path, str):
|
| 433 |
+
path = {path: value}
|
| 434 |
+
batch_size = batch_size or self.batch_size
|
| 435 |
+
return await _run_coros_in_chunks(
|
| 436 |
+
[self._pipe_file(k, v, **kwargs) for k, v in path.items()],
|
| 437 |
+
batch_size=batch_size,
|
| 438 |
+
nofiles=True,
|
| 439 |
+
)
|
| 440 |
+
|
| 441 |
+
async def _process_limits(self, url, start, end):
|
| 442 |
+
"""Helper for "Range"-based _cat_file"""
|
| 443 |
+
size = None
|
| 444 |
+
suff = False
|
| 445 |
+
if start is not None and start < 0:
|
| 446 |
+
# if start is negative and end None, end is the "suffix length"
|
| 447 |
+
if end is None:
|
| 448 |
+
end = -start
|
| 449 |
+
start = ""
|
| 450 |
+
suff = True
|
| 451 |
+
else:
|
| 452 |
+
size = size or (await self._info(url))["size"]
|
| 453 |
+
start = size + start
|
| 454 |
+
elif start is None:
|
| 455 |
+
start = 0
|
| 456 |
+
if not suff:
|
| 457 |
+
if end is not None and end < 0:
|
| 458 |
+
if start is not None:
|
| 459 |
+
size = size or (await self._info(url))["size"]
|
| 460 |
+
end = size + end
|
| 461 |
+
elif end is None:
|
| 462 |
+
end = ""
|
| 463 |
+
if isinstance(end, numbers.Integral):
|
| 464 |
+
end -= 1 # bytes range is inclusive
|
| 465 |
+
return f"bytes={start}-{end}"
|
| 466 |
+
|
| 467 |
+
async def _cat_file(self, path, start=None, end=None, **kwargs):
|
| 468 |
+
raise NotImplementedError
|
| 469 |
+
|
| 470 |
+
async def _cat(
|
| 471 |
+
self, path, recursive=False, on_error="raise", batch_size=None, **kwargs
|
| 472 |
+
):
|
| 473 |
+
paths = await self._expand_path(path, recursive=recursive)
|
| 474 |
+
coros = [self._cat_file(path, **kwargs) for path in paths]
|
| 475 |
+
batch_size = batch_size or self.batch_size
|
| 476 |
+
out = await _run_coros_in_chunks(
|
| 477 |
+
coros, batch_size=batch_size, nofiles=True, return_exceptions=True
|
| 478 |
+
)
|
| 479 |
+
if on_error == "raise":
|
| 480 |
+
ex = next(filter(is_exception, out), False)
|
| 481 |
+
if ex:
|
| 482 |
+
raise ex
|
| 483 |
+
if (
|
| 484 |
+
len(paths) > 1
|
| 485 |
+
or isinstance(path, list)
|
| 486 |
+
or paths[0] != self._strip_protocol(path)
|
| 487 |
+
):
|
| 488 |
+
return {
|
| 489 |
+
k: v
|
| 490 |
+
for k, v in zip(paths, out)
|
| 491 |
+
if on_error != "omit" or not is_exception(v)
|
| 492 |
+
}
|
| 493 |
+
else:
|
| 494 |
+
return out[0]
|
| 495 |
+
|
| 496 |
+
async def _cat_ranges(
|
| 497 |
+
self,
|
| 498 |
+
paths,
|
| 499 |
+
starts,
|
| 500 |
+
ends,
|
| 501 |
+
max_gap=None,
|
| 502 |
+
batch_size=None,
|
| 503 |
+
on_error="return",
|
| 504 |
+
**kwargs,
|
| 505 |
+
):
|
| 506 |
+
"""Get the contents of byte ranges from one or more files
|
| 507 |
+
|
| 508 |
+
Parameters
|
| 509 |
+
----------
|
| 510 |
+
paths: list
|
| 511 |
+
A list of of filepaths on this filesystems
|
| 512 |
+
starts, ends: int or list
|
| 513 |
+
Bytes limits of the read. If using a single int, the same value will be
|
| 514 |
+
used to read all the specified files.
|
| 515 |
+
"""
|
| 516 |
+
# TODO: on_error
|
| 517 |
+
if max_gap is not None:
|
| 518 |
+
# use utils.merge_offset_ranges
|
| 519 |
+
raise NotImplementedError
|
| 520 |
+
if not isinstance(paths, list):
|
| 521 |
+
raise TypeError
|
| 522 |
+
if not isinstance(starts, Iterable):
|
| 523 |
+
starts = [starts] * len(paths)
|
| 524 |
+
if not isinstance(ends, Iterable):
|
| 525 |
+
ends = [ends] * len(paths)
|
| 526 |
+
if len(starts) != len(paths) or len(ends) != len(paths):
|
| 527 |
+
raise ValueError
|
| 528 |
+
coros = [
|
| 529 |
+
self._cat_file(p, start=s, end=e, **kwargs)
|
| 530 |
+
for p, s, e in zip(paths, starts, ends)
|
| 531 |
+
]
|
| 532 |
+
batch_size = batch_size or self.batch_size
|
| 533 |
+
return await _run_coros_in_chunks(
|
| 534 |
+
coros, batch_size=batch_size, nofiles=True, return_exceptions=True
|
| 535 |
+
)
|
| 536 |
+
|
| 537 |
+
async def _put_file(self, lpath, rpath, mode="overwrite", **kwargs):
|
| 538 |
+
raise NotImplementedError
|
| 539 |
+
|
| 540 |
+
async def _put(
|
| 541 |
+
self,
|
| 542 |
+
lpath,
|
| 543 |
+
rpath,
|
| 544 |
+
recursive=False,
|
| 545 |
+
callback=DEFAULT_CALLBACK,
|
| 546 |
+
batch_size=None,
|
| 547 |
+
maxdepth=None,
|
| 548 |
+
**kwargs,
|
| 549 |
+
):
|
| 550 |
+
"""Copy file(s) from local.
|
| 551 |
+
|
| 552 |
+
Copies a specific file or tree of files (if recursive=True). If rpath
|
| 553 |
+
ends with a "/", it will be assumed to be a directory, and target files
|
| 554 |
+
will go within.
|
| 555 |
+
|
| 556 |
+
The put_file method will be called concurrently on a batch of files. The
|
| 557 |
+
batch_size option can configure the amount of futures that can be executed
|
| 558 |
+
at the same time. If it is -1, then all the files will be uploaded concurrently.
|
| 559 |
+
The default can be set for this instance by passing "batch_size" in the
|
| 560 |
+
constructor, or for all instances by setting the "gather_batch_size" key
|
| 561 |
+
in ``fsspec.config.conf``, falling back to 1/8th of the system limit .
|
| 562 |
+
"""
|
| 563 |
+
if isinstance(lpath, list) and isinstance(rpath, list):
|
| 564 |
+
# No need to expand paths when both source and destination
|
| 565 |
+
# are provided as lists
|
| 566 |
+
rpaths = rpath
|
| 567 |
+
lpaths = lpath
|
| 568 |
+
else:
|
| 569 |
+
source_is_str = isinstance(lpath, str)
|
| 570 |
+
if source_is_str:
|
| 571 |
+
lpath = make_path_posix(lpath)
|
| 572 |
+
fs = LocalFileSystem()
|
| 573 |
+
lpaths = fs.expand_path(lpath, recursive=recursive, maxdepth=maxdepth)
|
| 574 |
+
if source_is_str and (not recursive or maxdepth is not None):
|
| 575 |
+
# Non-recursive glob does not copy directories
|
| 576 |
+
lpaths = [p for p in lpaths if not (trailing_sep(p) or fs.isdir(p))]
|
| 577 |
+
if not lpaths:
|
| 578 |
+
return
|
| 579 |
+
|
| 580 |
+
source_is_file = len(lpaths) == 1
|
| 581 |
+
dest_is_dir = isinstance(rpath, str) and (
|
| 582 |
+
trailing_sep(rpath) or await self._isdir(rpath)
|
| 583 |
+
)
|
| 584 |
+
|
| 585 |
+
rpath = self._strip_protocol(rpath)
|
| 586 |
+
exists = source_is_str and (
|
| 587 |
+
(has_magic(lpath) and source_is_file)
|
| 588 |
+
or (not has_magic(lpath) and dest_is_dir and not trailing_sep(lpath))
|
| 589 |
+
)
|
| 590 |
+
rpaths = other_paths(
|
| 591 |
+
lpaths,
|
| 592 |
+
rpath,
|
| 593 |
+
exists=exists,
|
| 594 |
+
flatten=not source_is_str,
|
| 595 |
+
)
|
| 596 |
+
|
| 597 |
+
is_dir = {l: os.path.isdir(l) for l in lpaths}
|
| 598 |
+
rdirs = [r for l, r in zip(lpaths, rpaths) if is_dir[l]]
|
| 599 |
+
file_pairs = [(l, r) for l, r in zip(lpaths, rpaths) if not is_dir[l]]
|
| 600 |
+
|
| 601 |
+
await asyncio.gather(*[self._makedirs(d, exist_ok=True) for d in rdirs])
|
| 602 |
+
batch_size = batch_size or self.batch_size
|
| 603 |
+
|
| 604 |
+
coros = []
|
| 605 |
+
callback.set_size(len(file_pairs))
|
| 606 |
+
for lfile, rfile in file_pairs:
|
| 607 |
+
put_file = callback.branch_coro(self._put_file)
|
| 608 |
+
coros.append(put_file(lfile, rfile, **kwargs))
|
| 609 |
+
|
| 610 |
+
return await _run_coros_in_chunks(
|
| 611 |
+
coros, batch_size=batch_size, callback=callback
|
| 612 |
+
)
|
| 613 |
+
|
| 614 |
+
async def _get_file(self, rpath, lpath, **kwargs):
|
| 615 |
+
raise NotImplementedError
|
| 616 |
+
|
| 617 |
+
async def _get(
|
| 618 |
+
self,
|
| 619 |
+
rpath,
|
| 620 |
+
lpath,
|
| 621 |
+
recursive=False,
|
| 622 |
+
callback=DEFAULT_CALLBACK,
|
| 623 |
+
maxdepth=None,
|
| 624 |
+
**kwargs,
|
| 625 |
+
):
|
| 626 |
+
"""Copy file(s) to local.
|
| 627 |
+
|
| 628 |
+
Copies a specific file or tree of files (if recursive=True). If lpath
|
| 629 |
+
ends with a "/", it will be assumed to be a directory, and target files
|
| 630 |
+
will go within. Can submit a list of paths, which may be glob-patterns
|
| 631 |
+
and will be expanded.
|
| 632 |
+
|
| 633 |
+
The get_file method will be called concurrently on a batch of files. The
|
| 634 |
+
batch_size option can configure the amount of futures that can be executed
|
| 635 |
+
at the same time. If it is -1, then all the files will be uploaded concurrently.
|
| 636 |
+
The default can be set for this instance by passing "batch_size" in the
|
| 637 |
+
constructor, or for all instances by setting the "gather_batch_size" key
|
| 638 |
+
in ``fsspec.config.conf``, falling back to 1/8th of the system limit .
|
| 639 |
+
"""
|
| 640 |
+
if isinstance(lpath, list) and isinstance(rpath, list):
|
| 641 |
+
# No need to expand paths when both source and destination
|
| 642 |
+
# are provided as lists
|
| 643 |
+
rpaths = rpath
|
| 644 |
+
lpaths = lpath
|
| 645 |
+
else:
|
| 646 |
+
source_is_str = isinstance(rpath, str)
|
| 647 |
+
# First check for rpath trailing slash as _strip_protocol removes it.
|
| 648 |
+
source_not_trailing_sep = source_is_str and not trailing_sep(rpath)
|
| 649 |
+
rpath = self._strip_protocol(rpath)
|
| 650 |
+
rpaths = await self._expand_path(
|
| 651 |
+
rpath, recursive=recursive, maxdepth=maxdepth
|
| 652 |
+
)
|
| 653 |
+
if source_is_str and (not recursive or maxdepth is not None):
|
| 654 |
+
# Non-recursive glob does not copy directories
|
| 655 |
+
rpaths = [
|
| 656 |
+
p for p in rpaths if not (trailing_sep(p) or await self._isdir(p))
|
| 657 |
+
]
|
| 658 |
+
if not rpaths:
|
| 659 |
+
return
|
| 660 |
+
|
| 661 |
+
lpath = make_path_posix(lpath)
|
| 662 |
+
source_is_file = len(rpaths) == 1
|
| 663 |
+
dest_is_dir = isinstance(lpath, str) and (
|
| 664 |
+
trailing_sep(lpath) or LocalFileSystem().isdir(lpath)
|
| 665 |
+
)
|
| 666 |
+
|
| 667 |
+
exists = source_is_str and (
|
| 668 |
+
(has_magic(rpath) and source_is_file)
|
| 669 |
+
or (not has_magic(rpath) and dest_is_dir and source_not_trailing_sep)
|
| 670 |
+
)
|
| 671 |
+
lpaths = other_paths(
|
| 672 |
+
rpaths,
|
| 673 |
+
lpath,
|
| 674 |
+
exists=exists,
|
| 675 |
+
flatten=not source_is_str,
|
| 676 |
+
)
|
| 677 |
+
|
| 678 |
+
[os.makedirs(os.path.dirname(lp), exist_ok=True) for lp in lpaths]
|
| 679 |
+
batch_size = kwargs.pop("batch_size", self.batch_size)
|
| 680 |
+
|
| 681 |
+
coros = []
|
| 682 |
+
callback.set_size(len(lpaths))
|
| 683 |
+
for lpath, rpath in zip(lpaths, rpaths):
|
| 684 |
+
get_file = callback.branch_coro(self._get_file)
|
| 685 |
+
coros.append(get_file(rpath, lpath, **kwargs))
|
| 686 |
+
return await _run_coros_in_chunks(
|
| 687 |
+
coros, batch_size=batch_size, callback=callback
|
| 688 |
+
)
|
| 689 |
+
|
| 690 |
+
async def _isfile(self, path):
|
| 691 |
+
try:
|
| 692 |
+
return (await self._info(path))["type"] == "file"
|
| 693 |
+
except: # noqa: E722
|
| 694 |
+
return False
|
| 695 |
+
|
| 696 |
+
async def _isdir(self, path):
|
| 697 |
+
try:
|
| 698 |
+
return (await self._info(path))["type"] == "directory"
|
| 699 |
+
except OSError:
|
| 700 |
+
return False
|
| 701 |
+
|
| 702 |
+
async def _size(self, path):
|
| 703 |
+
return (await self._info(path)).get("size", None)
|
| 704 |
+
|
| 705 |
+
async def _sizes(self, paths, batch_size=None):
|
| 706 |
+
batch_size = batch_size or self.batch_size
|
| 707 |
+
return await _run_coros_in_chunks(
|
| 708 |
+
[self._size(p) for p in paths], batch_size=batch_size
|
| 709 |
+
)
|
| 710 |
+
|
| 711 |
+
async def _exists(self, path, **kwargs):
|
| 712 |
+
try:
|
| 713 |
+
await self._info(path, **kwargs)
|
| 714 |
+
return True
|
| 715 |
+
except FileNotFoundError:
|
| 716 |
+
return False
|
| 717 |
+
|
| 718 |
+
async def _info(self, path, **kwargs):
|
| 719 |
+
raise NotImplementedError
|
| 720 |
+
|
| 721 |
+
async def _ls(self, path, detail=True, **kwargs):
|
| 722 |
+
raise NotImplementedError
|
| 723 |
+
|
| 724 |
+
async def _walk(self, path, maxdepth=None, on_error="omit", **kwargs):
|
| 725 |
+
if maxdepth is not None and maxdepth < 1:
|
| 726 |
+
raise ValueError("maxdepth must be at least 1")
|
| 727 |
+
|
| 728 |
+
path = self._strip_protocol(path)
|
| 729 |
+
full_dirs = {}
|
| 730 |
+
dirs = {}
|
| 731 |
+
files = {}
|
| 732 |
+
|
| 733 |
+
detail = kwargs.pop("detail", False)
|
| 734 |
+
try:
|
| 735 |
+
listing = await self._ls(path, detail=True, **kwargs)
|
| 736 |
+
except (FileNotFoundError, OSError) as e:
|
| 737 |
+
if on_error == "raise":
|
| 738 |
+
raise
|
| 739 |
+
elif callable(on_error):
|
| 740 |
+
on_error(e)
|
| 741 |
+
if detail:
|
| 742 |
+
yield path, {}, {}
|
| 743 |
+
else:
|
| 744 |
+
yield path, [], []
|
| 745 |
+
return
|
| 746 |
+
|
| 747 |
+
for info in listing:
|
| 748 |
+
# each info name must be at least [path]/part , but here
|
| 749 |
+
# we check also for names like [path]/part/
|
| 750 |
+
pathname = info["name"].rstrip("/")
|
| 751 |
+
name = pathname.rsplit("/", 1)[-1]
|
| 752 |
+
if info["type"] == "directory" and pathname != path:
|
| 753 |
+
# do not include "self" path
|
| 754 |
+
full_dirs[name] = pathname
|
| 755 |
+
dirs[name] = info
|
| 756 |
+
elif pathname == path:
|
| 757 |
+
# file-like with same name as give path
|
| 758 |
+
files[""] = info
|
| 759 |
+
else:
|
| 760 |
+
files[name] = info
|
| 761 |
+
|
| 762 |
+
if detail:
|
| 763 |
+
yield path, dirs, files
|
| 764 |
+
else:
|
| 765 |
+
yield path, list(dirs), list(files)
|
| 766 |
+
|
| 767 |
+
if maxdepth is not None:
|
| 768 |
+
maxdepth -= 1
|
| 769 |
+
if maxdepth < 1:
|
| 770 |
+
return
|
| 771 |
+
|
| 772 |
+
for d in dirs:
|
| 773 |
+
async for _ in self._walk(
|
| 774 |
+
full_dirs[d], maxdepth=maxdepth, detail=detail, **kwargs
|
| 775 |
+
):
|
| 776 |
+
yield _
|
| 777 |
+
|
| 778 |
+
async def _glob(self, path, maxdepth=None, **kwargs):
|
| 779 |
+
if maxdepth is not None and maxdepth < 1:
|
| 780 |
+
raise ValueError("maxdepth must be at least 1")
|
| 781 |
+
|
| 782 |
+
import re
|
| 783 |
+
|
| 784 |
+
seps = (os.path.sep, os.path.altsep) if os.path.altsep else (os.path.sep,)
|
| 785 |
+
ends_with_sep = path.endswith(seps) # _strip_protocol strips trailing slash
|
| 786 |
+
path = self._strip_protocol(path)
|
| 787 |
+
append_slash_to_dirname = ends_with_sep or path.endswith(
|
| 788 |
+
tuple(sep + "**" for sep in seps)
|
| 789 |
+
)
|
| 790 |
+
idx_star = path.find("*") if path.find("*") >= 0 else len(path)
|
| 791 |
+
idx_qmark = path.find("?") if path.find("?") >= 0 else len(path)
|
| 792 |
+
idx_brace = path.find("[") if path.find("[") >= 0 else len(path)
|
| 793 |
+
|
| 794 |
+
min_idx = min(idx_star, idx_qmark, idx_brace)
|
| 795 |
+
|
| 796 |
+
detail = kwargs.pop("detail", False)
|
| 797 |
+
withdirs = kwargs.pop("withdirs", True)
|
| 798 |
+
|
| 799 |
+
if not has_magic(path):
|
| 800 |
+
if await self._exists(path, **kwargs):
|
| 801 |
+
if not detail:
|
| 802 |
+
return [path]
|
| 803 |
+
else:
|
| 804 |
+
return {path: await self._info(path, **kwargs)}
|
| 805 |
+
else:
|
| 806 |
+
if not detail:
|
| 807 |
+
return [] # glob of non-existent returns empty
|
| 808 |
+
else:
|
| 809 |
+
return {}
|
| 810 |
+
elif "/" in path[:min_idx]:
|
| 811 |
+
first_wildcard_idx = min_idx
|
| 812 |
+
min_idx = path[:min_idx].rindex("/")
|
| 813 |
+
root = path[
|
| 814 |
+
: min_idx + 1
|
| 815 |
+
] # everything up to the last / before the first wildcard
|
| 816 |
+
prefix = path[
|
| 817 |
+
min_idx + 1 : first_wildcard_idx
|
| 818 |
+
] # stem between last "/" and first wildcard
|
| 819 |
+
depth = path[min_idx + 1 :].count("/") + 1
|
| 820 |
+
else:
|
| 821 |
+
root = ""
|
| 822 |
+
prefix = path[:min_idx] # stem up to the first wildcard
|
| 823 |
+
depth = path[min_idx + 1 :].count("/") + 1
|
| 824 |
+
|
| 825 |
+
if "**" in path:
|
| 826 |
+
if maxdepth is not None:
|
| 827 |
+
idx_double_stars = path.find("**")
|
| 828 |
+
depth_double_stars = path[idx_double_stars:].count("/") + 1
|
| 829 |
+
depth = depth - depth_double_stars + maxdepth
|
| 830 |
+
else:
|
| 831 |
+
depth = None
|
| 832 |
+
|
| 833 |
+
# Pass the filename stem as prefix= so backends that support it such as
|
| 834 |
+
# gcsfs, s3fs and adlfs can filter server-side up to the first wildcard.
|
| 835 |
+
if prefix:
|
| 836 |
+
kwargs["prefix"] = prefix
|
| 837 |
+
allpaths = await self._find(
|
| 838 |
+
root, maxdepth=depth, withdirs=withdirs, detail=True, **kwargs
|
| 839 |
+
)
|
| 840 |
+
|
| 841 |
+
pattern = glob_translate(path + ("/" if ends_with_sep else ""))
|
| 842 |
+
pattern = re.compile(pattern)
|
| 843 |
+
|
| 844 |
+
out = {
|
| 845 |
+
p: info
|
| 846 |
+
for p, info in sorted(allpaths.items())
|
| 847 |
+
if pattern.match(
|
| 848 |
+
p + "/"
|
| 849 |
+
if append_slash_to_dirname and info["type"] == "directory"
|
| 850 |
+
else p
|
| 851 |
+
)
|
| 852 |
+
}
|
| 853 |
+
|
| 854 |
+
if detail:
|
| 855 |
+
return out
|
| 856 |
+
else:
|
| 857 |
+
return list(out)
|
| 858 |
+
|
| 859 |
+
async def _du(self, path, total=True, maxdepth=None, **kwargs):
|
| 860 |
+
sizes = {}
|
| 861 |
+
# async for?
|
| 862 |
+
for f in await self._find(path, maxdepth=maxdepth, **kwargs):
|
| 863 |
+
info = await self._info(f)
|
| 864 |
+
sizes[info["name"]] = info["size"]
|
| 865 |
+
if total:
|
| 866 |
+
return sum(sizes.values())
|
| 867 |
+
else:
|
| 868 |
+
return sizes
|
| 869 |
+
|
| 870 |
+
async def _find(self, path, maxdepth=None, withdirs=False, **kwargs):
|
| 871 |
+
path = self._strip_protocol(path)
|
| 872 |
+
out = {}
|
| 873 |
+
detail = kwargs.pop("detail", False)
|
| 874 |
+
|
| 875 |
+
# Add the root directory if withdirs is requested
|
| 876 |
+
# This is needed for posix glob compliance
|
| 877 |
+
if withdirs and path != "" and await self._isdir(path):
|
| 878 |
+
out[path] = await self._info(path)
|
| 879 |
+
|
| 880 |
+
# async for?
|
| 881 |
+
async for _, dirs, files in self._walk(path, maxdepth, detail=True, **kwargs):
|
| 882 |
+
if withdirs:
|
| 883 |
+
files.update(dirs)
|
| 884 |
+
out.update({info["name"]: info for name, info in files.items()})
|
| 885 |
+
if not out and (await self._isfile(path)):
|
| 886 |
+
# walk works on directories, but find should also return [path]
|
| 887 |
+
# when path happens to be a file
|
| 888 |
+
out[path] = {}
|
| 889 |
+
names = sorted(out)
|
| 890 |
+
if not detail:
|
| 891 |
+
return names
|
| 892 |
+
else:
|
| 893 |
+
return {name: out[name] for name in names}
|
| 894 |
+
|
| 895 |
+
async def _expand_path(self, path, recursive=False, maxdepth=None):
|
| 896 |
+
if maxdepth is not None and maxdepth < 1:
|
| 897 |
+
raise ValueError("maxdepth must be at least 1")
|
| 898 |
+
|
| 899 |
+
if isinstance(path, str):
|
| 900 |
+
out = await self._expand_path([path], recursive, maxdepth)
|
| 901 |
+
else:
|
| 902 |
+
out = set()
|
| 903 |
+
path = [self._strip_protocol(p) for p in path]
|
| 904 |
+
for p in path: # can gather here
|
| 905 |
+
if has_magic(p):
|
| 906 |
+
bit = set(await self._glob(p, maxdepth=maxdepth))
|
| 907 |
+
out |= bit
|
| 908 |
+
if recursive:
|
| 909 |
+
# glob call above expanded one depth so if maxdepth is defined
|
| 910 |
+
# then decrement it in expand_path call below. If it is zero
|
| 911 |
+
# after decrementing then avoid expand_path call.
|
| 912 |
+
if maxdepth is not None and maxdepth <= 1:
|
| 913 |
+
continue
|
| 914 |
+
out |= set(
|
| 915 |
+
await self._expand_path(
|
| 916 |
+
list(bit),
|
| 917 |
+
recursive=recursive,
|
| 918 |
+
maxdepth=maxdepth - 1 if maxdepth is not None else None,
|
| 919 |
+
)
|
| 920 |
+
)
|
| 921 |
+
continue
|
| 922 |
+
elif recursive:
|
| 923 |
+
rec = set(await self._find(p, maxdepth=maxdepth, withdirs=True))
|
| 924 |
+
out |= rec
|
| 925 |
+
if p not in out and (recursive is False or (await self._exists(p))):
|
| 926 |
+
# should only check once, for the root
|
| 927 |
+
out.add(p)
|
| 928 |
+
if not out:
|
| 929 |
+
raise FileNotFoundError(path)
|
| 930 |
+
return sorted(out)
|
| 931 |
+
|
| 932 |
+
async def _mkdir(self, path, create_parents=True, **kwargs):
|
| 933 |
+
pass # not necessary to implement, may not have directories
|
| 934 |
+
|
| 935 |
+
async def _makedirs(self, path, exist_ok=False):
|
| 936 |
+
pass # not necessary to implement, may not have directories
|
| 937 |
+
|
| 938 |
+
async def open_async(self, path, mode="rb", **kwargs):
|
| 939 |
+
if "b" not in mode or kwargs.get("compression"):
|
| 940 |
+
raise ValueError
|
| 941 |
+
raise NotImplementedError
|
| 942 |
+
|
| 943 |
+
|
| 944 |
+
def mirror_sync_methods(obj):
|
| 945 |
+
"""Populate sync and async methods for obj
|
| 946 |
+
|
| 947 |
+
For each method will create a sync version if the name refers to an async method
|
| 948 |
+
(coroutine) and there is no override in the child class; will create an async
|
| 949 |
+
method for the corresponding sync method if there is no implementation.
|
| 950 |
+
|
| 951 |
+
Uses the methods specified in
|
| 952 |
+
- async_methods: the set that an implementation is expected to provide
|
| 953 |
+
- default_async_methods: that can be derived from their sync version in
|
| 954 |
+
AbstractFileSystem
|
| 955 |
+
- AsyncFileSystem: async-specific default coroutines
|
| 956 |
+
"""
|
| 957 |
+
from fsspec import AbstractFileSystem
|
| 958 |
+
|
| 959 |
+
for method in async_methods + dir(AsyncFileSystem):
|
| 960 |
+
if not method.startswith("_"):
|
| 961 |
+
continue
|
| 962 |
+
smethod = method[1:]
|
| 963 |
+
if private.match(method):
|
| 964 |
+
isco = inspect.iscoroutinefunction(getattr(obj, method, None))
|
| 965 |
+
unsync = getattr(getattr(obj, smethod, False), "__func__", None)
|
| 966 |
+
is_default = unsync is getattr(AbstractFileSystem, smethod, "")
|
| 967 |
+
if isco and is_default:
|
| 968 |
+
mth = sync_wrapper(getattr(obj, method), obj=obj)
|
| 969 |
+
setattr(obj, smethod, mth)
|
| 970 |
+
if not mth.__doc__:
|
| 971 |
+
mth.__doc__ = getattr(
|
| 972 |
+
getattr(AbstractFileSystem, smethod, None), "__doc__", ""
|
| 973 |
+
)
|
| 974 |
+
|
| 975 |
+
|
| 976 |
+
class FSSpecCoroutineCancel(Exception):
|
| 977 |
+
pass
|
| 978 |
+
|
| 979 |
+
|
| 980 |
+
def _dump_running_tasks(
|
| 981 |
+
printout=True, cancel=True, exc=FSSpecCoroutineCancel, with_task=False
|
| 982 |
+
):
|
| 983 |
+
import traceback
|
| 984 |
+
|
| 985 |
+
tasks = [t for t in asyncio.tasks.all_tasks(loop[0]) if not t.done()]
|
| 986 |
+
if printout:
|
| 987 |
+
[task.print_stack() for task in tasks]
|
| 988 |
+
out = [
|
| 989 |
+
{
|
| 990 |
+
"locals": task._coro.cr_frame.f_locals,
|
| 991 |
+
"file": task._coro.cr_frame.f_code.co_filename,
|
| 992 |
+
"firstline": task._coro.cr_frame.f_code.co_firstlineno,
|
| 993 |
+
"linelo": task._coro.cr_frame.f_lineno,
|
| 994 |
+
"stack": traceback.format_stack(task._coro.cr_frame),
|
| 995 |
+
"task": task if with_task else None,
|
| 996 |
+
}
|
| 997 |
+
for task in tasks
|
| 998 |
+
]
|
| 999 |
+
if cancel:
|
| 1000 |
+
for t in tasks:
|
| 1001 |
+
cbs = t._callbacks
|
| 1002 |
+
t.cancel()
|
| 1003 |
+
asyncio.futures.Future.set_exception(t, exc)
|
| 1004 |
+
asyncio.futures.Future.cancel(t)
|
| 1005 |
+
[cb[0](t) for cb in cbs] # cancels any dependent concurrent.futures
|
| 1006 |
+
try:
|
| 1007 |
+
t._coro.throw(exc) # exits coro, unless explicitly handled
|
| 1008 |
+
except exc:
|
| 1009 |
+
pass
|
| 1010 |
+
return out
|
| 1011 |
+
|
| 1012 |
+
|
| 1013 |
+
class AbstractAsyncStreamedFile(AbstractBufferedFile):
|
| 1014 |
+
# no read buffering, and always auto-commit
|
| 1015 |
+
# TODO: readahead might still be useful here, but needs async version
|
| 1016 |
+
|
| 1017 |
+
async def read(self, length=-1):
|
| 1018 |
+
"""
|
| 1019 |
+
Return data from cache, or fetch pieces as necessary
|
| 1020 |
+
|
| 1021 |
+
Parameters
|
| 1022 |
+
----------
|
| 1023 |
+
length: int (-1)
|
| 1024 |
+
Number of bytes to read; if <0, all remaining bytes.
|
| 1025 |
+
"""
|
| 1026 |
+
length = -1 if length is None else int(length)
|
| 1027 |
+
if self.mode != "rb":
|
| 1028 |
+
raise ValueError("File not in read mode")
|
| 1029 |
+
if length < 0:
|
| 1030 |
+
length = self.size - self.loc
|
| 1031 |
+
if self.closed:
|
| 1032 |
+
raise ValueError("I/O operation on closed file.")
|
| 1033 |
+
if length == 0:
|
| 1034 |
+
# don't even bother calling fetch
|
| 1035 |
+
return b""
|
| 1036 |
+
out = await self._fetch_range(self.loc, self.loc + length)
|
| 1037 |
+
self.loc += len(out)
|
| 1038 |
+
return out
|
| 1039 |
+
|
| 1040 |
+
async def write(self, data):
|
| 1041 |
+
"""
|
| 1042 |
+
Write data to buffer.
|
| 1043 |
+
|
| 1044 |
+
Buffer only sent on flush() or if buffer is greater than
|
| 1045 |
+
or equal to blocksize.
|
| 1046 |
+
|
| 1047 |
+
Parameters
|
| 1048 |
+
----------
|
| 1049 |
+
data: bytes
|
| 1050 |
+
Set of bytes to be written.
|
| 1051 |
+
"""
|
| 1052 |
+
if self.mode not in {"wb", "ab"}:
|
| 1053 |
+
raise ValueError("File not in write mode")
|
| 1054 |
+
if self.closed:
|
| 1055 |
+
raise ValueError("I/O operation on closed file.")
|
| 1056 |
+
if self.forced:
|
| 1057 |
+
raise ValueError("This file has been force-flushed, can only close")
|
| 1058 |
+
out = self.buffer.write(data)
|
| 1059 |
+
self.loc += out
|
| 1060 |
+
if self.buffer.tell() >= self.blocksize:
|
| 1061 |
+
await self.flush()
|
| 1062 |
+
return out
|
| 1063 |
+
|
| 1064 |
+
async def close(self):
|
| 1065 |
+
"""Close file
|
| 1066 |
+
|
| 1067 |
+
Finalizes writes, discards cache
|
| 1068 |
+
"""
|
| 1069 |
+
if getattr(self, "_unclosable", False):
|
| 1070 |
+
return
|
| 1071 |
+
if self.closed:
|
| 1072 |
+
return
|
| 1073 |
+
if self.mode == "rb":
|
| 1074 |
+
self.cache = None
|
| 1075 |
+
else:
|
| 1076 |
+
if not self.forced:
|
| 1077 |
+
await self.flush(force=True)
|
| 1078 |
+
|
| 1079 |
+
if self.fs is not None:
|
| 1080 |
+
self.fs.invalidate_cache(self.path)
|
| 1081 |
+
self.fs.invalidate_cache(self.fs._parent(self.path))
|
| 1082 |
+
|
| 1083 |
+
self.closed = True
|
| 1084 |
+
|
| 1085 |
+
async def flush(self, force=False):
|
| 1086 |
+
if self.closed:
|
| 1087 |
+
raise ValueError("Flush on closed file")
|
| 1088 |
+
if force and self.forced:
|
| 1089 |
+
raise ValueError("Force flush cannot be called more than once")
|
| 1090 |
+
if force:
|
| 1091 |
+
self.forced = True
|
| 1092 |
+
|
| 1093 |
+
if self.mode not in {"wb", "ab"}:
|
| 1094 |
+
# no-op to flush on read-mode
|
| 1095 |
+
return
|
| 1096 |
+
|
| 1097 |
+
if not force and self.buffer.tell() < self.blocksize:
|
| 1098 |
+
# Defer write on small block
|
| 1099 |
+
return
|
| 1100 |
+
|
| 1101 |
+
if self.offset is None:
|
| 1102 |
+
# Initialize a multipart upload
|
| 1103 |
+
self.offset = 0
|
| 1104 |
+
try:
|
| 1105 |
+
await self._initiate_upload()
|
| 1106 |
+
except:
|
| 1107 |
+
self.closed = True
|
| 1108 |
+
raise
|
| 1109 |
+
|
| 1110 |
+
if await self._upload_chunk(final=force) is not False:
|
| 1111 |
+
self.offset += self.buffer.seek(0, 2)
|
| 1112 |
+
self.buffer = io.BytesIO()
|
| 1113 |
+
|
| 1114 |
+
async def __aenter__(self):
|
| 1115 |
+
return self
|
| 1116 |
+
|
| 1117 |
+
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
| 1118 |
+
await self.close()
|
| 1119 |
+
|
| 1120 |
+
async def _fetch_range(self, start, end):
|
| 1121 |
+
raise NotImplementedError
|
| 1122 |
+
|
| 1123 |
+
async def _initiate_upload(self):
|
| 1124 |
+
pass
|
| 1125 |
+
|
| 1126 |
+
async def _upload_chunk(self, final=False):
|
| 1127 |
+
raise NotImplementedError
|
LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/fsspec/fuse.py
ADDED
|
@@ -0,0 +1,324 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import argparse
|
| 2 |
+
import logging
|
| 3 |
+
import os
|
| 4 |
+
import stat
|
| 5 |
+
import threading
|
| 6 |
+
import time
|
| 7 |
+
from errno import EIO, ENOENT
|
| 8 |
+
|
| 9 |
+
from fuse import FUSE, FuseOSError, LoggingMixIn, Operations
|
| 10 |
+
|
| 11 |
+
from fsspec import __version__
|
| 12 |
+
from fsspec.core import url_to_fs
|
| 13 |
+
|
| 14 |
+
logger = logging.getLogger("fsspec.fuse")
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
class FUSEr(Operations):
|
| 18 |
+
def __init__(self, fs, path, ready_file=False):
|
| 19 |
+
self.fs = fs
|
| 20 |
+
self.cache = {}
|
| 21 |
+
self.root = path.rstrip("/") + "/"
|
| 22 |
+
self.counter = 0
|
| 23 |
+
logger.info("Starting FUSE at %s", path)
|
| 24 |
+
self._ready_file = ready_file
|
| 25 |
+
|
| 26 |
+
def getattr(self, path, fh=None):
|
| 27 |
+
logger.debug("getattr %s", path)
|
| 28 |
+
if self._ready_file and path in ["/.fuse_ready", ".fuse_ready"]:
|
| 29 |
+
return {"type": "file", "st_size": 5}
|
| 30 |
+
|
| 31 |
+
path = "".join([self.root, path.lstrip("/")]).rstrip("/")
|
| 32 |
+
try:
|
| 33 |
+
info = self.fs.info(path)
|
| 34 |
+
except FileNotFoundError as exc:
|
| 35 |
+
raise FuseOSError(ENOENT) from exc
|
| 36 |
+
|
| 37 |
+
data = {"st_uid": info.get("uid", 1000), "st_gid": info.get("gid", 1000)}
|
| 38 |
+
perm = info.get("mode", 0o777)
|
| 39 |
+
|
| 40 |
+
if info["type"] != "file":
|
| 41 |
+
data["st_mode"] = stat.S_IFDIR | perm
|
| 42 |
+
data["st_size"] = 0
|
| 43 |
+
data["st_blksize"] = 0
|
| 44 |
+
else:
|
| 45 |
+
data["st_mode"] = stat.S_IFREG | perm
|
| 46 |
+
data["st_size"] = info["size"]
|
| 47 |
+
data["st_blksize"] = 5 * 2**20
|
| 48 |
+
data["st_nlink"] = 1
|
| 49 |
+
data["st_atime"] = info["atime"] if "atime" in info else time.time()
|
| 50 |
+
data["st_ctime"] = info["ctime"] if "ctime" in info else time.time()
|
| 51 |
+
data["st_mtime"] = info["mtime"] if "mtime" in info else time.time()
|
| 52 |
+
return data
|
| 53 |
+
|
| 54 |
+
def readdir(self, path, fh):
|
| 55 |
+
logger.debug("readdir %s", path)
|
| 56 |
+
path = "".join([self.root, path.lstrip("/")])
|
| 57 |
+
files = self.fs.ls(path, False)
|
| 58 |
+
files = [os.path.basename(f.rstrip("/")) for f in files]
|
| 59 |
+
return [".", ".."] + files
|
| 60 |
+
|
| 61 |
+
def mkdir(self, path, mode):
|
| 62 |
+
path = "".join([self.root, path.lstrip("/")])
|
| 63 |
+
self.fs.mkdir(path)
|
| 64 |
+
return 0
|
| 65 |
+
|
| 66 |
+
def rmdir(self, path):
|
| 67 |
+
path = "".join([self.root, path.lstrip("/")])
|
| 68 |
+
self.fs.rmdir(path)
|
| 69 |
+
return 0
|
| 70 |
+
|
| 71 |
+
def read(self, path, size, offset, fh):
|
| 72 |
+
logger.debug("read %s", (path, size, offset))
|
| 73 |
+
if self._ready_file and path in ["/.fuse_ready", ".fuse_ready"]:
|
| 74 |
+
# status indicator
|
| 75 |
+
return b"ready"
|
| 76 |
+
|
| 77 |
+
f = self.cache[fh]
|
| 78 |
+
f.seek(offset)
|
| 79 |
+
out = f.read(size)
|
| 80 |
+
return out
|
| 81 |
+
|
| 82 |
+
def write(self, path, data, offset, fh):
|
| 83 |
+
logger.debug("write %s", (path, offset))
|
| 84 |
+
f = self.cache[fh]
|
| 85 |
+
f.seek(offset)
|
| 86 |
+
f.write(data)
|
| 87 |
+
return len(data)
|
| 88 |
+
|
| 89 |
+
def create(self, path, flags, fi=None):
|
| 90 |
+
logger.debug("create %s", (path, flags))
|
| 91 |
+
fn = "".join([self.root, path.lstrip("/")])
|
| 92 |
+
self.fs.touch(fn) # OS will want to get attributes immediately
|
| 93 |
+
f = self.fs.open(fn, "wb")
|
| 94 |
+
self.cache[self.counter] = f
|
| 95 |
+
self.counter += 1
|
| 96 |
+
return self.counter - 1
|
| 97 |
+
|
| 98 |
+
def open(self, path, flags):
|
| 99 |
+
logger.debug("open %s", (path, flags))
|
| 100 |
+
fn = "".join([self.root, path.lstrip("/")])
|
| 101 |
+
if flags % 2 == 0:
|
| 102 |
+
# read
|
| 103 |
+
mode = "rb"
|
| 104 |
+
else:
|
| 105 |
+
# write/create
|
| 106 |
+
mode = "wb"
|
| 107 |
+
self.cache[self.counter] = self.fs.open(fn, mode)
|
| 108 |
+
self.counter += 1
|
| 109 |
+
return self.counter - 1
|
| 110 |
+
|
| 111 |
+
def truncate(self, path, length, fh=None):
|
| 112 |
+
fn = "".join([self.root, path.lstrip("/")])
|
| 113 |
+
if length != 0:
|
| 114 |
+
raise NotImplementedError
|
| 115 |
+
# maybe should be no-op since open with write sets size to zero anyway
|
| 116 |
+
self.fs.touch(fn)
|
| 117 |
+
|
| 118 |
+
def unlink(self, path):
|
| 119 |
+
fn = "".join([self.root, path.lstrip("/")])
|
| 120 |
+
try:
|
| 121 |
+
self.fs.rm(fn, False)
|
| 122 |
+
except (OSError, FileNotFoundError) as exc:
|
| 123 |
+
raise FuseOSError(EIO) from exc
|
| 124 |
+
|
| 125 |
+
def release(self, path, fh):
|
| 126 |
+
try:
|
| 127 |
+
if fh in self.cache:
|
| 128 |
+
f = self.cache[fh]
|
| 129 |
+
f.close()
|
| 130 |
+
self.cache.pop(fh)
|
| 131 |
+
except Exception as e:
|
| 132 |
+
print(e)
|
| 133 |
+
return 0
|
| 134 |
+
|
| 135 |
+
def chmod(self, path, mode):
|
| 136 |
+
if hasattr(self.fs, "chmod"):
|
| 137 |
+
path = "".join([self.root, path.lstrip("/")])
|
| 138 |
+
return self.fs.chmod(path, mode)
|
| 139 |
+
raise NotImplementedError
|
| 140 |
+
|
| 141 |
+
|
| 142 |
+
def run(
|
| 143 |
+
fs,
|
| 144 |
+
path,
|
| 145 |
+
mount_point,
|
| 146 |
+
foreground=True,
|
| 147 |
+
threads=False,
|
| 148 |
+
ready_file=False,
|
| 149 |
+
ops_class=FUSEr,
|
| 150 |
+
):
|
| 151 |
+
"""Mount stuff in a local directory
|
| 152 |
+
|
| 153 |
+
This uses fusepy to make it appear as if a given path on an fsspec
|
| 154 |
+
instance is in fact resident within the local file-system.
|
| 155 |
+
|
| 156 |
+
This requires that fusepy by installed, and that FUSE be available on
|
| 157 |
+
the system (typically requiring a package to be installed with
|
| 158 |
+
apt, yum, brew, etc.).
|
| 159 |
+
|
| 160 |
+
Parameters
|
| 161 |
+
----------
|
| 162 |
+
fs: file-system instance
|
| 163 |
+
From one of the compatible implementations
|
| 164 |
+
path: str
|
| 165 |
+
Location on that file-system to regard as the root directory to
|
| 166 |
+
mount. Note that you typically should include the terminating "/"
|
| 167 |
+
character.
|
| 168 |
+
mount_point: str
|
| 169 |
+
An empty directory on the local file-system where the contents of
|
| 170 |
+
the remote path will appear.
|
| 171 |
+
foreground: bool
|
| 172 |
+
Whether or not calling this function will block. Operation will
|
| 173 |
+
typically be more stable if True.
|
| 174 |
+
threads: bool
|
| 175 |
+
Whether or not to create threads when responding to file operations
|
| 176 |
+
within the mounter directory. Operation will typically be more
|
| 177 |
+
stable if False.
|
| 178 |
+
ready_file: bool
|
| 179 |
+
Whether the FUSE process is ready. The ``.fuse_ready`` file will
|
| 180 |
+
exist in the ``mount_point`` directory if True. Debugging purpose.
|
| 181 |
+
ops_class: FUSEr or Subclass of FUSEr
|
| 182 |
+
To override the default behavior of FUSEr. For Example, logging
|
| 183 |
+
to file.
|
| 184 |
+
|
| 185 |
+
"""
|
| 186 |
+
func = lambda: FUSE(
|
| 187 |
+
ops_class(fs, path, ready_file=ready_file),
|
| 188 |
+
mount_point,
|
| 189 |
+
nothreads=not threads,
|
| 190 |
+
foreground=foreground,
|
| 191 |
+
)
|
| 192 |
+
if not foreground:
|
| 193 |
+
th = threading.Thread(target=func)
|
| 194 |
+
th.daemon = True
|
| 195 |
+
th.start()
|
| 196 |
+
return th
|
| 197 |
+
else: # pragma: no cover
|
| 198 |
+
try:
|
| 199 |
+
func()
|
| 200 |
+
except KeyboardInterrupt:
|
| 201 |
+
pass
|
| 202 |
+
|
| 203 |
+
|
| 204 |
+
def main(args):
|
| 205 |
+
"""Mount filesystem from chained URL to MOUNT_POINT.
|
| 206 |
+
|
| 207 |
+
Examples:
|
| 208 |
+
|
| 209 |
+
python3 -m fsspec.fuse memory /usr/share /tmp/mem
|
| 210 |
+
|
| 211 |
+
python3 -m fsspec.fuse local /tmp/source /tmp/local \\
|
| 212 |
+
-l /tmp/fsspecfuse.log
|
| 213 |
+
|
| 214 |
+
You can also mount chained-URLs and use special settings:
|
| 215 |
+
|
| 216 |
+
python3 -m fsspec.fuse 'filecache::zip::file://data.zip' \\
|
| 217 |
+
/ /tmp/zip \\
|
| 218 |
+
-o 'filecache-cache_storage=/tmp/simplecache'
|
| 219 |
+
|
| 220 |
+
You can specify the type of the setting by using `[int]` or `[bool]`,
|
| 221 |
+
(`true`, `yes`, `1` represents the Boolean value `True`):
|
| 222 |
+
|
| 223 |
+
python3 -m fsspec.fuse 'simplecache::ftp://ftp1.at.proftpd.org' \\
|
| 224 |
+
/historic/packages/RPMS /tmp/ftp \\
|
| 225 |
+
-o 'simplecache-cache_storage=/tmp/simplecache' \\
|
| 226 |
+
-o 'simplecache-check_files=false[bool]' \\
|
| 227 |
+
-o 'ftp-listings_expiry_time=60[int]' \\
|
| 228 |
+
-o 'ftp-username=anonymous' \\
|
| 229 |
+
-o 'ftp-password=xieyanbo'
|
| 230 |
+
"""
|
| 231 |
+
|
| 232 |
+
class RawDescriptionArgumentParser(argparse.ArgumentParser):
|
| 233 |
+
def format_help(self):
|
| 234 |
+
usage = super().format_help()
|
| 235 |
+
parts = usage.split("\n\n")
|
| 236 |
+
parts[1] = self.description.rstrip()
|
| 237 |
+
return "\n\n".join(parts)
|
| 238 |
+
|
| 239 |
+
parser = RawDescriptionArgumentParser(prog="fsspec.fuse", description=main.__doc__)
|
| 240 |
+
parser.add_argument("--version", action="version", version=__version__)
|
| 241 |
+
parser.add_argument("url", type=str, help="fs url")
|
| 242 |
+
parser.add_argument("source_path", type=str, help="source directory in fs")
|
| 243 |
+
parser.add_argument("mount_point", type=str, help="local directory")
|
| 244 |
+
parser.add_argument(
|
| 245 |
+
"-o",
|
| 246 |
+
"--option",
|
| 247 |
+
action="append",
|
| 248 |
+
help="Any options of protocol included in the chained URL",
|
| 249 |
+
)
|
| 250 |
+
parser.add_argument(
|
| 251 |
+
"-l", "--log-file", type=str, help="Logging FUSE debug info (Default: '')"
|
| 252 |
+
)
|
| 253 |
+
parser.add_argument(
|
| 254 |
+
"-f",
|
| 255 |
+
"--foreground",
|
| 256 |
+
action="store_false",
|
| 257 |
+
help="Running in foreground or not (Default: False)",
|
| 258 |
+
)
|
| 259 |
+
parser.add_argument(
|
| 260 |
+
"-t",
|
| 261 |
+
"--threads",
|
| 262 |
+
action="store_false",
|
| 263 |
+
help="Running with threads support (Default: False)",
|
| 264 |
+
)
|
| 265 |
+
parser.add_argument(
|
| 266 |
+
"-r",
|
| 267 |
+
"--ready-file",
|
| 268 |
+
action="store_false",
|
| 269 |
+
help="The `.fuse_ready` file will exist after FUSE is ready. "
|
| 270 |
+
"(Debugging purpose, Default: False)",
|
| 271 |
+
)
|
| 272 |
+
args = parser.parse_args(args)
|
| 273 |
+
|
| 274 |
+
kwargs = {}
|
| 275 |
+
for item in args.option or []:
|
| 276 |
+
key, sep, value = item.partition("=")
|
| 277 |
+
if not sep:
|
| 278 |
+
parser.error(message=f"Wrong option: {item!r}")
|
| 279 |
+
val = value.lower()
|
| 280 |
+
if val.endswith("[int]"):
|
| 281 |
+
value = int(value[: -len("[int]")])
|
| 282 |
+
elif val.endswith("[bool]"):
|
| 283 |
+
value = val[: -len("[bool]")] in ["1", "yes", "true"]
|
| 284 |
+
|
| 285 |
+
if "-" in key:
|
| 286 |
+
fs_name, setting_name = key.split("-", 1)
|
| 287 |
+
if fs_name in kwargs:
|
| 288 |
+
kwargs[fs_name][setting_name] = value
|
| 289 |
+
else:
|
| 290 |
+
kwargs[fs_name] = {setting_name: value}
|
| 291 |
+
else:
|
| 292 |
+
kwargs[key] = value
|
| 293 |
+
|
| 294 |
+
if args.log_file:
|
| 295 |
+
logging.basicConfig(
|
| 296 |
+
level=logging.DEBUG,
|
| 297 |
+
filename=args.log_file,
|
| 298 |
+
format="%(asctime)s %(message)s",
|
| 299 |
+
)
|
| 300 |
+
|
| 301 |
+
class LoggingFUSEr(FUSEr, LoggingMixIn):
|
| 302 |
+
pass
|
| 303 |
+
|
| 304 |
+
fuser = LoggingFUSEr
|
| 305 |
+
else:
|
| 306 |
+
fuser = FUSEr
|
| 307 |
+
|
| 308 |
+
fs, url_path = url_to_fs(args.url, **kwargs)
|
| 309 |
+
logger.debug("Mounting %s to %s", url_path, str(args.mount_point))
|
| 310 |
+
run(
|
| 311 |
+
fs,
|
| 312 |
+
args.source_path,
|
| 313 |
+
args.mount_point,
|
| 314 |
+
foreground=args.foreground,
|
| 315 |
+
threads=args.threads,
|
| 316 |
+
ready_file=args.ready_file,
|
| 317 |
+
ops_class=fuser,
|
| 318 |
+
)
|
| 319 |
+
|
| 320 |
+
|
| 321 |
+
if __name__ == "__main__":
|
| 322 |
+
import sys
|
| 323 |
+
|
| 324 |
+
main(sys.argv[1:])
|
LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/fsspec/generic.py
ADDED
|
@@ -0,0 +1,396 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
|
| 3 |
+
import inspect
|
| 4 |
+
import logging
|
| 5 |
+
import os
|
| 6 |
+
import shutil
|
| 7 |
+
import uuid
|
| 8 |
+
|
| 9 |
+
from .asyn import AsyncFileSystem, _run_coros_in_chunks, sync_wrapper
|
| 10 |
+
from .callbacks import DEFAULT_CALLBACK
|
| 11 |
+
from .core import filesystem, get_filesystem_class, split_protocol, url_to_fs
|
| 12 |
+
|
| 13 |
+
_generic_fs = {}
|
| 14 |
+
logger = logging.getLogger("fsspec.generic")
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
def set_generic_fs(protocol, **storage_options):
|
| 18 |
+
"""Populate the dict used for method=="generic" lookups"""
|
| 19 |
+
_generic_fs[protocol] = filesystem(protocol, **storage_options)
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
def _resolve_fs(url, method, protocol=None, storage_options=None):
|
| 23 |
+
"""Pick instance of backend FS"""
|
| 24 |
+
url = url[0] if isinstance(url, (list, tuple)) else url
|
| 25 |
+
protocol = protocol or split_protocol(url)[0]
|
| 26 |
+
storage_options = storage_options or {}
|
| 27 |
+
if method == "default":
|
| 28 |
+
return filesystem(protocol)
|
| 29 |
+
if method == "generic":
|
| 30 |
+
return _generic_fs[protocol]
|
| 31 |
+
if method == "current":
|
| 32 |
+
cls = get_filesystem_class(protocol)
|
| 33 |
+
return cls.current()
|
| 34 |
+
if method == "options":
|
| 35 |
+
fs, _ = url_to_fs(url, **storage_options.get(protocol, {}))
|
| 36 |
+
return fs
|
| 37 |
+
raise ValueError(f"Unknown FS resolution method: {method}")
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
def rsync(
|
| 41 |
+
source,
|
| 42 |
+
destination,
|
| 43 |
+
delete_missing=False,
|
| 44 |
+
source_field="size",
|
| 45 |
+
dest_field="size",
|
| 46 |
+
update_cond="different",
|
| 47 |
+
inst_kwargs=None,
|
| 48 |
+
fs=None,
|
| 49 |
+
**kwargs,
|
| 50 |
+
):
|
| 51 |
+
"""Sync files between two directory trees
|
| 52 |
+
|
| 53 |
+
(experimental)
|
| 54 |
+
|
| 55 |
+
Parameters
|
| 56 |
+
----------
|
| 57 |
+
source: str
|
| 58 |
+
Root of the directory tree to take files from. This must be a directory, but
|
| 59 |
+
do not include any terminating "/" character
|
| 60 |
+
destination: str
|
| 61 |
+
Root path to copy into. The contents of this location should be
|
| 62 |
+
identical to the contents of ``source`` when done. This will be made a
|
| 63 |
+
directory, and the terminal "/" should not be included.
|
| 64 |
+
delete_missing: bool
|
| 65 |
+
If there are paths in the destination that don't exist in the
|
| 66 |
+
source and this is True, delete them. Otherwise, leave them alone.
|
| 67 |
+
source_field: str | callable
|
| 68 |
+
If ``update_field`` is "different", this is the key in the info
|
| 69 |
+
of source files to consider for difference. Maybe a function of the
|
| 70 |
+
info dict.
|
| 71 |
+
dest_field: str | callable
|
| 72 |
+
If ``update_field`` is "different", this is the key in the info
|
| 73 |
+
of destination files to consider for difference. May be a function of
|
| 74 |
+
the info dict.
|
| 75 |
+
update_cond: "different"|"always"|"never"
|
| 76 |
+
If "always", every file is copied, regardless of whether it exists in
|
| 77 |
+
the destination. If "never", files that exist in the destination are
|
| 78 |
+
not copied again. If "different" (default), only copy if the info
|
| 79 |
+
fields given by ``source_field`` and ``dest_field`` (usually "size")
|
| 80 |
+
are different. Other comparisons may be added in the future.
|
| 81 |
+
inst_kwargs: dict|None
|
| 82 |
+
If ``fs`` is None, use this set of keyword arguments to make a
|
| 83 |
+
GenericFileSystem instance
|
| 84 |
+
fs: GenericFileSystem|None
|
| 85 |
+
Instance to use if explicitly given. The instance defines how to
|
| 86 |
+
to make downstream file system instances from paths.
|
| 87 |
+
|
| 88 |
+
Returns
|
| 89 |
+
-------
|
| 90 |
+
dict of the copy operations that were performed, {source: destination}
|
| 91 |
+
"""
|
| 92 |
+
fs = fs or GenericFileSystem(**(inst_kwargs or {}))
|
| 93 |
+
source = fs._strip_protocol(source)
|
| 94 |
+
destination = fs._strip_protocol(destination)
|
| 95 |
+
allfiles = fs.find(source, withdirs=True, detail=True)
|
| 96 |
+
if not fs.isdir(source):
|
| 97 |
+
raise ValueError("Can only rsync on a directory")
|
| 98 |
+
otherfiles = fs.find(destination, withdirs=True, detail=True)
|
| 99 |
+
dirs = [
|
| 100 |
+
a
|
| 101 |
+
for a, v in allfiles.items()
|
| 102 |
+
if v["type"] == "directory" and a.replace(source, destination) not in otherfiles
|
| 103 |
+
]
|
| 104 |
+
logger.debug(f"{len(dirs)} directories to create")
|
| 105 |
+
if dirs:
|
| 106 |
+
fs.make_many_dirs(
|
| 107 |
+
[dirn.replace(source, destination) for dirn in dirs], exist_ok=True
|
| 108 |
+
)
|
| 109 |
+
allfiles = {a: v for a, v in allfiles.items() if v["type"] == "file"}
|
| 110 |
+
logger.debug(f"{len(allfiles)} files to consider for copy")
|
| 111 |
+
to_delete = [
|
| 112 |
+
o
|
| 113 |
+
for o, v in otherfiles.items()
|
| 114 |
+
if o.replace(destination, source) not in allfiles and v["type"] == "file"
|
| 115 |
+
]
|
| 116 |
+
for k, v in allfiles.copy().items():
|
| 117 |
+
otherfile = k.replace(source, destination)
|
| 118 |
+
if otherfile in otherfiles:
|
| 119 |
+
if update_cond == "always":
|
| 120 |
+
allfiles[k] = otherfile
|
| 121 |
+
elif update_cond == "never":
|
| 122 |
+
allfiles.pop(k)
|
| 123 |
+
elif update_cond == "different":
|
| 124 |
+
inf1 = source_field(v) if callable(source_field) else v[source_field]
|
| 125 |
+
v2 = otherfiles[otherfile]
|
| 126 |
+
inf2 = dest_field(v2) if callable(dest_field) else v2[dest_field]
|
| 127 |
+
if inf1 != inf2:
|
| 128 |
+
# details mismatch, make copy
|
| 129 |
+
allfiles[k] = otherfile
|
| 130 |
+
else:
|
| 131 |
+
# details match, don't copy
|
| 132 |
+
allfiles.pop(k)
|
| 133 |
+
else:
|
| 134 |
+
# file not in target yet
|
| 135 |
+
allfiles[k] = otherfile
|
| 136 |
+
logger.debug(f"{len(allfiles)} files to copy")
|
| 137 |
+
if allfiles:
|
| 138 |
+
source_files, target_files = zip(*allfiles.items())
|
| 139 |
+
fs.cp(source_files, target_files, **kwargs)
|
| 140 |
+
logger.debug(f"{len(to_delete)} files to delete")
|
| 141 |
+
if delete_missing and to_delete:
|
| 142 |
+
fs.rm(to_delete)
|
| 143 |
+
return allfiles
|
| 144 |
+
|
| 145 |
+
|
| 146 |
+
class GenericFileSystem(AsyncFileSystem):
|
| 147 |
+
"""Wrapper over all other FS types
|
| 148 |
+
|
| 149 |
+
<experimental!>
|
| 150 |
+
|
| 151 |
+
This implementation is a single unified interface to be able to run FS operations
|
| 152 |
+
over generic URLs, and dispatch to the specific implementations using the URL
|
| 153 |
+
protocol prefix.
|
| 154 |
+
|
| 155 |
+
Note: instances of this FS are always async, even if you never use it with any async
|
| 156 |
+
backend.
|
| 157 |
+
"""
|
| 158 |
+
|
| 159 |
+
protocol = "generic" # there is no real reason to ever use a protocol with this FS
|
| 160 |
+
|
| 161 |
+
def __init__(self, default_method="default", storage_options=None, **kwargs):
|
| 162 |
+
"""
|
| 163 |
+
|
| 164 |
+
Parameters
|
| 165 |
+
----------
|
| 166 |
+
default_method: str (optional)
|
| 167 |
+
Defines how to configure backend FS instances. Options are:
|
| 168 |
+
- "default": instantiate like FSClass(), with no
|
| 169 |
+
extra arguments; this is the default instance of that FS, and can be
|
| 170 |
+
configured via the config system
|
| 171 |
+
- "generic": takes instances from the `_generic_fs` dict in this module,
|
| 172 |
+
which you must populate before use. Keys are by protocol
|
| 173 |
+
- "options": expects storage_options, a dict mapping protocol to
|
| 174 |
+
kwargs to use when constructing the filesystem
|
| 175 |
+
- "current": takes the most recently instantiated version of each FS
|
| 176 |
+
"""
|
| 177 |
+
self.method = default_method
|
| 178 |
+
self.st_opts = storage_options
|
| 179 |
+
super().__init__(**kwargs)
|
| 180 |
+
|
| 181 |
+
def _parent(self, path):
|
| 182 |
+
fs = _resolve_fs(path, self.method, storage_options=self.st_opts)
|
| 183 |
+
return fs.unstrip_protocol(fs._parent(path))
|
| 184 |
+
|
| 185 |
+
def _strip_protocol(self, path):
|
| 186 |
+
# normalization only
|
| 187 |
+
fs = _resolve_fs(path, self.method, storage_options=self.st_opts)
|
| 188 |
+
return fs.unstrip_protocol(fs._strip_protocol(path))
|
| 189 |
+
|
| 190 |
+
async def _find(self, path, maxdepth=None, withdirs=False, detail=False, **kwargs):
|
| 191 |
+
fs = _resolve_fs(path, self.method, storage_options=self.st_opts)
|
| 192 |
+
if fs.async_impl:
|
| 193 |
+
out = await fs._find(
|
| 194 |
+
path, maxdepth=maxdepth, withdirs=withdirs, detail=True, **kwargs
|
| 195 |
+
)
|
| 196 |
+
else:
|
| 197 |
+
out = fs.find(
|
| 198 |
+
path, maxdepth=maxdepth, withdirs=withdirs, detail=True, **kwargs
|
| 199 |
+
)
|
| 200 |
+
result = {}
|
| 201 |
+
for k, v in out.items():
|
| 202 |
+
v = v.copy() # don't corrupt target FS dircache
|
| 203 |
+
name = fs.unstrip_protocol(k)
|
| 204 |
+
v["name"] = name
|
| 205 |
+
result[name] = v
|
| 206 |
+
if detail:
|
| 207 |
+
return result
|
| 208 |
+
return list(result)
|
| 209 |
+
|
| 210 |
+
async def _info(self, url, **kwargs):
|
| 211 |
+
fs = _resolve_fs(url, self.method)
|
| 212 |
+
if fs.async_impl:
|
| 213 |
+
out = await fs._info(url, **kwargs)
|
| 214 |
+
else:
|
| 215 |
+
out = fs.info(url, **kwargs)
|
| 216 |
+
out = out.copy() # don't edit originals
|
| 217 |
+
out["name"] = fs.unstrip_protocol(out["name"])
|
| 218 |
+
return out
|
| 219 |
+
|
| 220 |
+
async def _ls(
|
| 221 |
+
self,
|
| 222 |
+
url,
|
| 223 |
+
detail=True,
|
| 224 |
+
**kwargs,
|
| 225 |
+
):
|
| 226 |
+
fs = _resolve_fs(url, self.method)
|
| 227 |
+
if fs.async_impl:
|
| 228 |
+
out = await fs._ls(url, detail=True, **kwargs)
|
| 229 |
+
else:
|
| 230 |
+
out = fs.ls(url, detail=True, **kwargs)
|
| 231 |
+
out = [o.copy() for o in out] # don't edit originals
|
| 232 |
+
for o in out:
|
| 233 |
+
o["name"] = fs.unstrip_protocol(o["name"])
|
| 234 |
+
if detail:
|
| 235 |
+
return out
|
| 236 |
+
else:
|
| 237 |
+
return [o["name"] for o in out]
|
| 238 |
+
|
| 239 |
+
async def _cat_file(
|
| 240 |
+
self,
|
| 241 |
+
url,
|
| 242 |
+
**kwargs,
|
| 243 |
+
):
|
| 244 |
+
fs = _resolve_fs(url, self.method)
|
| 245 |
+
if fs.async_impl:
|
| 246 |
+
return await fs._cat_file(url, **kwargs)
|
| 247 |
+
else:
|
| 248 |
+
return fs.cat_file(url, **kwargs)
|
| 249 |
+
|
| 250 |
+
async def _pipe_file(
|
| 251 |
+
self,
|
| 252 |
+
path,
|
| 253 |
+
value,
|
| 254 |
+
**kwargs,
|
| 255 |
+
):
|
| 256 |
+
fs = _resolve_fs(path, self.method, storage_options=self.st_opts)
|
| 257 |
+
if fs.async_impl:
|
| 258 |
+
return await fs._pipe_file(path, value, **kwargs)
|
| 259 |
+
else:
|
| 260 |
+
return fs.pipe_file(path, value, **kwargs)
|
| 261 |
+
|
| 262 |
+
async def _rm(self, url, **kwargs):
|
| 263 |
+
urls = url
|
| 264 |
+
if isinstance(urls, str):
|
| 265 |
+
urls = [urls]
|
| 266 |
+
fs = _resolve_fs(urls[0], self.method)
|
| 267 |
+
if fs.async_impl:
|
| 268 |
+
await fs._rm(urls, **kwargs)
|
| 269 |
+
else:
|
| 270 |
+
fs.rm(url, **kwargs)
|
| 271 |
+
|
| 272 |
+
async def _makedirs(self, path, exist_ok=False):
|
| 273 |
+
logger.debug("Make dir %s", path)
|
| 274 |
+
fs = _resolve_fs(path, self.method, storage_options=self.st_opts)
|
| 275 |
+
if fs.async_impl:
|
| 276 |
+
await fs._makedirs(path, exist_ok=exist_ok)
|
| 277 |
+
else:
|
| 278 |
+
fs.makedirs(path, exist_ok=exist_ok)
|
| 279 |
+
|
| 280 |
+
def rsync(self, source, destination, **kwargs):
|
| 281 |
+
"""Sync files between two directory trees
|
| 282 |
+
|
| 283 |
+
See `func:rsync` for more details.
|
| 284 |
+
"""
|
| 285 |
+
rsync(source, destination, fs=self, **kwargs)
|
| 286 |
+
|
| 287 |
+
async def _cp_file(
|
| 288 |
+
self,
|
| 289 |
+
url,
|
| 290 |
+
url2,
|
| 291 |
+
blocksize=2**20,
|
| 292 |
+
callback=DEFAULT_CALLBACK,
|
| 293 |
+
tempdir: str | None = None,
|
| 294 |
+
**kwargs,
|
| 295 |
+
):
|
| 296 |
+
fs = _resolve_fs(url, self.method)
|
| 297 |
+
fs2 = _resolve_fs(url2, self.method)
|
| 298 |
+
if fs is fs2:
|
| 299 |
+
# pure remote
|
| 300 |
+
if fs.async_impl:
|
| 301 |
+
return await fs._copy(url, url2, **kwargs)
|
| 302 |
+
else:
|
| 303 |
+
return fs.copy(url, url2, **kwargs)
|
| 304 |
+
await copy_file_op(fs, [url], fs2, [url2], tempdir, 1, on_error="raise")
|
| 305 |
+
|
| 306 |
+
async def _make_many_dirs(self, urls, exist_ok=True):
|
| 307 |
+
fs = _resolve_fs(urls[0], self.method)
|
| 308 |
+
if fs.async_impl:
|
| 309 |
+
coros = [fs._makedirs(u, exist_ok=exist_ok) for u in urls]
|
| 310 |
+
await _run_coros_in_chunks(coros)
|
| 311 |
+
else:
|
| 312 |
+
for u in urls:
|
| 313 |
+
fs.makedirs(u, exist_ok=exist_ok)
|
| 314 |
+
|
| 315 |
+
make_many_dirs = sync_wrapper(_make_many_dirs)
|
| 316 |
+
|
| 317 |
+
async def _copy(
|
| 318 |
+
self,
|
| 319 |
+
path1: list[str],
|
| 320 |
+
path2: list[str],
|
| 321 |
+
recursive: bool = False,
|
| 322 |
+
on_error: str = "ignore",
|
| 323 |
+
maxdepth: int | None = None,
|
| 324 |
+
batch_size: int | None = None,
|
| 325 |
+
tempdir: str | None = None,
|
| 326 |
+
**kwargs,
|
| 327 |
+
):
|
| 328 |
+
# TODO: special case for one FS being local, which can use get/put
|
| 329 |
+
# TODO: special case for one being memFS, which can use cat/pipe
|
| 330 |
+
if recursive:
|
| 331 |
+
raise NotImplementedError("Please use fsspec.generic.rsync")
|
| 332 |
+
path1 = [path1] if isinstance(path1, str) else path1
|
| 333 |
+
path2 = [path2] if isinstance(path2, str) else path2
|
| 334 |
+
|
| 335 |
+
fs = _resolve_fs(path1, self.method)
|
| 336 |
+
fs2 = _resolve_fs(path2, self.method)
|
| 337 |
+
|
| 338 |
+
if fs is fs2:
|
| 339 |
+
if fs.async_impl:
|
| 340 |
+
return await fs._copy(path1, path2, **kwargs)
|
| 341 |
+
else:
|
| 342 |
+
return fs.copy(path1, path2, **kwargs)
|
| 343 |
+
|
| 344 |
+
await copy_file_op(
|
| 345 |
+
fs, path1, fs2, path2, tempdir, batch_size, on_error=on_error
|
| 346 |
+
)
|
| 347 |
+
|
| 348 |
+
|
| 349 |
+
async def copy_file_op(
|
| 350 |
+
fs1, url1, fs2, url2, tempdir=None, batch_size=20, on_error="ignore"
|
| 351 |
+
):
|
| 352 |
+
import tempfile
|
| 353 |
+
|
| 354 |
+
tempdir = tempdir or tempfile.mkdtemp()
|
| 355 |
+
try:
|
| 356 |
+
coros = [
|
| 357 |
+
_copy_file_op(
|
| 358 |
+
fs1,
|
| 359 |
+
u1,
|
| 360 |
+
fs2,
|
| 361 |
+
u2,
|
| 362 |
+
os.path.join(tempdir, uuid.uuid4().hex),
|
| 363 |
+
)
|
| 364 |
+
for u1, u2 in zip(url1, url2)
|
| 365 |
+
]
|
| 366 |
+
out = await _run_coros_in_chunks(
|
| 367 |
+
coros, batch_size=batch_size, return_exceptions=True
|
| 368 |
+
)
|
| 369 |
+
finally:
|
| 370 |
+
shutil.rmtree(tempdir)
|
| 371 |
+
if on_error == "return":
|
| 372 |
+
return out
|
| 373 |
+
elif on_error == "raise":
|
| 374 |
+
for o in out:
|
| 375 |
+
if isinstance(o, Exception):
|
| 376 |
+
raise o
|
| 377 |
+
|
| 378 |
+
|
| 379 |
+
async def _copy_file_op(fs1, url1, fs2, url2, local, on_error="ignore"):
|
| 380 |
+
if fs1.async_impl:
|
| 381 |
+
await fs1._get_file(url1, local)
|
| 382 |
+
else:
|
| 383 |
+
fs1.get_file(url1, local)
|
| 384 |
+
if fs2.async_impl:
|
| 385 |
+
await fs2._put_file(local, url2)
|
| 386 |
+
else:
|
| 387 |
+
fs2.put_file(local, url2)
|
| 388 |
+
os.unlink(local)
|
| 389 |
+
logger.debug("Copy %s -> %s; done", url1, url2)
|
| 390 |
+
|
| 391 |
+
|
| 392 |
+
async def maybe_await(cor):
|
| 393 |
+
if inspect.iscoroutine(cor):
|
| 394 |
+
return await cor
|
| 395 |
+
else:
|
| 396 |
+
return cor
|
LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/fsspec/mapping.py
ADDED
|
@@ -0,0 +1,251 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import array
|
| 2 |
+
import logging
|
| 3 |
+
import posixpath
|
| 4 |
+
import warnings
|
| 5 |
+
from collections.abc import MutableMapping
|
| 6 |
+
from functools import cached_property
|
| 7 |
+
|
| 8 |
+
from fsspec.core import url_to_fs
|
| 9 |
+
|
| 10 |
+
logger = logging.getLogger("fsspec.mapping")
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
class FSMap(MutableMapping):
|
| 14 |
+
"""Wrap a FileSystem instance as a mutable wrapping.
|
| 15 |
+
|
| 16 |
+
The keys of the mapping become files under the given root, and the
|
| 17 |
+
values (which must be bytes) the contents of those files.
|
| 18 |
+
|
| 19 |
+
Parameters
|
| 20 |
+
----------
|
| 21 |
+
root: string
|
| 22 |
+
prefix for all the files
|
| 23 |
+
fs: FileSystem instance
|
| 24 |
+
check: bool (=True)
|
| 25 |
+
performs a touch at the location, to check for write access.
|
| 26 |
+
|
| 27 |
+
Examples
|
| 28 |
+
--------
|
| 29 |
+
>>> fs = FileSystem(**parameters) # doctest: +SKIP
|
| 30 |
+
>>> d = FSMap('my-data/path/', fs) # doctest: +SKIP
|
| 31 |
+
or, more likely
|
| 32 |
+
>>> d = fs.get_mapper('my-data/path/')
|
| 33 |
+
|
| 34 |
+
>>> d['loc1'] = b'Hello World' # doctest: +SKIP
|
| 35 |
+
>>> list(d.keys()) # doctest: +SKIP
|
| 36 |
+
['loc1']
|
| 37 |
+
>>> d['loc1'] # doctest: +SKIP
|
| 38 |
+
b'Hello World'
|
| 39 |
+
"""
|
| 40 |
+
|
| 41 |
+
def __init__(self, root, fs, check=False, create=False, missing_exceptions=None):
|
| 42 |
+
self.fs = fs
|
| 43 |
+
self.root = fs._strip_protocol(root)
|
| 44 |
+
self._root_key_to_str = fs._strip_protocol(posixpath.join(root, "x"))[:-1]
|
| 45 |
+
if missing_exceptions is None:
|
| 46 |
+
missing_exceptions = (
|
| 47 |
+
FileNotFoundError,
|
| 48 |
+
IsADirectoryError,
|
| 49 |
+
NotADirectoryError,
|
| 50 |
+
)
|
| 51 |
+
self.missing_exceptions = missing_exceptions
|
| 52 |
+
self.check = check
|
| 53 |
+
self.create = create
|
| 54 |
+
if create:
|
| 55 |
+
if not self.fs.exists(root):
|
| 56 |
+
self.fs.mkdir(root)
|
| 57 |
+
if check:
|
| 58 |
+
if not self.fs.exists(root):
|
| 59 |
+
raise ValueError(
|
| 60 |
+
f"Path {root} does not exist. Create "
|
| 61 |
+
f" with the ``create=True`` keyword"
|
| 62 |
+
)
|
| 63 |
+
self.fs.touch(root + "/a")
|
| 64 |
+
self.fs.rm(root + "/a")
|
| 65 |
+
|
| 66 |
+
@cached_property
|
| 67 |
+
def dirfs(self):
|
| 68 |
+
"""dirfs instance that can be used with the same keys as the mapper"""
|
| 69 |
+
from .implementations.dirfs import DirFileSystem
|
| 70 |
+
|
| 71 |
+
return DirFileSystem(path=self._root_key_to_str, fs=self.fs)
|
| 72 |
+
|
| 73 |
+
def clear(self):
|
| 74 |
+
"""Remove all keys below root - empties out mapping"""
|
| 75 |
+
logger.info("Clear mapping at %s", self.root)
|
| 76 |
+
try:
|
| 77 |
+
self.fs.rm(self.root, True)
|
| 78 |
+
self.fs.mkdir(self.root)
|
| 79 |
+
except: # noqa: E722
|
| 80 |
+
pass
|
| 81 |
+
|
| 82 |
+
def getitems(self, keys, on_error="raise"):
|
| 83 |
+
"""Fetch multiple items from the store
|
| 84 |
+
|
| 85 |
+
If the backend is async-able, this might proceed concurrently
|
| 86 |
+
|
| 87 |
+
Parameters
|
| 88 |
+
----------
|
| 89 |
+
keys: list(str)
|
| 90 |
+
They keys to be fetched
|
| 91 |
+
on_error : "raise", "omit", "return"
|
| 92 |
+
If raise, an underlying exception will be raised (converted to KeyError
|
| 93 |
+
if the type is in self.missing_exceptions); if omit, keys with exception
|
| 94 |
+
will simply not be included in the output; if "return", all keys are
|
| 95 |
+
included in the output, but the value will be bytes or an exception
|
| 96 |
+
instance.
|
| 97 |
+
|
| 98 |
+
Returns
|
| 99 |
+
-------
|
| 100 |
+
dict(key, bytes|exception)
|
| 101 |
+
"""
|
| 102 |
+
keys2 = [self._key_to_str(k) for k in keys]
|
| 103 |
+
oe = on_error if on_error == "raise" else "return"
|
| 104 |
+
try:
|
| 105 |
+
out = self.fs.cat(keys2, on_error=oe)
|
| 106 |
+
if isinstance(out, bytes):
|
| 107 |
+
out = {keys2[0]: out}
|
| 108 |
+
except self.missing_exceptions as e:
|
| 109 |
+
raise KeyError from e
|
| 110 |
+
out = {
|
| 111 |
+
k: (KeyError() if isinstance(v, self.missing_exceptions) else v)
|
| 112 |
+
for k, v in out.items()
|
| 113 |
+
}
|
| 114 |
+
return {
|
| 115 |
+
key: out[k2] if on_error == "raise" else out.get(k2, KeyError(k2))
|
| 116 |
+
for key, k2 in zip(keys, keys2)
|
| 117 |
+
if on_error == "return" or not isinstance(out[k2], BaseException)
|
| 118 |
+
}
|
| 119 |
+
|
| 120 |
+
def setitems(self, values_dict):
|
| 121 |
+
"""Set the values of multiple items in the store
|
| 122 |
+
|
| 123 |
+
Parameters
|
| 124 |
+
----------
|
| 125 |
+
values_dict: dict(str, bytes)
|
| 126 |
+
"""
|
| 127 |
+
values = {self._key_to_str(k): maybe_convert(v) for k, v in values_dict.items()}
|
| 128 |
+
self.fs.pipe(values)
|
| 129 |
+
|
| 130 |
+
def delitems(self, keys):
|
| 131 |
+
"""Remove multiple keys from the store"""
|
| 132 |
+
self.fs.rm([self._key_to_str(k) for k in keys])
|
| 133 |
+
|
| 134 |
+
def _key_to_str(self, key):
|
| 135 |
+
"""Generate full path for the key"""
|
| 136 |
+
if not isinstance(key, str):
|
| 137 |
+
# raise TypeError("key must be of type `str`, got `{type(key).__name__}`"
|
| 138 |
+
warnings.warn(
|
| 139 |
+
"from fsspec 2023.5 onward FSMap non-str keys will raise TypeError",
|
| 140 |
+
DeprecationWarning,
|
| 141 |
+
)
|
| 142 |
+
if isinstance(key, list):
|
| 143 |
+
key = tuple(key)
|
| 144 |
+
key = str(key)
|
| 145 |
+
return f"{self._root_key_to_str}{key}".rstrip("/")
|
| 146 |
+
|
| 147 |
+
def _str_to_key(self, s):
|
| 148 |
+
"""Strip path of to leave key name"""
|
| 149 |
+
return s[len(self.root) :].lstrip("/")
|
| 150 |
+
|
| 151 |
+
def __getitem__(self, key, default=None):
|
| 152 |
+
"""Retrieve data"""
|
| 153 |
+
k = self._key_to_str(key)
|
| 154 |
+
try:
|
| 155 |
+
result = self.fs.cat(k)
|
| 156 |
+
except self.missing_exceptions as exc:
|
| 157 |
+
if default is not None:
|
| 158 |
+
return default
|
| 159 |
+
raise KeyError(key) from exc
|
| 160 |
+
return result
|
| 161 |
+
|
| 162 |
+
def pop(self, key, default=None):
|
| 163 |
+
"""Pop data"""
|
| 164 |
+
result = self.__getitem__(key, default)
|
| 165 |
+
try:
|
| 166 |
+
del self[key]
|
| 167 |
+
except KeyError:
|
| 168 |
+
pass
|
| 169 |
+
return result
|
| 170 |
+
|
| 171 |
+
def __setitem__(self, key, value):
|
| 172 |
+
"""Store value in key"""
|
| 173 |
+
key = self._key_to_str(key)
|
| 174 |
+
self.fs.mkdirs(self.fs._parent(key), exist_ok=True)
|
| 175 |
+
self.fs.pipe_file(key, maybe_convert(value))
|
| 176 |
+
|
| 177 |
+
def __iter__(self):
|
| 178 |
+
return (self._str_to_key(x) for x in self.fs.find(self.root))
|
| 179 |
+
|
| 180 |
+
def __len__(self):
|
| 181 |
+
return len(self.fs.find(self.root))
|
| 182 |
+
|
| 183 |
+
def __delitem__(self, key):
|
| 184 |
+
"""Remove key"""
|
| 185 |
+
try:
|
| 186 |
+
self.fs.rm(self._key_to_str(key))
|
| 187 |
+
except Exception as exc:
|
| 188 |
+
raise KeyError from exc
|
| 189 |
+
|
| 190 |
+
def __contains__(self, key):
|
| 191 |
+
"""Does key exist in mapping?"""
|
| 192 |
+
path = self._key_to_str(key)
|
| 193 |
+
return self.fs.isfile(path)
|
| 194 |
+
|
| 195 |
+
def __reduce__(self):
|
| 196 |
+
return FSMap, (self.root, self.fs, False, False, self.missing_exceptions)
|
| 197 |
+
|
| 198 |
+
|
| 199 |
+
def maybe_convert(value):
|
| 200 |
+
if isinstance(value, array.array) or hasattr(value, "__array__"):
|
| 201 |
+
# bytes-like things
|
| 202 |
+
if hasattr(value, "dtype") and value.dtype.kind in "Mm":
|
| 203 |
+
# The buffer interface doesn't support datetime64/timdelta64 numpy
|
| 204 |
+
# arrays
|
| 205 |
+
value = value.view("int64")
|
| 206 |
+
value = bytes(memoryview(value))
|
| 207 |
+
return value
|
| 208 |
+
|
| 209 |
+
|
| 210 |
+
def get_mapper(
|
| 211 |
+
url="",
|
| 212 |
+
check=False,
|
| 213 |
+
create=False,
|
| 214 |
+
missing_exceptions=None,
|
| 215 |
+
alternate_root=None,
|
| 216 |
+
**kwargs,
|
| 217 |
+
):
|
| 218 |
+
"""Create key-value interface for given URL and options
|
| 219 |
+
|
| 220 |
+
The URL will be of the form "protocol://location" and point to the root
|
| 221 |
+
of the mapper required. All keys will be file-names below this location,
|
| 222 |
+
and their values the contents of each key.
|
| 223 |
+
|
| 224 |
+
Also accepts compound URLs like zip::s3://bucket/file.zip , see ``fsspec.open``.
|
| 225 |
+
|
| 226 |
+
Parameters
|
| 227 |
+
----------
|
| 228 |
+
url: str
|
| 229 |
+
Root URL of mapping
|
| 230 |
+
check: bool
|
| 231 |
+
Whether to attempt to read from the location before instantiation, to
|
| 232 |
+
check that the mapping does exist
|
| 233 |
+
create: bool
|
| 234 |
+
Whether to make the directory corresponding to the root before
|
| 235 |
+
instantiating
|
| 236 |
+
missing_exceptions: None or tuple
|
| 237 |
+
If given, these exception types will be regarded as missing keys and
|
| 238 |
+
return KeyError when trying to read data. By default, you get
|
| 239 |
+
(FileNotFoundError, IsADirectoryError, NotADirectoryError)
|
| 240 |
+
alternate_root: None or str
|
| 241 |
+
In cases of complex URLs, the parser may fail to pick the correct part
|
| 242 |
+
for the mapper root, so this arg can override
|
| 243 |
+
|
| 244 |
+
Returns
|
| 245 |
+
-------
|
| 246 |
+
``FSMap`` instance, the dict-like key-value store.
|
| 247 |
+
"""
|
| 248 |
+
# Removing protocol here - could defer to each open() on the backend
|
| 249 |
+
fs, urlpath = url_to_fs(url, **kwargs)
|
| 250 |
+
root = alternate_root if alternate_root is not None else urlpath
|
| 251 |
+
return FSMap(root, fs, check, create, missing_exceptions=missing_exceptions)
|
LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/fsspec/utils.py
ADDED
|
@@ -0,0 +1,748 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
|
| 3 |
+
import contextlib
|
| 4 |
+
import logging
|
| 5 |
+
import math
|
| 6 |
+
import os
|
| 7 |
+
import re
|
| 8 |
+
import sys
|
| 9 |
+
import tempfile
|
| 10 |
+
from collections.abc import Callable, Iterable, Iterator, Sequence
|
| 11 |
+
from functools import partial
|
| 12 |
+
from hashlib import md5
|
| 13 |
+
from importlib.metadata import version
|
| 14 |
+
from typing import IO, TYPE_CHECKING, Any, TypeVar
|
| 15 |
+
from urllib.parse import urlsplit
|
| 16 |
+
|
| 17 |
+
if TYPE_CHECKING:
|
| 18 |
+
import pathlib
|
| 19 |
+
from typing import TypeGuard
|
| 20 |
+
|
| 21 |
+
from fsspec.spec import AbstractFileSystem
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
DEFAULT_BLOCK_SIZE = 5 * 2**20
|
| 25 |
+
|
| 26 |
+
T = TypeVar("T")
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
def infer_storage_options(
|
| 30 |
+
urlpath: str, inherit_storage_options: dict[str, Any] | None = None
|
| 31 |
+
) -> dict[str, Any]:
|
| 32 |
+
"""Infer storage options from URL path and merge it with existing storage
|
| 33 |
+
options.
|
| 34 |
+
|
| 35 |
+
Parameters
|
| 36 |
+
----------
|
| 37 |
+
urlpath: str or unicode
|
| 38 |
+
Either local absolute file path or URL (hdfs://namenode:8020/file.csv)
|
| 39 |
+
inherit_storage_options: dict (optional)
|
| 40 |
+
Its contents will get merged with the inferred information from the
|
| 41 |
+
given path
|
| 42 |
+
|
| 43 |
+
Returns
|
| 44 |
+
-------
|
| 45 |
+
Storage options dict.
|
| 46 |
+
|
| 47 |
+
Examples
|
| 48 |
+
--------
|
| 49 |
+
>>> infer_storage_options('/mnt/datasets/test.csv') # doctest: +SKIP
|
| 50 |
+
{"protocol": "file", "path", "/mnt/datasets/test.csv"}
|
| 51 |
+
>>> infer_storage_options(
|
| 52 |
+
... 'hdfs://username:pwd@node:123/mnt/datasets/test.csv?q=1',
|
| 53 |
+
... inherit_storage_options={'extra': 'value'},
|
| 54 |
+
... ) # doctest: +SKIP
|
| 55 |
+
{"protocol": "hdfs", "username": "username", "password": "pwd",
|
| 56 |
+
"host": "node", "port": 123, "path": "/mnt/datasets/test.csv",
|
| 57 |
+
"url_query": "q=1", "extra": "value"}
|
| 58 |
+
"""
|
| 59 |
+
# Handle Windows paths including disk name in this special case
|
| 60 |
+
if (
|
| 61 |
+
re.match(r"^[a-zA-Z]:[\\/]", urlpath)
|
| 62 |
+
or re.match(r"^[a-zA-Z0-9]+://", urlpath) is None
|
| 63 |
+
):
|
| 64 |
+
return {"protocol": "file", "path": urlpath}
|
| 65 |
+
|
| 66 |
+
parsed_path = urlsplit(urlpath)
|
| 67 |
+
protocol = parsed_path.scheme or "file"
|
| 68 |
+
if parsed_path.fragment:
|
| 69 |
+
path = "#".join([parsed_path.path, parsed_path.fragment])
|
| 70 |
+
else:
|
| 71 |
+
path = parsed_path.path
|
| 72 |
+
if protocol == "file":
|
| 73 |
+
# Special case parsing file protocol URL on Windows according to:
|
| 74 |
+
# https://msdn.microsoft.com/en-us/library/jj710207.aspx
|
| 75 |
+
windows_path = re.match(r"^/([a-zA-Z])[:|]([\\/].*)$", path)
|
| 76 |
+
if windows_path:
|
| 77 |
+
drive, path = windows_path.groups()
|
| 78 |
+
path = f"{drive}:{path}"
|
| 79 |
+
|
| 80 |
+
if protocol in ["http", "https"]:
|
| 81 |
+
# for HTTP, we don't want to parse, as requests will anyway
|
| 82 |
+
return {"protocol": protocol, "path": urlpath}
|
| 83 |
+
|
| 84 |
+
options: dict[str, Any] = {"protocol": protocol, "path": path}
|
| 85 |
+
|
| 86 |
+
if parsed_path.netloc:
|
| 87 |
+
# Parse `hostname` from netloc manually because `parsed_path.hostname`
|
| 88 |
+
# lowercases the hostname which is not always desirable (e.g. in S3):
|
| 89 |
+
# https://github.com/dask/dask/issues/1417
|
| 90 |
+
options["host"] = parsed_path.netloc.rsplit("@", 1)[-1].rsplit(":", 1)[0]
|
| 91 |
+
|
| 92 |
+
if protocol in ("s3", "s3a", "gcs", "gs"):
|
| 93 |
+
options["path"] = options["host"] + options["path"]
|
| 94 |
+
else:
|
| 95 |
+
options["host"] = options["host"]
|
| 96 |
+
if parsed_path.port:
|
| 97 |
+
options["port"] = parsed_path.port
|
| 98 |
+
if parsed_path.username:
|
| 99 |
+
options["username"] = parsed_path.username
|
| 100 |
+
if parsed_path.password:
|
| 101 |
+
options["password"] = parsed_path.password
|
| 102 |
+
|
| 103 |
+
if parsed_path.query:
|
| 104 |
+
options["url_query"] = parsed_path.query
|
| 105 |
+
if parsed_path.fragment:
|
| 106 |
+
options["url_fragment"] = parsed_path.fragment
|
| 107 |
+
|
| 108 |
+
if inherit_storage_options:
|
| 109 |
+
update_storage_options(options, inherit_storage_options)
|
| 110 |
+
|
| 111 |
+
return options
|
| 112 |
+
|
| 113 |
+
|
| 114 |
+
def update_storage_options(
|
| 115 |
+
options: dict[str, Any], inherited: dict[str, Any] | None = None
|
| 116 |
+
) -> None:
|
| 117 |
+
if not inherited:
|
| 118 |
+
inherited = {}
|
| 119 |
+
collisions = set(options) & set(inherited)
|
| 120 |
+
if collisions:
|
| 121 |
+
for collision in collisions:
|
| 122 |
+
if options.get(collision) != inherited.get(collision):
|
| 123 |
+
raise KeyError(
|
| 124 |
+
f"Collision between inferred and specified storage "
|
| 125 |
+
f"option:\n{collision}"
|
| 126 |
+
)
|
| 127 |
+
options.update(inherited)
|
| 128 |
+
|
| 129 |
+
|
| 130 |
+
# Compression extensions registered via fsspec.compression.register_compression
|
| 131 |
+
compressions: dict[str, str] = {}
|
| 132 |
+
|
| 133 |
+
|
| 134 |
+
def infer_compression(filename: str) -> str | None:
|
| 135 |
+
"""Infer compression, if available, from filename.
|
| 136 |
+
|
| 137 |
+
Infer a named compression type, if registered and available, from filename
|
| 138 |
+
extension. This includes builtin (gz, bz2, zip) compressions, as well as
|
| 139 |
+
optional compressions. See fsspec.compression.register_compression.
|
| 140 |
+
"""
|
| 141 |
+
extension = os.path.splitext(filename)[-1].strip(".").lower()
|
| 142 |
+
if extension in compressions:
|
| 143 |
+
return compressions[extension]
|
| 144 |
+
return None
|
| 145 |
+
|
| 146 |
+
|
| 147 |
+
def build_name_function(max_int: float) -> Callable[[int], str]:
|
| 148 |
+
"""Returns a function that receives a single integer
|
| 149 |
+
and returns it as a string padded by enough zero characters
|
| 150 |
+
to align with maximum possible integer
|
| 151 |
+
|
| 152 |
+
>>> name_f = build_name_function(57)
|
| 153 |
+
|
| 154 |
+
>>> name_f(7)
|
| 155 |
+
'07'
|
| 156 |
+
>>> name_f(31)
|
| 157 |
+
'31'
|
| 158 |
+
>>> build_name_function(1000)(42)
|
| 159 |
+
'0042'
|
| 160 |
+
>>> build_name_function(999)(42)
|
| 161 |
+
'042'
|
| 162 |
+
>>> build_name_function(0)(0)
|
| 163 |
+
'0'
|
| 164 |
+
"""
|
| 165 |
+
# handle corner cases max_int is 0 or exact power of 10
|
| 166 |
+
max_int += 1e-8
|
| 167 |
+
|
| 168 |
+
pad_length = int(math.ceil(math.log10(max_int)))
|
| 169 |
+
|
| 170 |
+
def name_function(i: int) -> str:
|
| 171 |
+
return str(i).zfill(pad_length)
|
| 172 |
+
|
| 173 |
+
return name_function
|
| 174 |
+
|
| 175 |
+
|
| 176 |
+
def seek_delimiter(file: IO[bytes], delimiter: bytes, blocksize: int) -> bool:
|
| 177 |
+
r"""Seek current file to file start, file end, or byte after delimiter seq.
|
| 178 |
+
|
| 179 |
+
Seeks file to next chunk delimiter, where chunks are defined on file start,
|
| 180 |
+
a delimiting sequence, and file end. Use file.tell() to see location afterwards.
|
| 181 |
+
Note that file start is a valid split, so must be at offset > 0 to seek for
|
| 182 |
+
delimiter.
|
| 183 |
+
|
| 184 |
+
Parameters
|
| 185 |
+
----------
|
| 186 |
+
file: a file
|
| 187 |
+
delimiter: bytes
|
| 188 |
+
a delimiter like ``b'\n'`` or message sentinel, matching file .read() type
|
| 189 |
+
blocksize: int
|
| 190 |
+
Number of bytes to read from the file at once.
|
| 191 |
+
|
| 192 |
+
|
| 193 |
+
Returns
|
| 194 |
+
-------
|
| 195 |
+
Returns True if a delimiter was found, False if at file start or end.
|
| 196 |
+
|
| 197 |
+
"""
|
| 198 |
+
|
| 199 |
+
if file.tell() == 0:
|
| 200 |
+
# beginning-of-file, return without seek
|
| 201 |
+
return False
|
| 202 |
+
|
| 203 |
+
# Interface is for binary IO, with delimiter as bytes, but initialize last
|
| 204 |
+
# with result of file.read to preserve compatibility with text IO.
|
| 205 |
+
last: bytes | None = None
|
| 206 |
+
while True:
|
| 207 |
+
current = file.read(blocksize)
|
| 208 |
+
if not current:
|
| 209 |
+
# end-of-file without delimiter
|
| 210 |
+
return False
|
| 211 |
+
full = last + current if last else current
|
| 212 |
+
try:
|
| 213 |
+
if delimiter in full:
|
| 214 |
+
i = full.index(delimiter)
|
| 215 |
+
file.seek(file.tell() - (len(full) - i) + len(delimiter))
|
| 216 |
+
return True
|
| 217 |
+
elif len(current) < blocksize:
|
| 218 |
+
# end-of-file without delimiter
|
| 219 |
+
return False
|
| 220 |
+
except (OSError, ValueError):
|
| 221 |
+
pass
|
| 222 |
+
last = full[-len(delimiter) :]
|
| 223 |
+
|
| 224 |
+
|
| 225 |
+
def read_block(
|
| 226 |
+
f: IO[bytes],
|
| 227 |
+
offset: int,
|
| 228 |
+
length: int | None,
|
| 229 |
+
delimiter: bytes | None = None,
|
| 230 |
+
split_before: bool = False,
|
| 231 |
+
) -> bytes:
|
| 232 |
+
"""Read a block of bytes from a file
|
| 233 |
+
|
| 234 |
+
Parameters
|
| 235 |
+
----------
|
| 236 |
+
f: File
|
| 237 |
+
Open file
|
| 238 |
+
offset: int
|
| 239 |
+
Byte offset to start read
|
| 240 |
+
length: int
|
| 241 |
+
Number of bytes to read, read through end of file if None
|
| 242 |
+
delimiter: bytes (optional)
|
| 243 |
+
Ensure reading starts and stops at delimiter bytestring
|
| 244 |
+
split_before: bool (optional)
|
| 245 |
+
Start/stop read *before* delimiter bytestring.
|
| 246 |
+
|
| 247 |
+
|
| 248 |
+
If using the ``delimiter=`` keyword argument we ensure that the read
|
| 249 |
+
starts and stops at delimiter boundaries that follow the locations
|
| 250 |
+
``offset`` and ``offset + length``. If ``offset`` is zero then we
|
| 251 |
+
start at zero, regardless of delimiter. The bytestring returned WILL
|
| 252 |
+
include the terminating delimiter string.
|
| 253 |
+
|
| 254 |
+
Examples
|
| 255 |
+
--------
|
| 256 |
+
|
| 257 |
+
>>> from io import BytesIO # doctest: +SKIP
|
| 258 |
+
>>> f = BytesIO(b'Alice, 100\\nBob, 200\\nCharlie, 300') # doctest: +SKIP
|
| 259 |
+
>>> read_block(f, 0, 13) # doctest: +SKIP
|
| 260 |
+
b'Alice, 100\\nBo'
|
| 261 |
+
|
| 262 |
+
>>> read_block(f, 0, 13, delimiter=b'\\n') # doctest: +SKIP
|
| 263 |
+
b'Alice, 100\\nBob, 200\\n'
|
| 264 |
+
|
| 265 |
+
>>> read_block(f, 10, 10, delimiter=b'\\n') # doctest: +SKIP
|
| 266 |
+
b'Bob, 200\\nCharlie, 300'
|
| 267 |
+
"""
|
| 268 |
+
if delimiter:
|
| 269 |
+
f.seek(offset)
|
| 270 |
+
found_start_delim = seek_delimiter(f, delimiter, 2**16)
|
| 271 |
+
if length is None:
|
| 272 |
+
return f.read()
|
| 273 |
+
start = f.tell()
|
| 274 |
+
length -= start - offset
|
| 275 |
+
|
| 276 |
+
f.seek(start + length)
|
| 277 |
+
found_end_delim = seek_delimiter(f, delimiter, 2**16)
|
| 278 |
+
end = f.tell()
|
| 279 |
+
|
| 280 |
+
# Adjust split location to before delimiter if seek found the
|
| 281 |
+
# delimiter sequence, not start or end of file.
|
| 282 |
+
if found_start_delim and split_before:
|
| 283 |
+
start -= len(delimiter)
|
| 284 |
+
|
| 285 |
+
if found_end_delim and split_before:
|
| 286 |
+
end -= len(delimiter)
|
| 287 |
+
|
| 288 |
+
offset = start
|
| 289 |
+
length = end - start
|
| 290 |
+
|
| 291 |
+
f.seek(offset)
|
| 292 |
+
|
| 293 |
+
# TODO: allow length to be None and read to the end of the file?
|
| 294 |
+
assert length is not None
|
| 295 |
+
b = f.read(length)
|
| 296 |
+
return b
|
| 297 |
+
|
| 298 |
+
|
| 299 |
+
def tokenize(*args: Any, **kwargs: Any) -> str:
|
| 300 |
+
"""Deterministic token
|
| 301 |
+
|
| 302 |
+
(modified from dask.base)
|
| 303 |
+
|
| 304 |
+
>>> tokenize([1, 2, '3'])
|
| 305 |
+
'9d71491b50023b06fc76928e6eddb952'
|
| 306 |
+
|
| 307 |
+
>>> tokenize('Hello') == tokenize('Hello')
|
| 308 |
+
True
|
| 309 |
+
"""
|
| 310 |
+
if kwargs:
|
| 311 |
+
args += (kwargs,)
|
| 312 |
+
try:
|
| 313 |
+
h = md5(str(args).encode())
|
| 314 |
+
except ValueError:
|
| 315 |
+
# FIPS systems: https://github.com/fsspec/filesystem_spec/issues/380
|
| 316 |
+
h = md5(str(args).encode(), usedforsecurity=False)
|
| 317 |
+
return h.hexdigest()
|
| 318 |
+
|
| 319 |
+
|
| 320 |
+
def stringify_path(filepath: str | os.PathLike[str] | pathlib.Path) -> str:
|
| 321 |
+
"""Attempt to convert a path-like object to a string.
|
| 322 |
+
|
| 323 |
+
Parameters
|
| 324 |
+
----------
|
| 325 |
+
filepath: object to be converted
|
| 326 |
+
|
| 327 |
+
Returns
|
| 328 |
+
-------
|
| 329 |
+
filepath_str: maybe a string version of the object
|
| 330 |
+
|
| 331 |
+
Notes
|
| 332 |
+
-----
|
| 333 |
+
Objects supporting the fspath protocol are coerced according to its
|
| 334 |
+
__fspath__ method.
|
| 335 |
+
|
| 336 |
+
For backwards compatibility with older Python version, pathlib.Path
|
| 337 |
+
objects are specially coerced.
|
| 338 |
+
|
| 339 |
+
Any other object is passed through unchanged, which includes bytes,
|
| 340 |
+
strings, buffers, or anything else that's not even path-like.
|
| 341 |
+
"""
|
| 342 |
+
if isinstance(filepath, str):
|
| 343 |
+
return filepath
|
| 344 |
+
elif hasattr(filepath, "__fspath__"):
|
| 345 |
+
return filepath.__fspath__()
|
| 346 |
+
elif hasattr(filepath, "path"):
|
| 347 |
+
return filepath.path
|
| 348 |
+
else:
|
| 349 |
+
return filepath # type: ignore[return-value]
|
| 350 |
+
|
| 351 |
+
|
| 352 |
+
def make_instance(
|
| 353 |
+
cls: Callable[..., T], args: Sequence[Any], kwargs: dict[str, Any]
|
| 354 |
+
) -> T:
|
| 355 |
+
inst = cls(*args, **kwargs)
|
| 356 |
+
inst._determine_worker() # type: ignore[attr-defined]
|
| 357 |
+
return inst
|
| 358 |
+
|
| 359 |
+
|
| 360 |
+
def common_prefix(paths: Iterable[str]) -> str:
|
| 361 |
+
"""For a list of paths, find the shortest prefix common to all"""
|
| 362 |
+
parts = [p.split("/") for p in paths]
|
| 363 |
+
lmax = min(len(p) for p in parts)
|
| 364 |
+
end = 0
|
| 365 |
+
for i in range(lmax):
|
| 366 |
+
end = all(p[i] == parts[0][i] for p in parts)
|
| 367 |
+
if not end:
|
| 368 |
+
break
|
| 369 |
+
i += end
|
| 370 |
+
return "/".join(parts[0][:i])
|
| 371 |
+
|
| 372 |
+
|
| 373 |
+
def other_paths(
|
| 374 |
+
paths: list[str],
|
| 375 |
+
path2: str | list[str],
|
| 376 |
+
exists: bool = False,
|
| 377 |
+
flatten: bool = False,
|
| 378 |
+
) -> list[str]:
|
| 379 |
+
"""In bulk file operations, construct a new file tree from a list of files
|
| 380 |
+
|
| 381 |
+
Parameters
|
| 382 |
+
----------
|
| 383 |
+
paths: list of str
|
| 384 |
+
The input file tree
|
| 385 |
+
path2: str or list of str
|
| 386 |
+
Root to construct the new list in. If this is already a list of str, we just
|
| 387 |
+
assert it has the right number of elements.
|
| 388 |
+
exists: bool (optional)
|
| 389 |
+
For a str destination, it is already exists (and is a dir), files should
|
| 390 |
+
end up inside.
|
| 391 |
+
flatten: bool (optional)
|
| 392 |
+
Whether to flatten the input directory tree structure so that the output files
|
| 393 |
+
are in the same directory.
|
| 394 |
+
|
| 395 |
+
Returns
|
| 396 |
+
-------
|
| 397 |
+
list of str
|
| 398 |
+
"""
|
| 399 |
+
|
| 400 |
+
if isinstance(path2, str):
|
| 401 |
+
path2 = path2.rstrip("/")
|
| 402 |
+
|
| 403 |
+
if flatten:
|
| 404 |
+
path2 = ["/".join((path2, p.split("/")[-1])) for p in paths]
|
| 405 |
+
else:
|
| 406 |
+
cp = common_prefix(paths)
|
| 407 |
+
if exists:
|
| 408 |
+
cp = cp.rsplit("/", 1)[0]
|
| 409 |
+
if not cp and all(not s.startswith("/") for s in paths):
|
| 410 |
+
path2 = ["/".join([path2, p]) for p in paths]
|
| 411 |
+
else:
|
| 412 |
+
path2 = [p.replace(cp, path2, 1) for p in paths]
|
| 413 |
+
else:
|
| 414 |
+
assert len(paths) == len(path2)
|
| 415 |
+
return path2
|
| 416 |
+
|
| 417 |
+
|
| 418 |
+
def is_exception(obj: Any) -> bool:
|
| 419 |
+
return isinstance(obj, BaseException)
|
| 420 |
+
|
| 421 |
+
|
| 422 |
+
def isfilelike(f: Any) -> TypeGuard[IO[bytes]]:
|
| 423 |
+
return all(hasattr(f, attr) for attr in ["read", "close", "tell"])
|
| 424 |
+
|
| 425 |
+
|
| 426 |
+
def get_protocol(url: str) -> str:
|
| 427 |
+
url = stringify_path(url)
|
| 428 |
+
parts = re.split(r"(\:\:|\://)", url, maxsplit=1)
|
| 429 |
+
if len(parts) > 1:
|
| 430 |
+
return parts[0]
|
| 431 |
+
return "file"
|
| 432 |
+
|
| 433 |
+
|
| 434 |
+
def get_file_extension(url: str) -> str:
|
| 435 |
+
url = stringify_path(url)
|
| 436 |
+
ext_parts = url.rsplit(".", 1)
|
| 437 |
+
if len(ext_parts) > 1:
|
| 438 |
+
return ext_parts[-1]
|
| 439 |
+
return ""
|
| 440 |
+
|
| 441 |
+
|
| 442 |
+
def can_be_local(path: str) -> bool:
|
| 443 |
+
"""Can the given URL be used with open_local?"""
|
| 444 |
+
from fsspec import get_filesystem_class
|
| 445 |
+
|
| 446 |
+
try:
|
| 447 |
+
return getattr(get_filesystem_class(get_protocol(path)), "local_file", False)
|
| 448 |
+
except (ValueError, ImportError):
|
| 449 |
+
# not in registry or import failed
|
| 450 |
+
return False
|
| 451 |
+
|
| 452 |
+
|
| 453 |
+
def get_package_version_without_import(name: str) -> str | None:
|
| 454 |
+
"""For given package name, try to find the version without importing it
|
| 455 |
+
|
| 456 |
+
Import and package.__version__ is still the backup here, so an import
|
| 457 |
+
*might* happen.
|
| 458 |
+
|
| 459 |
+
Returns either the version string, or None if the package
|
| 460 |
+
or the version was not readily found.
|
| 461 |
+
"""
|
| 462 |
+
if name in sys.modules:
|
| 463 |
+
mod = sys.modules[name]
|
| 464 |
+
if hasattr(mod, "__version__"):
|
| 465 |
+
return mod.__version__
|
| 466 |
+
try:
|
| 467 |
+
return version(name)
|
| 468 |
+
except: # noqa: E722
|
| 469 |
+
pass
|
| 470 |
+
try:
|
| 471 |
+
import importlib
|
| 472 |
+
|
| 473 |
+
mod = importlib.import_module(name)
|
| 474 |
+
return mod.__version__
|
| 475 |
+
except (ImportError, AttributeError):
|
| 476 |
+
return None
|
| 477 |
+
|
| 478 |
+
|
| 479 |
+
def setup_logging(
|
| 480 |
+
logger: logging.Logger | None = None,
|
| 481 |
+
logger_name: str | None = None,
|
| 482 |
+
level: str = "DEBUG",
|
| 483 |
+
clear: bool = True,
|
| 484 |
+
) -> logging.Logger:
|
| 485 |
+
if logger is None and logger_name is None:
|
| 486 |
+
raise ValueError("Provide either logger object or logger name")
|
| 487 |
+
logger = logger or logging.getLogger(logger_name)
|
| 488 |
+
handle = logging.StreamHandler()
|
| 489 |
+
formatter = logging.Formatter(
|
| 490 |
+
"%(asctime)s - %(name)s - %(levelname)s - %(funcName)s -- %(message)s"
|
| 491 |
+
)
|
| 492 |
+
handle.setFormatter(formatter)
|
| 493 |
+
if clear:
|
| 494 |
+
logger.handlers.clear()
|
| 495 |
+
logger.addHandler(handle)
|
| 496 |
+
logger.setLevel(level)
|
| 497 |
+
return logger
|
| 498 |
+
|
| 499 |
+
|
| 500 |
+
def _unstrip_protocol(name: str, fs: AbstractFileSystem) -> str:
|
| 501 |
+
return fs.unstrip_protocol(name)
|
| 502 |
+
|
| 503 |
+
|
| 504 |
+
def mirror_from(
|
| 505 |
+
origin_name: str, methods: Iterable[str]
|
| 506 |
+
) -> Callable[[type[T]], type[T]]:
|
| 507 |
+
"""Mirror attributes and methods from the given
|
| 508 |
+
origin_name attribute of the instance to the
|
| 509 |
+
decorated class"""
|
| 510 |
+
|
| 511 |
+
def origin_getter(method: str, self: Any) -> Any:
|
| 512 |
+
origin = getattr(self, origin_name)
|
| 513 |
+
return getattr(origin, method)
|
| 514 |
+
|
| 515 |
+
def wrapper(cls: type[T]) -> type[T]:
|
| 516 |
+
for method in methods:
|
| 517 |
+
wrapped_method = partial(origin_getter, method)
|
| 518 |
+
setattr(cls, method, property(wrapped_method))
|
| 519 |
+
return cls
|
| 520 |
+
|
| 521 |
+
return wrapper
|
| 522 |
+
|
| 523 |
+
|
| 524 |
+
@contextlib.contextmanager
|
| 525 |
+
def nullcontext(obj: T) -> Iterator[T]:
|
| 526 |
+
yield obj
|
| 527 |
+
|
| 528 |
+
|
| 529 |
+
def merge_offset_ranges(
|
| 530 |
+
paths: list[str],
|
| 531 |
+
starts: list[int] | int,
|
| 532 |
+
ends: list[int] | int,
|
| 533 |
+
max_gap: int = 0,
|
| 534 |
+
max_block: int | None = None,
|
| 535 |
+
sort: bool = True,
|
| 536 |
+
) -> tuple[list[str], list[int], list[int]]:
|
| 537 |
+
"""Merge adjacent byte-offset ranges when the inter-range
|
| 538 |
+
gap is <= `max_gap`, and when the merged byte range does not
|
| 539 |
+
exceed `max_block` (if specified). By default, this function
|
| 540 |
+
will re-order the input paths and byte ranges to ensure sorted
|
| 541 |
+
order. If the user can guarantee that the inputs are already
|
| 542 |
+
sorted, passing `sort=False` will skip the re-ordering.
|
| 543 |
+
"""
|
| 544 |
+
# Check input
|
| 545 |
+
if not isinstance(paths, list):
|
| 546 |
+
raise TypeError
|
| 547 |
+
if not isinstance(starts, list):
|
| 548 |
+
starts = [starts] * len(paths)
|
| 549 |
+
if not isinstance(ends, list):
|
| 550 |
+
ends = [ends] * len(paths)
|
| 551 |
+
if len(starts) != len(paths) or len(ends) != len(paths):
|
| 552 |
+
raise ValueError
|
| 553 |
+
|
| 554 |
+
# Early Return
|
| 555 |
+
if len(starts) <= 1:
|
| 556 |
+
return paths, starts, ends
|
| 557 |
+
|
| 558 |
+
starts = [s or 0 for s in starts]
|
| 559 |
+
# Sort by paths and then ranges if `sort=True`
|
| 560 |
+
if sort:
|
| 561 |
+
paths, starts, ends = (
|
| 562 |
+
list(v)
|
| 563 |
+
for v in zip(
|
| 564 |
+
*sorted(
|
| 565 |
+
zip(paths, starts, ends),
|
| 566 |
+
)
|
| 567 |
+
)
|
| 568 |
+
)
|
| 569 |
+
remove = []
|
| 570 |
+
for i, (path, start, end) in enumerate(zip(paths, starts, ends)):
|
| 571 |
+
if any(
|
| 572 |
+
e is not None and p == path and start >= s and end <= e and i != i2
|
| 573 |
+
for i2, (p, s, e) in enumerate(zip(paths, starts, ends))
|
| 574 |
+
):
|
| 575 |
+
remove.append(i)
|
| 576 |
+
paths = [p for i, p in enumerate(paths) if i not in remove]
|
| 577 |
+
starts = [s for i, s in enumerate(starts) if i not in remove]
|
| 578 |
+
ends = [e for i, e in enumerate(ends) if i not in remove]
|
| 579 |
+
|
| 580 |
+
if paths:
|
| 581 |
+
# Loop through the coupled `paths`, `starts`, and
|
| 582 |
+
# `ends`, and merge adjacent blocks when appropriate
|
| 583 |
+
new_paths = paths[:1]
|
| 584 |
+
new_starts = starts[:1]
|
| 585 |
+
new_ends = ends[:1]
|
| 586 |
+
for i in range(1, len(paths)):
|
| 587 |
+
if paths[i] == paths[i - 1] and new_ends[-1] is None:
|
| 588 |
+
continue
|
| 589 |
+
elif (
|
| 590 |
+
paths[i] != paths[i - 1]
|
| 591 |
+
or ((starts[i] - new_ends[-1]) > max_gap)
|
| 592 |
+
or (max_block is not None and (ends[i] - new_starts[-1]) > max_block)
|
| 593 |
+
):
|
| 594 |
+
# Cannot merge with previous block.
|
| 595 |
+
# Add new `paths`, `starts`, and `ends` elements
|
| 596 |
+
new_paths.append(paths[i])
|
| 597 |
+
new_starts.append(starts[i])
|
| 598 |
+
new_ends.append(ends[i])
|
| 599 |
+
else:
|
| 600 |
+
# Merge with the previous block by updating the
|
| 601 |
+
# last element of `ends`
|
| 602 |
+
new_ends[-1] = ends[i]
|
| 603 |
+
return new_paths, new_starts, new_ends
|
| 604 |
+
|
| 605 |
+
# `paths` is empty. Just return input lists
|
| 606 |
+
return paths, starts, ends
|
| 607 |
+
|
| 608 |
+
|
| 609 |
+
def file_size(filelike: IO[bytes]) -> int:
|
| 610 |
+
"""Find length of any open read-mode file-like"""
|
| 611 |
+
pos = filelike.tell()
|
| 612 |
+
try:
|
| 613 |
+
return filelike.seek(0, 2)
|
| 614 |
+
finally:
|
| 615 |
+
filelike.seek(pos)
|
| 616 |
+
|
| 617 |
+
|
| 618 |
+
@contextlib.contextmanager
|
| 619 |
+
def atomic_write(path: str, mode: str = "wb"):
|
| 620 |
+
"""
|
| 621 |
+
A context manager that opens a temporary file next to `path` and, on exit,
|
| 622 |
+
replaces `path` with the temporary file, thereby updating `path`
|
| 623 |
+
atomically.
|
| 624 |
+
"""
|
| 625 |
+
fd, fn = tempfile.mkstemp(
|
| 626 |
+
dir=os.path.dirname(path), prefix=os.path.basename(path) + "-"
|
| 627 |
+
)
|
| 628 |
+
try:
|
| 629 |
+
with open(fd, mode) as fp:
|
| 630 |
+
yield fp
|
| 631 |
+
except BaseException:
|
| 632 |
+
with contextlib.suppress(FileNotFoundError):
|
| 633 |
+
os.unlink(fn)
|
| 634 |
+
raise
|
| 635 |
+
else:
|
| 636 |
+
os.replace(fn, path)
|
| 637 |
+
|
| 638 |
+
|
| 639 |
+
def _translate(pat, STAR, QUESTION_MARK):
|
| 640 |
+
# Copied from: https://github.com/python/cpython/pull/106703.
|
| 641 |
+
res: list[str] = []
|
| 642 |
+
add = res.append
|
| 643 |
+
i, n = 0, len(pat)
|
| 644 |
+
while i < n:
|
| 645 |
+
c = pat[i]
|
| 646 |
+
i = i + 1
|
| 647 |
+
if c == "*":
|
| 648 |
+
# compress consecutive `*` into one
|
| 649 |
+
if (not res) or res[-1] is not STAR:
|
| 650 |
+
add(STAR)
|
| 651 |
+
elif c == "?":
|
| 652 |
+
add(QUESTION_MARK)
|
| 653 |
+
elif c == "[":
|
| 654 |
+
j = i
|
| 655 |
+
if j < n and pat[j] == "!":
|
| 656 |
+
j = j + 1
|
| 657 |
+
if j < n and pat[j] == "]":
|
| 658 |
+
j = j + 1
|
| 659 |
+
while j < n and pat[j] != "]":
|
| 660 |
+
j = j + 1
|
| 661 |
+
if j >= n:
|
| 662 |
+
add("\\[")
|
| 663 |
+
else:
|
| 664 |
+
stuff = pat[i:j]
|
| 665 |
+
if "-" not in stuff:
|
| 666 |
+
stuff = stuff.replace("\\", r"\\")
|
| 667 |
+
else:
|
| 668 |
+
chunks = []
|
| 669 |
+
k = i + 2 if pat[i] == "!" else i + 1
|
| 670 |
+
while True:
|
| 671 |
+
k = pat.find("-", k, j)
|
| 672 |
+
if k < 0:
|
| 673 |
+
break
|
| 674 |
+
chunks.append(pat[i:k])
|
| 675 |
+
i = k + 1
|
| 676 |
+
k = k + 3
|
| 677 |
+
chunk = pat[i:j]
|
| 678 |
+
if chunk:
|
| 679 |
+
chunks.append(chunk)
|
| 680 |
+
else:
|
| 681 |
+
chunks[-1] += "-"
|
| 682 |
+
# Remove empty ranges -- invalid in RE.
|
| 683 |
+
for k in range(len(chunks) - 1, 0, -1):
|
| 684 |
+
if chunks[k - 1][-1] > chunks[k][0]:
|
| 685 |
+
chunks[k - 1] = chunks[k - 1][:-1] + chunks[k][1:]
|
| 686 |
+
del chunks[k]
|
| 687 |
+
# Escape backslashes and hyphens for set difference (--).
|
| 688 |
+
# Hyphens that create ranges shouldn't be escaped.
|
| 689 |
+
stuff = "-".join(
|
| 690 |
+
s.replace("\\", r"\\").replace("-", r"\-") for s in chunks
|
| 691 |
+
)
|
| 692 |
+
# Escape set operations (&&, ~~ and ||).
|
| 693 |
+
stuff = re.sub(r"([&~|])", r"\\\1", stuff)
|
| 694 |
+
i = j + 1
|
| 695 |
+
if not stuff:
|
| 696 |
+
# Empty range: never match.
|
| 697 |
+
add("(?!)")
|
| 698 |
+
elif stuff == "!":
|
| 699 |
+
# Negated empty range: match any character.
|
| 700 |
+
add(".")
|
| 701 |
+
else:
|
| 702 |
+
if stuff[0] == "!":
|
| 703 |
+
stuff = "^" + stuff[1:]
|
| 704 |
+
elif stuff[0] in ("^", "["):
|
| 705 |
+
stuff = "\\" + stuff
|
| 706 |
+
add(f"[{stuff}]")
|
| 707 |
+
else:
|
| 708 |
+
add(re.escape(c))
|
| 709 |
+
assert i == n
|
| 710 |
+
return res
|
| 711 |
+
|
| 712 |
+
|
| 713 |
+
def glob_translate(pat):
|
| 714 |
+
# Copied from: https://github.com/python/cpython/pull/106703.
|
| 715 |
+
# The keyword parameters' values are fixed to:
|
| 716 |
+
# recursive=True, include_hidden=True, seps=None
|
| 717 |
+
"""Translate a pathname with shell wildcards to a regular expression."""
|
| 718 |
+
if os.path.altsep:
|
| 719 |
+
seps = os.path.sep + os.path.altsep
|
| 720 |
+
else:
|
| 721 |
+
seps = os.path.sep
|
| 722 |
+
escaped_seps = "".join(map(re.escape, seps))
|
| 723 |
+
any_sep = f"[{escaped_seps}]" if len(seps) > 1 else escaped_seps
|
| 724 |
+
not_sep = f"[^{escaped_seps}]"
|
| 725 |
+
one_last_segment = f"{not_sep}+"
|
| 726 |
+
one_segment = f"{one_last_segment}{any_sep}"
|
| 727 |
+
any_segments = f"(?:.+{any_sep})?"
|
| 728 |
+
any_last_segments = ".*"
|
| 729 |
+
results = []
|
| 730 |
+
parts = re.split(any_sep, pat)
|
| 731 |
+
last_part_idx = len(parts) - 1
|
| 732 |
+
for idx, part in enumerate(parts):
|
| 733 |
+
if part == "*":
|
| 734 |
+
results.append(one_segment if idx < last_part_idx else one_last_segment)
|
| 735 |
+
continue
|
| 736 |
+
if part == "**":
|
| 737 |
+
results.append(any_segments if idx < last_part_idx else any_last_segments)
|
| 738 |
+
continue
|
| 739 |
+
elif "**" in part:
|
| 740 |
+
raise ValueError(
|
| 741 |
+
"Invalid pattern: '**' can only be an entire path component"
|
| 742 |
+
)
|
| 743 |
+
if part:
|
| 744 |
+
results.extend(_translate(part, f"{not_sep}*", not_sep))
|
| 745 |
+
if idx < last_part_idx:
|
| 746 |
+
results.append(any_sep)
|
| 747 |
+
res = "".join(results)
|
| 748 |
+
return rf"(?s:{res})\Z"
|
LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/numpy/ma/API_CHANGES.txt
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
.. -*- rest -*-
|
| 2 |
+
|
| 3 |
+
==================================================
|
| 4 |
+
API changes in the new masked array implementation
|
| 5 |
+
==================================================
|
| 6 |
+
|
| 7 |
+
Masked arrays are subclasses of ndarray
|
| 8 |
+
---------------------------------------
|
| 9 |
+
|
| 10 |
+
Contrary to the original implementation, masked arrays are now regular
|
| 11 |
+
ndarrays::
|
| 12 |
+
|
| 13 |
+
>>> x = masked_array([1,2,3],mask=[0,0,1])
|
| 14 |
+
>>> print isinstance(x, numpy.ndarray)
|
| 15 |
+
True
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
``_data`` returns a view of the masked array
|
| 19 |
+
--------------------------------------------
|
| 20 |
+
|
| 21 |
+
Masked arrays are composed of a ``_data`` part and a ``_mask``. Accessing the
|
| 22 |
+
``_data`` part will return a regular ndarray or any of its subclass, depending
|
| 23 |
+
on the initial data::
|
| 24 |
+
|
| 25 |
+
>>> x = masked_array(numpy.matrix([[1,2],[3,4]]),mask=[[0,0],[0,1]])
|
| 26 |
+
>>> print x._data
|
| 27 |
+
[[1 2]
|
| 28 |
+
[3 4]]
|
| 29 |
+
>>> print type(x._data)
|
| 30 |
+
<class 'numpy.matrixlib.defmatrix.matrix'>
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
In practice, ``_data`` is implemented as a property, not as an attribute.
|
| 34 |
+
Therefore, you cannot access it directly, and some simple tests such as the
|
| 35 |
+
following one will fail::
|
| 36 |
+
|
| 37 |
+
>>>x._data is x._data
|
| 38 |
+
False
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
``filled(x)`` can return a subclass of ndarray
|
| 42 |
+
----------------------------------------------
|
| 43 |
+
The function ``filled(a)`` returns an array of the same type as ``a._data``::
|
| 44 |
+
|
| 45 |
+
>>> x = masked_array(numpy.matrix([[1,2],[3,4]]),mask=[[0,0],[0,1]])
|
| 46 |
+
>>> y = filled(x)
|
| 47 |
+
>>> print type(y)
|
| 48 |
+
<class 'numpy.matrixlib.defmatrix.matrix'>
|
| 49 |
+
>>> print y
|
| 50 |
+
matrix([[ 1, 2],
|
| 51 |
+
[ 3, 999999]])
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
``put``, ``putmask`` behave like their ndarray counterparts
|
| 55 |
+
-----------------------------------------------------------
|
| 56 |
+
|
| 57 |
+
Previously, ``putmask`` was used like this::
|
| 58 |
+
|
| 59 |
+
mask = [False,True,True]
|
| 60 |
+
x = array([1,4,7],mask=mask)
|
| 61 |
+
putmask(x,mask,[3])
|
| 62 |
+
|
| 63 |
+
which translated to::
|
| 64 |
+
|
| 65 |
+
x[~mask] = [3]
|
| 66 |
+
|
| 67 |
+
(Note that a ``True``-value in a mask suppresses a value.)
|
| 68 |
+
|
| 69 |
+
In other words, the mask had the same length as ``x``, whereas
|
| 70 |
+
``values`` had ``sum(~mask)`` elements.
|
| 71 |
+
|
| 72 |
+
Now, the behaviour is similar to that of ``ndarray.putmask``, where
|
| 73 |
+
the mask and the values are both the same length as ``x``, i.e.
|
| 74 |
+
|
| 75 |
+
::
|
| 76 |
+
|
| 77 |
+
putmask(x,mask,[3,0,0])
|
| 78 |
+
|
| 79 |
+
|
| 80 |
+
``fill_value`` is a property
|
| 81 |
+
----------------------------
|
| 82 |
+
|
| 83 |
+
``fill_value`` is no longer a method, but a property::
|
| 84 |
+
|
| 85 |
+
>>> print x.fill_value
|
| 86 |
+
999999
|
| 87 |
+
|
| 88 |
+
``cumsum`` and ``cumprod`` ignore missing values
|
| 89 |
+
------------------------------------------------
|
| 90 |
+
|
| 91 |
+
Missing values are assumed to be the identity element, i.e. 0 for
|
| 92 |
+
``cumsum`` and 1 for ``cumprod``::
|
| 93 |
+
|
| 94 |
+
>>> x = N.ma.array([1,2,3,4],mask=[False,True,False,False])
|
| 95 |
+
>>> print x
|
| 96 |
+
[1 -- 3 4]
|
| 97 |
+
>>> print x.cumsum()
|
| 98 |
+
[1 -- 4 8]
|
| 99 |
+
>> print x.cumprod()
|
| 100 |
+
[1 -- 3 12]
|
| 101 |
+
|
| 102 |
+
``bool(x)`` raises a ValueError
|
| 103 |
+
-------------------------------
|
| 104 |
+
|
| 105 |
+
Masked arrays now behave like regular ``ndarrays``, in that they cannot be
|
| 106 |
+
converted to booleans:
|
| 107 |
+
|
| 108 |
+
::
|
| 109 |
+
|
| 110 |
+
>>> x = N.ma.array([1,2,3])
|
| 111 |
+
>>> bool(x)
|
| 112 |
+
Traceback (most recent call last):
|
| 113 |
+
File "<stdin>", line 1, in <module>
|
| 114 |
+
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
|
| 115 |
+
|
| 116 |
+
|
| 117 |
+
==================================
|
| 118 |
+
New features (non exhaustive list)
|
| 119 |
+
==================================
|
| 120 |
+
|
| 121 |
+
``mr_``
|
| 122 |
+
-------
|
| 123 |
+
|
| 124 |
+
``mr_`` mimics the behavior of ``r_`` for masked arrays::
|
| 125 |
+
|
| 126 |
+
>>> np.ma.mr_[3,4,5]
|
| 127 |
+
masked_array(data = [3 4 5],
|
| 128 |
+
mask = False,
|
| 129 |
+
fill_value=999999)
|
| 130 |
+
|
| 131 |
+
|
| 132 |
+
``anom``
|
| 133 |
+
--------
|
| 134 |
+
|
| 135 |
+
The ``anom`` method returns the deviations from the average (anomalies).
|
LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/numpy/ma/LICENSE
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
* Copyright (c) 2006, University of Georgia and Pierre G.F. Gerard-Marchant
|
| 2 |
+
* All rights reserved.
|
| 3 |
+
* Redistribution and use in source and binary forms, with or without
|
| 4 |
+
* modification, are permitted provided that the following conditions are met:
|
| 5 |
+
*
|
| 6 |
+
* * Redistributions of source code must retain the above copyright
|
| 7 |
+
* notice, this list of conditions and the following disclaimer.
|
| 8 |
+
* * Redistributions in binary form must reproduce the above copyright
|
| 9 |
+
* notice, this list of conditions and the following disclaimer in the
|
| 10 |
+
* documentation and/or other materials provided with the distribution.
|
| 11 |
+
* * Neither the name of the University of Georgia nor the
|
| 12 |
+
* names of its contributors may be used to endorse or promote products
|
| 13 |
+
* derived from this software without specific prior written permission.
|
| 14 |
+
*
|
| 15 |
+
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
|
| 16 |
+
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
| 17 |
+
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
| 18 |
+
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
| 19 |
+
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
| 20 |
+
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
| 21 |
+
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
| 22 |
+
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
| 23 |
+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
| 24 |
+
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/numpy/ma/README.rst
ADDED
|
@@ -0,0 +1,236 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
==================================
|
| 2 |
+
A Guide to Masked Arrays in NumPy
|
| 3 |
+
==================================
|
| 4 |
+
|
| 5 |
+
.. Contents::
|
| 6 |
+
|
| 7 |
+
See http://www.scipy.org/scipy/numpy/wiki/MaskedArray (dead link)
|
| 8 |
+
for updates of this document.
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
History
|
| 12 |
+
-------
|
| 13 |
+
|
| 14 |
+
As a regular user of MaskedArray, I (Pierre G.F. Gerard-Marchant) became
|
| 15 |
+
increasingly frustrated with the subclassing of masked arrays (even if
|
| 16 |
+
I can only blame my inexperience). I needed to develop a class of arrays
|
| 17 |
+
that could store some additional information along with numerical values,
|
| 18 |
+
while keeping the possibility for missing data (picture storing a series
|
| 19 |
+
of dates along with measurements, what would later become the `TimeSeries
|
| 20 |
+
Scikit <http://projects.scipy.org/scipy/scikits/wiki/TimeSeries>`__
|
| 21 |
+
(dead link).
|
| 22 |
+
|
| 23 |
+
I started to implement such a class, but then quickly realized that
|
| 24 |
+
any additional information disappeared when processing these subarrays
|
| 25 |
+
(for example, adding a constant value to a subarray would erase its
|
| 26 |
+
dates). I ended up writing the equivalent of *numpy.core.ma* for my
|
| 27 |
+
particular class, ufuncs included. Everything went fine until I needed to
|
| 28 |
+
subclass my new class, when more problems showed up: some attributes of
|
| 29 |
+
the new subclass were lost during processing. I identified the culprit as
|
| 30 |
+
MaskedArray, which returns masked ndarrays when I expected masked
|
| 31 |
+
arrays of my class. I was preparing myself to rewrite *numpy.core.ma*
|
| 32 |
+
when I forced myself to learn how to subclass ndarrays. As I became more
|
| 33 |
+
familiar with the *__new__* and *__array_finalize__* methods,
|
| 34 |
+
I started to wonder why masked arrays were objects, and not ndarrays,
|
| 35 |
+
and whether it wouldn't be more convenient for subclassing if they did
|
| 36 |
+
behave like regular ndarrays.
|
| 37 |
+
|
| 38 |
+
The new *maskedarray* is what I eventually come up with. The
|
| 39 |
+
main differences with the initial *numpy.core.ma* package are
|
| 40 |
+
that MaskedArray is now a subclass of *ndarray* and that the
|
| 41 |
+
*_data* section can now be any subclass of *ndarray*. Apart from a
|
| 42 |
+
couple of issues listed below, the behavior of the new MaskedArray
|
| 43 |
+
class reproduces the old one. Initially the *maskedarray*
|
| 44 |
+
implementation was marginally slower than *numpy.ma* in some areas,
|
| 45 |
+
but work is underway to speed it up; the expectation is that it can be
|
| 46 |
+
made substantially faster than the present *numpy.ma*.
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
Note that if the subclass has some special methods and
|
| 50 |
+
attributes, they are not propagated to the masked version:
|
| 51 |
+
this would require a modification of the *__getattribute__*
|
| 52 |
+
method (first trying *ndarray.__getattribute__*, then trying
|
| 53 |
+
*self._data.__getattribute__* if an exception is raised in the first
|
| 54 |
+
place), which really slows things down.
|
| 55 |
+
|
| 56 |
+
Main differences
|
| 57 |
+
----------------
|
| 58 |
+
|
| 59 |
+
* The *_data* part of the masked array can be any subclass of ndarray (but not recarray, cf below).
|
| 60 |
+
* *fill_value* is now a property, not a function.
|
| 61 |
+
* in the majority of cases, the mask is forced to *nomask* when no value is actually masked. A notable exception is when a masked array (with no masked values) has just been unpickled.
|
| 62 |
+
* I got rid of the *share_mask* flag, I never understood its purpose.
|
| 63 |
+
* *put*, *putmask* and *take* now mimic the ndarray methods, to avoid unpleasant surprises. Moreover, *put* and *putmask* both update the mask when needed. * if *a* is a masked array, *bool(a)* raises a *ValueError*, as it does with ndarrays.
|
| 64 |
+
* in the same way, the comparison of two masked arrays is a masked array, not a boolean
|
| 65 |
+
* *filled(a)* returns an array of the same subclass as *a._data*, and no test is performed on whether it is contiguous or not.
|
| 66 |
+
* the mask is always printed, even if it's *nomask*, which makes things easy (for me at least) to remember that a masked array is used.
|
| 67 |
+
* *cumsum* works as if the *_data* array was filled with 0. The mask is preserved, but not updated.
|
| 68 |
+
* *cumprod* works as if the *_data* array was filled with 1. The mask is preserved, but not updated.
|
| 69 |
+
|
| 70 |
+
New features
|
| 71 |
+
------------
|
| 72 |
+
|
| 73 |
+
This list is non-exhaustive...
|
| 74 |
+
|
| 75 |
+
* the *mr_* function mimics *r_* for masked arrays.
|
| 76 |
+
* the *anom* method returns the anomalies (deviations from the average)
|
| 77 |
+
|
| 78 |
+
Using the new package with numpy.core.ma
|
| 79 |
+
----------------------------------------
|
| 80 |
+
|
| 81 |
+
I tried to make sure that the new package can understand old masked
|
| 82 |
+
arrays. Unfortunately, there's no upward compatibility.
|
| 83 |
+
|
| 84 |
+
For example:
|
| 85 |
+
|
| 86 |
+
>>> import numpy.core.ma as old_ma
|
| 87 |
+
>>> import maskedarray as new_ma
|
| 88 |
+
>>> x = old_ma.array([1,2,3,4,5], mask=[0,0,1,0,0])
|
| 89 |
+
>>> x
|
| 90 |
+
array(data =
|
| 91 |
+
[ 1 2 999999 4 5],
|
| 92 |
+
mask =
|
| 93 |
+
[False False True False False],
|
| 94 |
+
fill_value=999999)
|
| 95 |
+
>>> y = new_ma.array([1,2,3,4,5], mask=[0,0,1,0,0])
|
| 96 |
+
>>> y
|
| 97 |
+
array(data = [1 2 -- 4 5],
|
| 98 |
+
mask = [False False True False False],
|
| 99 |
+
fill_value=999999)
|
| 100 |
+
>>> x==y
|
| 101 |
+
array(data =
|
| 102 |
+
[True True True True True],
|
| 103 |
+
mask =
|
| 104 |
+
[False False True False False],
|
| 105 |
+
fill_value=?)
|
| 106 |
+
>>> old_ma.getmask(x) == new_ma.getmask(x)
|
| 107 |
+
array([True, True, True, True, True])
|
| 108 |
+
>>> old_ma.getmask(y) == new_ma.getmask(y)
|
| 109 |
+
array([True, True, False, True, True])
|
| 110 |
+
>>> old_ma.getmask(y)
|
| 111 |
+
False
|
| 112 |
+
|
| 113 |
+
|
| 114 |
+
Using maskedarray with matplotlib
|
| 115 |
+
---------------------------------
|
| 116 |
+
|
| 117 |
+
Starting with matplotlib 0.91.2, the masked array importing will work with
|
| 118 |
+
the maskedarray branch) as well as with earlier versions.
|
| 119 |
+
|
| 120 |
+
By default matplotlib still uses numpy.ma, but there is an rcParams setting
|
| 121 |
+
that you can use to select maskedarray instead. In the matplotlibrc file
|
| 122 |
+
you will find::
|
| 123 |
+
|
| 124 |
+
#maskedarray : False # True to use external maskedarray module
|
| 125 |
+
# instead of numpy.ma; this is a temporary #
|
| 126 |
+
setting for testing maskedarray.
|
| 127 |
+
|
| 128 |
+
|
| 129 |
+
Uncomment and set to True to select maskedarray everywhere.
|
| 130 |
+
Alternatively, you can test a script with maskedarray by using a
|
| 131 |
+
command-line option, e.g.::
|
| 132 |
+
|
| 133 |
+
python simple_plot.py --maskedarray
|
| 134 |
+
|
| 135 |
+
|
| 136 |
+
Masked records
|
| 137 |
+
--------------
|
| 138 |
+
|
| 139 |
+
Like *numpy.core.ma*, the *ndarray*-based implementation
|
| 140 |
+
of MaskedArray is limited when working with records: you can
|
| 141 |
+
mask any record of the array, but not a field in a record. If you
|
| 142 |
+
need this feature, you may want to give the *mrecords* package
|
| 143 |
+
a try (available in the *maskedarray* directory in the scipy
|
| 144 |
+
sandbox). This module defines a new class, *MaskedRecord*. An
|
| 145 |
+
instance of this class accepts a *recarray* as data, and uses two
|
| 146 |
+
masks: the *fieldmask* has as many entries as records in the array,
|
| 147 |
+
each entry with the same fields as a record, but of boolean types:
|
| 148 |
+
they indicate whether the field is masked or not; a record entry
|
| 149 |
+
is flagged as masked in the *mask* array if all the fields are
|
| 150 |
+
masked. A few examples in the file should give you an idea of what
|
| 151 |
+
can be done. Note that *mrecords* is still experimental...
|
| 152 |
+
|
| 153 |
+
Optimizing maskedarray
|
| 154 |
+
----------------------
|
| 155 |
+
|
| 156 |
+
Should masked arrays be filled before processing or not?
|
| 157 |
+
--------------------------------------------------------
|
| 158 |
+
|
| 159 |
+
In the current implementation, most operations on masked arrays involve
|
| 160 |
+
the following steps:
|
| 161 |
+
|
| 162 |
+
* the input arrays are filled
|
| 163 |
+
* the operation is performed on the filled arrays
|
| 164 |
+
* the mask is set for the results, from the combination of the input masks and the mask corresponding to the domain of the operation.
|
| 165 |
+
|
| 166 |
+
For example, consider the division of two masked arrays::
|
| 167 |
+
|
| 168 |
+
import numpy
|
| 169 |
+
import maskedarray as ma
|
| 170 |
+
x = ma.array([1,2,3,4],mask=[1,0,0,0], dtype=numpy.float_)
|
| 171 |
+
y = ma.array([-1,0,1,2], mask=[0,0,0,1], dtype=numpy.float_)
|
| 172 |
+
|
| 173 |
+
The division of x by y is then computed as::
|
| 174 |
+
|
| 175 |
+
d1 = x.filled(0) # d1 = array([0., 2., 3., 4.])
|
| 176 |
+
d2 = y.filled(1) # array([-1., 0., 1., 1.])
|
| 177 |
+
m = ma.mask_or(ma.getmask(x), ma.getmask(y)) # m =
|
| 178 |
+
array([True,False,False,True])
|
| 179 |
+
dm = ma.divide.domain(d1,d2) # array([False, True, False, False])
|
| 180 |
+
result = (d1/d2).view(MaskedArray) # masked_array([-0. inf, 3., 4.])
|
| 181 |
+
result._mask = logical_or(m, dm)
|
| 182 |
+
|
| 183 |
+
Note that a division by zero takes place. To avoid it, we can consider
|
| 184 |
+
to fill the input arrays, taking the domain mask into account, so that::
|
| 185 |
+
|
| 186 |
+
d1 = x._data.copy() # d1 = array([1., 2., 3., 4.])
|
| 187 |
+
d2 = y._data.copy() # array([-1., 0., 1., 2.])
|
| 188 |
+
dm = ma.divide.domain(d1,d2) # array([False, True, False, False])
|
| 189 |
+
numpy.putmask(d2, dm, 1) # d2 = array([-1., 1., 1., 2.])
|
| 190 |
+
m = ma.mask_or(ma.getmask(x), ma.getmask(y)) # m =
|
| 191 |
+
array([True,False,False,True])
|
| 192 |
+
result = (d1/d2).view(MaskedArray) # masked_array([-1. 0., 3., 2.])
|
| 193 |
+
result._mask = logical_or(m, dm)
|
| 194 |
+
|
| 195 |
+
Note that the *.copy()* is required to avoid updating the inputs with
|
| 196 |
+
*putmask*. The *.filled()* method also involves a *.copy()*.
|
| 197 |
+
|
| 198 |
+
A third possibility consists in avoid filling the arrays::
|
| 199 |
+
|
| 200 |
+
d1 = x._data # d1 = array([1., 2., 3., 4.])
|
| 201 |
+
d2 = y._data # array([-1., 0., 1., 2.])
|
| 202 |
+
dm = ma.divide.domain(d1,d2) # array([False, True, False, False])
|
| 203 |
+
m = ma.mask_or(ma.getmask(x), ma.getmask(y)) # m =
|
| 204 |
+
array([True,False,False,True])
|
| 205 |
+
result = (d1/d2).view(MaskedArray) # masked_array([-1. inf, 3., 2.])
|
| 206 |
+
result._mask = logical_or(m, dm)
|
| 207 |
+
|
| 208 |
+
Note that here again the division by zero takes place.
|
| 209 |
+
|
| 210 |
+
A quick benchmark gives the following results:
|
| 211 |
+
|
| 212 |
+
* *numpy.ma.divide* : 2.69 ms per loop
|
| 213 |
+
* classical division : 2.21 ms per loop
|
| 214 |
+
* division w/ prefilling : 2.34 ms per loop
|
| 215 |
+
* division w/o filling : 1.55 ms per loop
|
| 216 |
+
|
| 217 |
+
So, is it worth filling the arrays beforehand ? Yes, if we are interested
|
| 218 |
+
in avoiding floating-point exceptions that may fill the result with infs
|
| 219 |
+
and nans. No, if we are only interested into speed...
|
| 220 |
+
|
| 221 |
+
|
| 222 |
+
Thanks
|
| 223 |
+
------
|
| 224 |
+
|
| 225 |
+
I'd like to thank Paul Dubois, Travis Oliphant and Sasha for the
|
| 226 |
+
original masked array package: without you, I would never have started
|
| 227 |
+
that (it might be argued that I shouldn't have anyway, but that's
|
| 228 |
+
another story...). I also wish to extend these thanks to Reggie Dugard
|
| 229 |
+
and Eric Firing for their suggestions and numerous improvements.
|
| 230 |
+
|
| 231 |
+
|
| 232 |
+
Revision notes
|
| 233 |
+
--------------
|
| 234 |
+
|
| 235 |
+
* 08/25/2007 : Creation of this page
|
| 236 |
+
* 01/23/2007 : The package has been moved to the SciPy sandbox, and is regularly updated: please check out your SVN version!
|
LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/numpy/ma/__init__.py
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
=============
|
| 3 |
+
Masked Arrays
|
| 4 |
+
=============
|
| 5 |
+
|
| 6 |
+
Arrays sometimes contain invalid or missing data. When doing operations
|
| 7 |
+
on such arrays, we wish to suppress invalid values, which is the purpose masked
|
| 8 |
+
arrays fulfill (an example of typical use is given below).
|
| 9 |
+
|
| 10 |
+
For example, examine the following array:
|
| 11 |
+
|
| 12 |
+
>>> x = np.array([2, 1, 3, np.nan, 5, 2, 3, np.nan])
|
| 13 |
+
|
| 14 |
+
When we try to calculate the mean of the data, the result is undetermined:
|
| 15 |
+
|
| 16 |
+
>>> np.mean(x)
|
| 17 |
+
nan
|
| 18 |
+
|
| 19 |
+
The mean is calculated using roughly ``np.sum(x)/len(x)``, but since
|
| 20 |
+
any number added to ``NaN`` [1]_ produces ``NaN``, this doesn't work. Enter
|
| 21 |
+
masked arrays:
|
| 22 |
+
|
| 23 |
+
>>> m = np.ma.masked_array(x, np.isnan(x))
|
| 24 |
+
>>> m
|
| 25 |
+
masked_array(data = [2.0 1.0 3.0 -- 5.0 2.0 3.0 --],
|
| 26 |
+
mask = [False False False True False False False True],
|
| 27 |
+
fill_value=1e+20)
|
| 28 |
+
|
| 29 |
+
Here, we construct a masked array that suppress all ``NaN`` values. We
|
| 30 |
+
may now proceed to calculate the mean of the other values:
|
| 31 |
+
|
| 32 |
+
>>> np.mean(m)
|
| 33 |
+
2.6666666666666665
|
| 34 |
+
|
| 35 |
+
.. [1] Not-a-Number, a floating point value that is the result of an
|
| 36 |
+
invalid operation.
|
| 37 |
+
|
| 38 |
+
.. moduleauthor:: Pierre Gerard-Marchant
|
| 39 |
+
.. moduleauthor:: Jarrod Millman
|
| 40 |
+
|
| 41 |
+
"""
|
| 42 |
+
from . import core
|
| 43 |
+
from .core import *
|
| 44 |
+
|
| 45 |
+
from . import extras
|
| 46 |
+
from .extras import *
|
| 47 |
+
|
| 48 |
+
__all__ = ['core', 'extras']
|
| 49 |
+
__all__ += core.__all__
|
| 50 |
+
__all__ += extras.__all__
|
| 51 |
+
|
| 52 |
+
from numpy._pytesttester import PytestTester
|
| 53 |
+
test = PytestTester(__name__)
|
| 54 |
+
del PytestTester
|
LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/numpy/ma/__init__.pyi
ADDED
|
@@ -0,0 +1,234 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from numpy._pytesttester import PytestTester
|
| 2 |
+
|
| 3 |
+
from numpy.ma import extras as extras
|
| 4 |
+
|
| 5 |
+
from numpy.ma.core import (
|
| 6 |
+
MAError as MAError,
|
| 7 |
+
MaskError as MaskError,
|
| 8 |
+
MaskType as MaskType,
|
| 9 |
+
MaskedArray as MaskedArray,
|
| 10 |
+
abs as abs,
|
| 11 |
+
absolute as absolute,
|
| 12 |
+
add as add,
|
| 13 |
+
all as all,
|
| 14 |
+
allclose as allclose,
|
| 15 |
+
allequal as allequal,
|
| 16 |
+
alltrue as alltrue,
|
| 17 |
+
amax as amax,
|
| 18 |
+
amin as amin,
|
| 19 |
+
angle as angle,
|
| 20 |
+
anom as anom,
|
| 21 |
+
anomalies as anomalies,
|
| 22 |
+
any as any,
|
| 23 |
+
append as append,
|
| 24 |
+
arange as arange,
|
| 25 |
+
arccos as arccos,
|
| 26 |
+
arccosh as arccosh,
|
| 27 |
+
arcsin as arcsin,
|
| 28 |
+
arcsinh as arcsinh,
|
| 29 |
+
arctan as arctan,
|
| 30 |
+
arctan2 as arctan2,
|
| 31 |
+
arctanh as arctanh,
|
| 32 |
+
argmax as argmax,
|
| 33 |
+
argmin as argmin,
|
| 34 |
+
argsort as argsort,
|
| 35 |
+
around as around,
|
| 36 |
+
array as array,
|
| 37 |
+
asanyarray as asanyarray,
|
| 38 |
+
asarray as asarray,
|
| 39 |
+
bitwise_and as bitwise_and,
|
| 40 |
+
bitwise_or as bitwise_or,
|
| 41 |
+
bitwise_xor as bitwise_xor,
|
| 42 |
+
bool_ as bool_,
|
| 43 |
+
ceil as ceil,
|
| 44 |
+
choose as choose,
|
| 45 |
+
clip as clip,
|
| 46 |
+
common_fill_value as common_fill_value,
|
| 47 |
+
compress as compress,
|
| 48 |
+
compressed as compressed,
|
| 49 |
+
concatenate as concatenate,
|
| 50 |
+
conjugate as conjugate,
|
| 51 |
+
convolve as convolve,
|
| 52 |
+
copy as copy,
|
| 53 |
+
correlate as correlate,
|
| 54 |
+
cos as cos,
|
| 55 |
+
cosh as cosh,
|
| 56 |
+
count as count,
|
| 57 |
+
cumprod as cumprod,
|
| 58 |
+
cumsum as cumsum,
|
| 59 |
+
default_fill_value as default_fill_value,
|
| 60 |
+
diag as diag,
|
| 61 |
+
diagonal as diagonal,
|
| 62 |
+
diff as diff,
|
| 63 |
+
divide as divide,
|
| 64 |
+
empty as empty,
|
| 65 |
+
empty_like as empty_like,
|
| 66 |
+
equal as equal,
|
| 67 |
+
exp as exp,
|
| 68 |
+
expand_dims as expand_dims,
|
| 69 |
+
fabs as fabs,
|
| 70 |
+
filled as filled,
|
| 71 |
+
fix_invalid as fix_invalid,
|
| 72 |
+
flatten_mask as flatten_mask,
|
| 73 |
+
flatten_structured_array as flatten_structured_array,
|
| 74 |
+
floor as floor,
|
| 75 |
+
floor_divide as floor_divide,
|
| 76 |
+
fmod as fmod,
|
| 77 |
+
frombuffer as frombuffer,
|
| 78 |
+
fromflex as fromflex,
|
| 79 |
+
fromfunction as fromfunction,
|
| 80 |
+
getdata as getdata,
|
| 81 |
+
getmask as getmask,
|
| 82 |
+
getmaskarray as getmaskarray,
|
| 83 |
+
greater as greater,
|
| 84 |
+
greater_equal as greater_equal,
|
| 85 |
+
harden_mask as harden_mask,
|
| 86 |
+
hypot as hypot,
|
| 87 |
+
identity as identity,
|
| 88 |
+
ids as ids,
|
| 89 |
+
indices as indices,
|
| 90 |
+
inner as inner,
|
| 91 |
+
innerproduct as innerproduct,
|
| 92 |
+
isMA as isMA,
|
| 93 |
+
isMaskedArray as isMaskedArray,
|
| 94 |
+
is_mask as is_mask,
|
| 95 |
+
is_masked as is_masked,
|
| 96 |
+
isarray as isarray,
|
| 97 |
+
left_shift as left_shift,
|
| 98 |
+
less as less,
|
| 99 |
+
less_equal as less_equal,
|
| 100 |
+
log as log,
|
| 101 |
+
log10 as log10,
|
| 102 |
+
log2 as log2,
|
| 103 |
+
logical_and as logical_and,
|
| 104 |
+
logical_not as logical_not,
|
| 105 |
+
logical_or as logical_or,
|
| 106 |
+
logical_xor as logical_xor,
|
| 107 |
+
make_mask as make_mask,
|
| 108 |
+
make_mask_descr as make_mask_descr,
|
| 109 |
+
make_mask_none as make_mask_none,
|
| 110 |
+
mask_or as mask_or,
|
| 111 |
+
masked as masked,
|
| 112 |
+
masked_array as masked_array,
|
| 113 |
+
masked_equal as masked_equal,
|
| 114 |
+
masked_greater as masked_greater,
|
| 115 |
+
masked_greater_equal as masked_greater_equal,
|
| 116 |
+
masked_inside as masked_inside,
|
| 117 |
+
masked_invalid as masked_invalid,
|
| 118 |
+
masked_less as masked_less,
|
| 119 |
+
masked_less_equal as masked_less_equal,
|
| 120 |
+
masked_not_equal as masked_not_equal,
|
| 121 |
+
masked_object as masked_object,
|
| 122 |
+
masked_outside as masked_outside,
|
| 123 |
+
masked_print_option as masked_print_option,
|
| 124 |
+
masked_singleton as masked_singleton,
|
| 125 |
+
masked_values as masked_values,
|
| 126 |
+
masked_where as masked_where,
|
| 127 |
+
max as max,
|
| 128 |
+
maximum as maximum,
|
| 129 |
+
maximum_fill_value as maximum_fill_value,
|
| 130 |
+
mean as mean,
|
| 131 |
+
min as min,
|
| 132 |
+
minimum as minimum,
|
| 133 |
+
minimum_fill_value as minimum_fill_value,
|
| 134 |
+
mod as mod,
|
| 135 |
+
multiply as multiply,
|
| 136 |
+
mvoid as mvoid,
|
| 137 |
+
ndim as ndim,
|
| 138 |
+
negative as negative,
|
| 139 |
+
nomask as nomask,
|
| 140 |
+
nonzero as nonzero,
|
| 141 |
+
not_equal as not_equal,
|
| 142 |
+
ones as ones,
|
| 143 |
+
outer as outer,
|
| 144 |
+
outerproduct as outerproduct,
|
| 145 |
+
power as power,
|
| 146 |
+
prod as prod,
|
| 147 |
+
product as product,
|
| 148 |
+
ptp as ptp,
|
| 149 |
+
put as put,
|
| 150 |
+
putmask as putmask,
|
| 151 |
+
ravel as ravel,
|
| 152 |
+
remainder as remainder,
|
| 153 |
+
repeat as repeat,
|
| 154 |
+
reshape as reshape,
|
| 155 |
+
resize as resize,
|
| 156 |
+
right_shift as right_shift,
|
| 157 |
+
round as round,
|
| 158 |
+
set_fill_value as set_fill_value,
|
| 159 |
+
shape as shape,
|
| 160 |
+
sin as sin,
|
| 161 |
+
sinh as sinh,
|
| 162 |
+
size as size,
|
| 163 |
+
soften_mask as soften_mask,
|
| 164 |
+
sometrue as sometrue,
|
| 165 |
+
sort as sort,
|
| 166 |
+
sqrt as sqrt,
|
| 167 |
+
squeeze as squeeze,
|
| 168 |
+
std as std,
|
| 169 |
+
subtract as subtract,
|
| 170 |
+
sum as sum,
|
| 171 |
+
swapaxes as swapaxes,
|
| 172 |
+
take as take,
|
| 173 |
+
tan as tan,
|
| 174 |
+
tanh as tanh,
|
| 175 |
+
trace as trace,
|
| 176 |
+
transpose as transpose,
|
| 177 |
+
true_divide as true_divide,
|
| 178 |
+
var as var,
|
| 179 |
+
where as where,
|
| 180 |
+
zeros as zeros,
|
| 181 |
+
)
|
| 182 |
+
|
| 183 |
+
from numpy.ma.extras import (
|
| 184 |
+
apply_along_axis as apply_along_axis,
|
| 185 |
+
apply_over_axes as apply_over_axes,
|
| 186 |
+
atleast_1d as atleast_1d,
|
| 187 |
+
atleast_2d as atleast_2d,
|
| 188 |
+
atleast_3d as atleast_3d,
|
| 189 |
+
average as average,
|
| 190 |
+
clump_masked as clump_masked,
|
| 191 |
+
clump_unmasked as clump_unmasked,
|
| 192 |
+
column_stack as column_stack,
|
| 193 |
+
compress_cols as compress_cols,
|
| 194 |
+
compress_nd as compress_nd,
|
| 195 |
+
compress_rowcols as compress_rowcols,
|
| 196 |
+
compress_rows as compress_rows,
|
| 197 |
+
count_masked as count_masked,
|
| 198 |
+
corrcoef as corrcoef,
|
| 199 |
+
cov as cov,
|
| 200 |
+
diagflat as diagflat,
|
| 201 |
+
dot as dot,
|
| 202 |
+
dstack as dstack,
|
| 203 |
+
ediff1d as ediff1d,
|
| 204 |
+
flatnotmasked_contiguous as flatnotmasked_contiguous,
|
| 205 |
+
flatnotmasked_edges as flatnotmasked_edges,
|
| 206 |
+
hsplit as hsplit,
|
| 207 |
+
hstack as hstack,
|
| 208 |
+
isin as isin,
|
| 209 |
+
in1d as in1d,
|
| 210 |
+
intersect1d as intersect1d,
|
| 211 |
+
mask_cols as mask_cols,
|
| 212 |
+
mask_rowcols as mask_rowcols,
|
| 213 |
+
mask_rows as mask_rows,
|
| 214 |
+
masked_all as masked_all,
|
| 215 |
+
masked_all_like as masked_all_like,
|
| 216 |
+
median as median,
|
| 217 |
+
mr_ as mr_,
|
| 218 |
+
ndenumerate as ndenumerate,
|
| 219 |
+
notmasked_contiguous as notmasked_contiguous,
|
| 220 |
+
notmasked_edges as notmasked_edges,
|
| 221 |
+
polyfit as polyfit,
|
| 222 |
+
row_stack as row_stack,
|
| 223 |
+
setdiff1d as setdiff1d,
|
| 224 |
+
setxor1d as setxor1d,
|
| 225 |
+
stack as stack,
|
| 226 |
+
unique as unique,
|
| 227 |
+
union1d as union1d,
|
| 228 |
+
vander as vander,
|
| 229 |
+
vstack as vstack,
|
| 230 |
+
)
|
| 231 |
+
|
| 232 |
+
__all__: list[str]
|
| 233 |
+
__path__: list[str]
|
| 234 |
+
test: PytestTester
|
LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/numpy/ma/core.py
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/numpy/ma/core.pyi
ADDED
|
@@ -0,0 +1,471 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from collections.abc import Callable
|
| 2 |
+
from typing import Any, TypeVar
|
| 3 |
+
from numpy import ndarray, dtype, float64
|
| 4 |
+
|
| 5 |
+
from numpy import (
|
| 6 |
+
amax as amax,
|
| 7 |
+
amin as amin,
|
| 8 |
+
bool_ as bool_,
|
| 9 |
+
expand_dims as expand_dims,
|
| 10 |
+
clip as clip,
|
| 11 |
+
indices as indices,
|
| 12 |
+
ones_like as ones_like,
|
| 13 |
+
squeeze as squeeze,
|
| 14 |
+
zeros_like as zeros_like,
|
| 15 |
+
)
|
| 16 |
+
|
| 17 |
+
from numpy.lib.function_base import (
|
| 18 |
+
angle as angle,
|
| 19 |
+
)
|
| 20 |
+
|
| 21 |
+
# TODO: Set the `bound` to something more suitable once we
|
| 22 |
+
# have proper shape support
|
| 23 |
+
_ShapeType = TypeVar("_ShapeType", bound=Any)
|
| 24 |
+
_DType_co = TypeVar("_DType_co", bound=dtype[Any], covariant=True)
|
| 25 |
+
|
| 26 |
+
__all__: list[str]
|
| 27 |
+
|
| 28 |
+
MaskType = bool_
|
| 29 |
+
nomask: bool_
|
| 30 |
+
|
| 31 |
+
class MaskedArrayFutureWarning(FutureWarning): ...
|
| 32 |
+
class MAError(Exception): ...
|
| 33 |
+
class MaskError(MAError): ...
|
| 34 |
+
|
| 35 |
+
def default_fill_value(obj): ...
|
| 36 |
+
def minimum_fill_value(obj): ...
|
| 37 |
+
def maximum_fill_value(obj): ...
|
| 38 |
+
def set_fill_value(a, fill_value): ...
|
| 39 |
+
def common_fill_value(a, b): ...
|
| 40 |
+
def filled(a, fill_value=...): ...
|
| 41 |
+
def getdata(a, subok=...): ...
|
| 42 |
+
get_data = getdata
|
| 43 |
+
|
| 44 |
+
def fix_invalid(a, mask=..., copy=..., fill_value=...): ...
|
| 45 |
+
|
| 46 |
+
class _MaskedUFunc:
|
| 47 |
+
f: Any
|
| 48 |
+
__doc__: Any
|
| 49 |
+
__name__: Any
|
| 50 |
+
def __init__(self, ufunc): ...
|
| 51 |
+
|
| 52 |
+
class _MaskedUnaryOperation(_MaskedUFunc):
|
| 53 |
+
fill: Any
|
| 54 |
+
domain: Any
|
| 55 |
+
def __init__(self, mufunc, fill=..., domain=...): ...
|
| 56 |
+
def __call__(self, a, *args, **kwargs): ...
|
| 57 |
+
|
| 58 |
+
class _MaskedBinaryOperation(_MaskedUFunc):
|
| 59 |
+
fillx: Any
|
| 60 |
+
filly: Any
|
| 61 |
+
def __init__(self, mbfunc, fillx=..., filly=...): ...
|
| 62 |
+
def __call__(self, a, b, *args, **kwargs): ...
|
| 63 |
+
def reduce(self, target, axis=..., dtype=...): ...
|
| 64 |
+
def outer(self, a, b): ...
|
| 65 |
+
def accumulate(self, target, axis=...): ...
|
| 66 |
+
|
| 67 |
+
class _DomainedBinaryOperation(_MaskedUFunc):
|
| 68 |
+
domain: Any
|
| 69 |
+
fillx: Any
|
| 70 |
+
filly: Any
|
| 71 |
+
def __init__(self, dbfunc, domain, fillx=..., filly=...): ...
|
| 72 |
+
def __call__(self, a, b, *args, **kwargs): ...
|
| 73 |
+
|
| 74 |
+
exp: _MaskedUnaryOperation
|
| 75 |
+
conjugate: _MaskedUnaryOperation
|
| 76 |
+
sin: _MaskedUnaryOperation
|
| 77 |
+
cos: _MaskedUnaryOperation
|
| 78 |
+
arctan: _MaskedUnaryOperation
|
| 79 |
+
arcsinh: _MaskedUnaryOperation
|
| 80 |
+
sinh: _MaskedUnaryOperation
|
| 81 |
+
cosh: _MaskedUnaryOperation
|
| 82 |
+
tanh: _MaskedUnaryOperation
|
| 83 |
+
abs: _MaskedUnaryOperation
|
| 84 |
+
absolute: _MaskedUnaryOperation
|
| 85 |
+
fabs: _MaskedUnaryOperation
|
| 86 |
+
negative: _MaskedUnaryOperation
|
| 87 |
+
floor: _MaskedUnaryOperation
|
| 88 |
+
ceil: _MaskedUnaryOperation
|
| 89 |
+
around: _MaskedUnaryOperation
|
| 90 |
+
logical_not: _MaskedUnaryOperation
|
| 91 |
+
sqrt: _MaskedUnaryOperation
|
| 92 |
+
log: _MaskedUnaryOperation
|
| 93 |
+
log2: _MaskedUnaryOperation
|
| 94 |
+
log10: _MaskedUnaryOperation
|
| 95 |
+
tan: _MaskedUnaryOperation
|
| 96 |
+
arcsin: _MaskedUnaryOperation
|
| 97 |
+
arccos: _MaskedUnaryOperation
|
| 98 |
+
arccosh: _MaskedUnaryOperation
|
| 99 |
+
arctanh: _MaskedUnaryOperation
|
| 100 |
+
|
| 101 |
+
add: _MaskedBinaryOperation
|
| 102 |
+
subtract: _MaskedBinaryOperation
|
| 103 |
+
multiply: _MaskedBinaryOperation
|
| 104 |
+
arctan2: _MaskedBinaryOperation
|
| 105 |
+
equal: _MaskedBinaryOperation
|
| 106 |
+
not_equal: _MaskedBinaryOperation
|
| 107 |
+
less_equal: _MaskedBinaryOperation
|
| 108 |
+
greater_equal: _MaskedBinaryOperation
|
| 109 |
+
less: _MaskedBinaryOperation
|
| 110 |
+
greater: _MaskedBinaryOperation
|
| 111 |
+
logical_and: _MaskedBinaryOperation
|
| 112 |
+
alltrue: _MaskedBinaryOperation
|
| 113 |
+
logical_or: _MaskedBinaryOperation
|
| 114 |
+
sometrue: Callable[..., Any]
|
| 115 |
+
logical_xor: _MaskedBinaryOperation
|
| 116 |
+
bitwise_and: _MaskedBinaryOperation
|
| 117 |
+
bitwise_or: _MaskedBinaryOperation
|
| 118 |
+
bitwise_xor: _MaskedBinaryOperation
|
| 119 |
+
hypot: _MaskedBinaryOperation
|
| 120 |
+
divide: _MaskedBinaryOperation
|
| 121 |
+
true_divide: _MaskedBinaryOperation
|
| 122 |
+
floor_divide: _MaskedBinaryOperation
|
| 123 |
+
remainder: _MaskedBinaryOperation
|
| 124 |
+
fmod: _MaskedBinaryOperation
|
| 125 |
+
mod: _MaskedBinaryOperation
|
| 126 |
+
|
| 127 |
+
def make_mask_descr(ndtype): ...
|
| 128 |
+
def getmask(a): ...
|
| 129 |
+
get_mask = getmask
|
| 130 |
+
|
| 131 |
+
def getmaskarray(arr): ...
|
| 132 |
+
def is_mask(m): ...
|
| 133 |
+
def make_mask(m, copy=..., shrink=..., dtype=...): ...
|
| 134 |
+
def make_mask_none(newshape, dtype=...): ...
|
| 135 |
+
def mask_or(m1, m2, copy=..., shrink=...): ...
|
| 136 |
+
def flatten_mask(mask): ...
|
| 137 |
+
def masked_where(condition, a, copy=...): ...
|
| 138 |
+
def masked_greater(x, value, copy=...): ...
|
| 139 |
+
def masked_greater_equal(x, value, copy=...): ...
|
| 140 |
+
def masked_less(x, value, copy=...): ...
|
| 141 |
+
def masked_less_equal(x, value, copy=...): ...
|
| 142 |
+
def masked_not_equal(x, value, copy=...): ...
|
| 143 |
+
def masked_equal(x, value, copy=...): ...
|
| 144 |
+
def masked_inside(x, v1, v2, copy=...): ...
|
| 145 |
+
def masked_outside(x, v1, v2, copy=...): ...
|
| 146 |
+
def masked_object(x, value, copy=..., shrink=...): ...
|
| 147 |
+
def masked_values(x, value, rtol=..., atol=..., copy=..., shrink=...): ...
|
| 148 |
+
def masked_invalid(a, copy=...): ...
|
| 149 |
+
|
| 150 |
+
class _MaskedPrintOption:
|
| 151 |
+
def __init__(self, display): ...
|
| 152 |
+
def display(self): ...
|
| 153 |
+
def set_display(self, s): ...
|
| 154 |
+
def enabled(self): ...
|
| 155 |
+
def enable(self, shrink=...): ...
|
| 156 |
+
|
| 157 |
+
masked_print_option: _MaskedPrintOption
|
| 158 |
+
|
| 159 |
+
def flatten_structured_array(a): ...
|
| 160 |
+
|
| 161 |
+
class MaskedIterator:
|
| 162 |
+
ma: Any
|
| 163 |
+
dataiter: Any
|
| 164 |
+
maskiter: Any
|
| 165 |
+
def __init__(self, ma): ...
|
| 166 |
+
def __iter__(self): ...
|
| 167 |
+
def __getitem__(self, indx): ...
|
| 168 |
+
def __setitem__(self, index, value): ...
|
| 169 |
+
def __next__(self): ...
|
| 170 |
+
|
| 171 |
+
class MaskedArray(ndarray[_ShapeType, _DType_co]):
|
| 172 |
+
__array_priority__: Any
|
| 173 |
+
def __new__(cls, data=..., mask=..., dtype=..., copy=..., subok=..., ndmin=..., fill_value=..., keep_mask=..., hard_mask=..., shrink=..., order=...): ...
|
| 174 |
+
def __array_finalize__(self, obj): ...
|
| 175 |
+
def __array_wrap__(self, obj, context=...): ...
|
| 176 |
+
def view(self, dtype=..., type=..., fill_value=...): ...
|
| 177 |
+
def __getitem__(self, indx): ...
|
| 178 |
+
def __setitem__(self, indx, value): ...
|
| 179 |
+
@property
|
| 180 |
+
def dtype(self): ...
|
| 181 |
+
@dtype.setter
|
| 182 |
+
def dtype(self, dtype): ...
|
| 183 |
+
@property
|
| 184 |
+
def shape(self): ...
|
| 185 |
+
@shape.setter
|
| 186 |
+
def shape(self, shape): ...
|
| 187 |
+
def __setmask__(self, mask, copy=...): ...
|
| 188 |
+
@property
|
| 189 |
+
def mask(self): ...
|
| 190 |
+
@mask.setter
|
| 191 |
+
def mask(self, value): ...
|
| 192 |
+
@property
|
| 193 |
+
def recordmask(self): ...
|
| 194 |
+
@recordmask.setter
|
| 195 |
+
def recordmask(self, mask): ...
|
| 196 |
+
def harden_mask(self): ...
|
| 197 |
+
def soften_mask(self): ...
|
| 198 |
+
@property
|
| 199 |
+
def hardmask(self): ...
|
| 200 |
+
def unshare_mask(self): ...
|
| 201 |
+
@property
|
| 202 |
+
def sharedmask(self): ...
|
| 203 |
+
def shrink_mask(self): ...
|
| 204 |
+
@property
|
| 205 |
+
def baseclass(self): ...
|
| 206 |
+
data: Any
|
| 207 |
+
@property
|
| 208 |
+
def flat(self): ...
|
| 209 |
+
@flat.setter
|
| 210 |
+
def flat(self, value): ...
|
| 211 |
+
@property
|
| 212 |
+
def fill_value(self): ...
|
| 213 |
+
@fill_value.setter
|
| 214 |
+
def fill_value(self, value=...): ...
|
| 215 |
+
get_fill_value: Any
|
| 216 |
+
set_fill_value: Any
|
| 217 |
+
def filled(self, fill_value=...): ...
|
| 218 |
+
def compressed(self): ...
|
| 219 |
+
def compress(self, condition, axis=..., out=...): ...
|
| 220 |
+
def __eq__(self, other): ...
|
| 221 |
+
def __ne__(self, other): ...
|
| 222 |
+
def __ge__(self, other): ...
|
| 223 |
+
def __gt__(self, other): ...
|
| 224 |
+
def __le__(self, other): ...
|
| 225 |
+
def __lt__(self, other): ...
|
| 226 |
+
def __add__(self, other): ...
|
| 227 |
+
def __radd__(self, other): ...
|
| 228 |
+
def __sub__(self, other): ...
|
| 229 |
+
def __rsub__(self, other): ...
|
| 230 |
+
def __mul__(self, other): ...
|
| 231 |
+
def __rmul__(self, other): ...
|
| 232 |
+
def __div__(self, other): ...
|
| 233 |
+
def __truediv__(self, other): ...
|
| 234 |
+
def __rtruediv__(self, other): ...
|
| 235 |
+
def __floordiv__(self, other): ...
|
| 236 |
+
def __rfloordiv__(self, other): ...
|
| 237 |
+
def __pow__(self, other): ...
|
| 238 |
+
def __rpow__(self, other): ...
|
| 239 |
+
def __iadd__(self, other): ...
|
| 240 |
+
def __isub__(self, other): ...
|
| 241 |
+
def __imul__(self, other): ...
|
| 242 |
+
def __idiv__(self, other): ...
|
| 243 |
+
def __ifloordiv__(self, other): ...
|
| 244 |
+
def __itruediv__(self, other): ...
|
| 245 |
+
def __ipow__(self, other): ...
|
| 246 |
+
def __float__(self): ...
|
| 247 |
+
def __int__(self): ...
|
| 248 |
+
@property # type: ignore[misc]
|
| 249 |
+
def imag(self): ...
|
| 250 |
+
get_imag: Any
|
| 251 |
+
@property # type: ignore[misc]
|
| 252 |
+
def real(self): ...
|
| 253 |
+
get_real: Any
|
| 254 |
+
def count(self, axis=..., keepdims=...): ...
|
| 255 |
+
def ravel(self, order=...): ...
|
| 256 |
+
def reshape(self, *s, **kwargs): ...
|
| 257 |
+
def resize(self, newshape, refcheck=..., order=...): ...
|
| 258 |
+
def put(self, indices, values, mode=...): ...
|
| 259 |
+
def ids(self): ...
|
| 260 |
+
def iscontiguous(self): ...
|
| 261 |
+
def all(self, axis=..., out=..., keepdims=...): ...
|
| 262 |
+
def any(self, axis=..., out=..., keepdims=...): ...
|
| 263 |
+
def nonzero(self): ...
|
| 264 |
+
def trace(self, offset=..., axis1=..., axis2=..., dtype=..., out=...): ...
|
| 265 |
+
def dot(self, b, out=..., strict=...): ...
|
| 266 |
+
def sum(self, axis=..., dtype=..., out=..., keepdims=...): ...
|
| 267 |
+
def cumsum(self, axis=..., dtype=..., out=...): ...
|
| 268 |
+
def prod(self, axis=..., dtype=..., out=..., keepdims=...): ...
|
| 269 |
+
product: Any
|
| 270 |
+
def cumprod(self, axis=..., dtype=..., out=...): ...
|
| 271 |
+
def mean(self, axis=..., dtype=..., out=..., keepdims=...): ...
|
| 272 |
+
def anom(self, axis=..., dtype=...): ...
|
| 273 |
+
def var(self, axis=..., dtype=..., out=..., ddof=..., keepdims=...): ...
|
| 274 |
+
def std(self, axis=..., dtype=..., out=..., ddof=..., keepdims=...): ...
|
| 275 |
+
def round(self, decimals=..., out=...): ...
|
| 276 |
+
def argsort(self, axis=..., kind=..., order=..., endwith=..., fill_value=...): ...
|
| 277 |
+
def argmin(self, axis=..., fill_value=..., out=..., *, keepdims=...): ...
|
| 278 |
+
def argmax(self, axis=..., fill_value=..., out=..., *, keepdims=...): ...
|
| 279 |
+
def sort(self, axis=..., kind=..., order=..., endwith=..., fill_value=...): ...
|
| 280 |
+
def min(self, axis=..., out=..., fill_value=..., keepdims=...): ...
|
| 281 |
+
# NOTE: deprecated
|
| 282 |
+
# def tostring(self, fill_value=..., order=...): ...
|
| 283 |
+
def max(self, axis=..., out=..., fill_value=..., keepdims=...): ...
|
| 284 |
+
def ptp(self, axis=..., out=..., fill_value=..., keepdims=...): ...
|
| 285 |
+
def partition(self, *args, **kwargs): ...
|
| 286 |
+
def argpartition(self, *args, **kwargs): ...
|
| 287 |
+
def take(self, indices, axis=..., out=..., mode=...): ...
|
| 288 |
+
copy: Any
|
| 289 |
+
diagonal: Any
|
| 290 |
+
flatten: Any
|
| 291 |
+
repeat: Any
|
| 292 |
+
squeeze: Any
|
| 293 |
+
swapaxes: Any
|
| 294 |
+
T: Any
|
| 295 |
+
transpose: Any
|
| 296 |
+
def tolist(self, fill_value=...): ...
|
| 297 |
+
def tobytes(self, fill_value=..., order=...): ...
|
| 298 |
+
def tofile(self, fid, sep=..., format=...): ...
|
| 299 |
+
def toflex(self): ...
|
| 300 |
+
torecords: Any
|
| 301 |
+
def __reduce__(self): ...
|
| 302 |
+
def __deepcopy__(self, memo=...): ...
|
| 303 |
+
|
| 304 |
+
class mvoid(MaskedArray[_ShapeType, _DType_co]):
|
| 305 |
+
def __new__(
|
| 306 |
+
self,
|
| 307 |
+
data,
|
| 308 |
+
mask=...,
|
| 309 |
+
dtype=...,
|
| 310 |
+
fill_value=...,
|
| 311 |
+
hardmask=...,
|
| 312 |
+
copy=...,
|
| 313 |
+
subok=...,
|
| 314 |
+
): ...
|
| 315 |
+
def __getitem__(self, indx): ...
|
| 316 |
+
def __setitem__(self, indx, value): ...
|
| 317 |
+
def __iter__(self): ...
|
| 318 |
+
def __len__(self): ...
|
| 319 |
+
def filled(self, fill_value=...): ...
|
| 320 |
+
def tolist(self): ...
|
| 321 |
+
|
| 322 |
+
def isMaskedArray(x): ...
|
| 323 |
+
isarray = isMaskedArray
|
| 324 |
+
isMA = isMaskedArray
|
| 325 |
+
|
| 326 |
+
# 0D float64 array
|
| 327 |
+
class MaskedConstant(MaskedArray[Any, dtype[float64]]):
|
| 328 |
+
def __new__(cls): ...
|
| 329 |
+
__class__: Any
|
| 330 |
+
def __array_finalize__(self, obj): ...
|
| 331 |
+
def __array_prepare__(self, obj, context=...): ...
|
| 332 |
+
def __array_wrap__(self, obj, context=...): ...
|
| 333 |
+
def __format__(self, format_spec): ...
|
| 334 |
+
def __reduce__(self): ...
|
| 335 |
+
def __iop__(self, other): ...
|
| 336 |
+
__iadd__: Any
|
| 337 |
+
__isub__: Any
|
| 338 |
+
__imul__: Any
|
| 339 |
+
__ifloordiv__: Any
|
| 340 |
+
__itruediv__: Any
|
| 341 |
+
__ipow__: Any
|
| 342 |
+
def copy(self, *args, **kwargs): ...
|
| 343 |
+
def __copy__(self): ...
|
| 344 |
+
def __deepcopy__(self, memo): ...
|
| 345 |
+
def __setattr__(self, attr, value): ...
|
| 346 |
+
|
| 347 |
+
masked: MaskedConstant
|
| 348 |
+
masked_singleton: MaskedConstant
|
| 349 |
+
masked_array = MaskedArray
|
| 350 |
+
|
| 351 |
+
def array(
|
| 352 |
+
data,
|
| 353 |
+
dtype=...,
|
| 354 |
+
copy=...,
|
| 355 |
+
order=...,
|
| 356 |
+
mask=...,
|
| 357 |
+
fill_value=...,
|
| 358 |
+
keep_mask=...,
|
| 359 |
+
hard_mask=...,
|
| 360 |
+
shrink=...,
|
| 361 |
+
subok=...,
|
| 362 |
+
ndmin=...,
|
| 363 |
+
): ...
|
| 364 |
+
def is_masked(x): ...
|
| 365 |
+
|
| 366 |
+
class _extrema_operation(_MaskedUFunc):
|
| 367 |
+
compare: Any
|
| 368 |
+
fill_value_func: Any
|
| 369 |
+
def __init__(self, ufunc, compare, fill_value): ...
|
| 370 |
+
# NOTE: in practice `b` has a default value, but users should
|
| 371 |
+
# explicitly provide a value here as the default is deprecated
|
| 372 |
+
def __call__(self, a, b): ...
|
| 373 |
+
def reduce(self, target, axis=...): ...
|
| 374 |
+
def outer(self, a, b): ...
|
| 375 |
+
|
| 376 |
+
def min(obj, axis=..., out=..., fill_value=..., keepdims=...): ...
|
| 377 |
+
def max(obj, axis=..., out=..., fill_value=..., keepdims=...): ...
|
| 378 |
+
def ptp(obj, axis=..., out=..., fill_value=..., keepdims=...): ...
|
| 379 |
+
|
| 380 |
+
class _frommethod:
|
| 381 |
+
__name__: Any
|
| 382 |
+
__doc__: Any
|
| 383 |
+
reversed: Any
|
| 384 |
+
def __init__(self, methodname, reversed=...): ...
|
| 385 |
+
def getdoc(self): ...
|
| 386 |
+
def __call__(self, a, *args, **params): ...
|
| 387 |
+
|
| 388 |
+
all: _frommethod
|
| 389 |
+
anomalies: _frommethod
|
| 390 |
+
anom: _frommethod
|
| 391 |
+
any: _frommethod
|
| 392 |
+
compress: _frommethod
|
| 393 |
+
cumprod: _frommethod
|
| 394 |
+
cumsum: _frommethod
|
| 395 |
+
copy: _frommethod
|
| 396 |
+
diagonal: _frommethod
|
| 397 |
+
harden_mask: _frommethod
|
| 398 |
+
ids: _frommethod
|
| 399 |
+
mean: _frommethod
|
| 400 |
+
nonzero: _frommethod
|
| 401 |
+
prod: _frommethod
|
| 402 |
+
product: _frommethod
|
| 403 |
+
ravel: _frommethod
|
| 404 |
+
repeat: _frommethod
|
| 405 |
+
soften_mask: _frommethod
|
| 406 |
+
std: _frommethod
|
| 407 |
+
sum: _frommethod
|
| 408 |
+
swapaxes: _frommethod
|
| 409 |
+
trace: _frommethod
|
| 410 |
+
var: _frommethod
|
| 411 |
+
count: _frommethod
|
| 412 |
+
argmin: _frommethod
|
| 413 |
+
argmax: _frommethod
|
| 414 |
+
|
| 415 |
+
minimum: _extrema_operation
|
| 416 |
+
maximum: _extrema_operation
|
| 417 |
+
|
| 418 |
+
def take(a, indices, axis=..., out=..., mode=...): ...
|
| 419 |
+
def power(a, b, third=...): ...
|
| 420 |
+
def argsort(a, axis=..., kind=..., order=..., endwith=..., fill_value=...): ...
|
| 421 |
+
def sort(a, axis=..., kind=..., order=..., endwith=..., fill_value=...): ...
|
| 422 |
+
def compressed(x): ...
|
| 423 |
+
def concatenate(arrays, axis=...): ...
|
| 424 |
+
def diag(v, k=...): ...
|
| 425 |
+
def left_shift(a, n): ...
|
| 426 |
+
def right_shift(a, n): ...
|
| 427 |
+
def put(a, indices, values, mode=...): ...
|
| 428 |
+
def putmask(a, mask, values): ...
|
| 429 |
+
def transpose(a, axes=...): ...
|
| 430 |
+
def reshape(a, new_shape, order=...): ...
|
| 431 |
+
def resize(x, new_shape): ...
|
| 432 |
+
def ndim(obj): ...
|
| 433 |
+
def shape(obj): ...
|
| 434 |
+
def size(obj, axis=...): ...
|
| 435 |
+
def diff(a, /, n=..., axis=..., prepend=..., append=...): ...
|
| 436 |
+
def where(condition, x=..., y=...): ...
|
| 437 |
+
def choose(indices, choices, out=..., mode=...): ...
|
| 438 |
+
def round(a, decimals=..., out=...): ...
|
| 439 |
+
|
| 440 |
+
def inner(a, b): ...
|
| 441 |
+
innerproduct = inner
|
| 442 |
+
|
| 443 |
+
def outer(a, b): ...
|
| 444 |
+
outerproduct = outer
|
| 445 |
+
|
| 446 |
+
def correlate(a, v, mode=..., propagate_mask=...): ...
|
| 447 |
+
def convolve(a, v, mode=..., propagate_mask=...): ...
|
| 448 |
+
def allequal(a, b, fill_value=...): ...
|
| 449 |
+
def allclose(a, b, masked_equal=..., rtol=..., atol=...): ...
|
| 450 |
+
def asarray(a, dtype=..., order=...): ...
|
| 451 |
+
def asanyarray(a, dtype=...): ...
|
| 452 |
+
def fromflex(fxarray): ...
|
| 453 |
+
|
| 454 |
+
class _convert2ma:
|
| 455 |
+
__doc__: Any
|
| 456 |
+
def __init__(self, funcname, params=...): ...
|
| 457 |
+
def getdoc(self): ...
|
| 458 |
+
def __call__(self, *args, **params): ...
|
| 459 |
+
|
| 460 |
+
arange: _convert2ma
|
| 461 |
+
empty: _convert2ma
|
| 462 |
+
empty_like: _convert2ma
|
| 463 |
+
frombuffer: _convert2ma
|
| 464 |
+
fromfunction: _convert2ma
|
| 465 |
+
identity: _convert2ma
|
| 466 |
+
ones: _convert2ma
|
| 467 |
+
zeros: _convert2ma
|
| 468 |
+
|
| 469 |
+
def append(a, b, axis=...): ...
|
| 470 |
+
def dot(a, b, strict=..., out=...): ...
|
| 471 |
+
def mask_rowcols(a, axis=...): ...
|
LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/numpy/ma/extras.py
ADDED
|
@@ -0,0 +1,2133 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Masked arrays add-ons.
|
| 3 |
+
|
| 4 |
+
A collection of utilities for `numpy.ma`.
|
| 5 |
+
|
| 6 |
+
:author: Pierre Gerard-Marchant
|
| 7 |
+
:contact: pierregm_at_uga_dot_edu
|
| 8 |
+
:version: $Id: extras.py 3473 2007-10-29 15:18:13Z jarrod.millman $
|
| 9 |
+
|
| 10 |
+
"""
|
| 11 |
+
__all__ = [
|
| 12 |
+
'apply_along_axis', 'apply_over_axes', 'atleast_1d', 'atleast_2d',
|
| 13 |
+
'atleast_3d', 'average', 'clump_masked', 'clump_unmasked', 'column_stack',
|
| 14 |
+
'compress_cols', 'compress_nd', 'compress_rowcols', 'compress_rows',
|
| 15 |
+
'count_masked', 'corrcoef', 'cov', 'diagflat', 'dot', 'dstack', 'ediff1d',
|
| 16 |
+
'flatnotmasked_contiguous', 'flatnotmasked_edges', 'hsplit', 'hstack',
|
| 17 |
+
'isin', 'in1d', 'intersect1d', 'mask_cols', 'mask_rowcols', 'mask_rows',
|
| 18 |
+
'masked_all', 'masked_all_like', 'median', 'mr_', 'ndenumerate',
|
| 19 |
+
'notmasked_contiguous', 'notmasked_edges', 'polyfit', 'row_stack',
|
| 20 |
+
'setdiff1d', 'setxor1d', 'stack', 'unique', 'union1d', 'vander', 'vstack',
|
| 21 |
+
]
|
| 22 |
+
|
| 23 |
+
import itertools
|
| 24 |
+
import warnings
|
| 25 |
+
|
| 26 |
+
from . import core as ma
|
| 27 |
+
from .core import (
|
| 28 |
+
MaskedArray, MAError, add, array, asarray, concatenate, filled, count,
|
| 29 |
+
getmask, getmaskarray, make_mask_descr, masked, masked_array, mask_or,
|
| 30 |
+
nomask, ones, sort, zeros, getdata, get_masked_subclass, dot
|
| 31 |
+
)
|
| 32 |
+
|
| 33 |
+
import numpy as np
|
| 34 |
+
from numpy import ndarray, array as nxarray
|
| 35 |
+
from numpy.core.multiarray import normalize_axis_index
|
| 36 |
+
from numpy.core.numeric import normalize_axis_tuple
|
| 37 |
+
from numpy.lib.function_base import _ureduce
|
| 38 |
+
from numpy.lib.index_tricks import AxisConcatenator
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
def issequence(seq):
|
| 42 |
+
"""
|
| 43 |
+
Is seq a sequence (ndarray, list or tuple)?
|
| 44 |
+
|
| 45 |
+
"""
|
| 46 |
+
return isinstance(seq, (ndarray, tuple, list))
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
def count_masked(arr, axis=None):
|
| 50 |
+
"""
|
| 51 |
+
Count the number of masked elements along the given axis.
|
| 52 |
+
|
| 53 |
+
Parameters
|
| 54 |
+
----------
|
| 55 |
+
arr : array_like
|
| 56 |
+
An array with (possibly) masked elements.
|
| 57 |
+
axis : int, optional
|
| 58 |
+
Axis along which to count. If None (default), a flattened
|
| 59 |
+
version of the array is used.
|
| 60 |
+
|
| 61 |
+
Returns
|
| 62 |
+
-------
|
| 63 |
+
count : int, ndarray
|
| 64 |
+
The total number of masked elements (axis=None) or the number
|
| 65 |
+
of masked elements along each slice of the given axis.
|
| 66 |
+
|
| 67 |
+
See Also
|
| 68 |
+
--------
|
| 69 |
+
MaskedArray.count : Count non-masked elements.
|
| 70 |
+
|
| 71 |
+
Examples
|
| 72 |
+
--------
|
| 73 |
+
>>> import numpy.ma as ma
|
| 74 |
+
>>> a = np.arange(9).reshape((3,3))
|
| 75 |
+
>>> a = ma.array(a)
|
| 76 |
+
>>> a[1, 0] = ma.masked
|
| 77 |
+
>>> a[1, 2] = ma.masked
|
| 78 |
+
>>> a[2, 1] = ma.masked
|
| 79 |
+
>>> a
|
| 80 |
+
masked_array(
|
| 81 |
+
data=[[0, 1, 2],
|
| 82 |
+
[--, 4, --],
|
| 83 |
+
[6, --, 8]],
|
| 84 |
+
mask=[[False, False, False],
|
| 85 |
+
[ True, False, True],
|
| 86 |
+
[False, True, False]],
|
| 87 |
+
fill_value=999999)
|
| 88 |
+
>>> ma.count_masked(a)
|
| 89 |
+
3
|
| 90 |
+
|
| 91 |
+
When the `axis` keyword is used an array is returned.
|
| 92 |
+
|
| 93 |
+
>>> ma.count_masked(a, axis=0)
|
| 94 |
+
array([1, 1, 1])
|
| 95 |
+
>>> ma.count_masked(a, axis=1)
|
| 96 |
+
array([0, 2, 1])
|
| 97 |
+
|
| 98 |
+
"""
|
| 99 |
+
m = getmaskarray(arr)
|
| 100 |
+
return m.sum(axis)
|
| 101 |
+
|
| 102 |
+
|
| 103 |
+
def masked_all(shape, dtype=float):
|
| 104 |
+
"""
|
| 105 |
+
Empty masked array with all elements masked.
|
| 106 |
+
|
| 107 |
+
Return an empty masked array of the given shape and dtype, where all the
|
| 108 |
+
data are masked.
|
| 109 |
+
|
| 110 |
+
Parameters
|
| 111 |
+
----------
|
| 112 |
+
shape : int or tuple of ints
|
| 113 |
+
Shape of the required MaskedArray, e.g., ``(2, 3)`` or ``2``.
|
| 114 |
+
dtype : dtype, optional
|
| 115 |
+
Data type of the output.
|
| 116 |
+
|
| 117 |
+
Returns
|
| 118 |
+
-------
|
| 119 |
+
a : MaskedArray
|
| 120 |
+
A masked array with all data masked.
|
| 121 |
+
|
| 122 |
+
See Also
|
| 123 |
+
--------
|
| 124 |
+
masked_all_like : Empty masked array modelled on an existing array.
|
| 125 |
+
|
| 126 |
+
Examples
|
| 127 |
+
--------
|
| 128 |
+
>>> import numpy.ma as ma
|
| 129 |
+
>>> ma.masked_all((3, 3))
|
| 130 |
+
masked_array(
|
| 131 |
+
data=[[--, --, --],
|
| 132 |
+
[--, --, --],
|
| 133 |
+
[--, --, --]],
|
| 134 |
+
mask=[[ True, True, True],
|
| 135 |
+
[ True, True, True],
|
| 136 |
+
[ True, True, True]],
|
| 137 |
+
fill_value=1e+20,
|
| 138 |
+
dtype=float64)
|
| 139 |
+
|
| 140 |
+
The `dtype` parameter defines the underlying data type.
|
| 141 |
+
|
| 142 |
+
>>> a = ma.masked_all((3, 3))
|
| 143 |
+
>>> a.dtype
|
| 144 |
+
dtype('float64')
|
| 145 |
+
>>> a = ma.masked_all((3, 3), dtype=np.int32)
|
| 146 |
+
>>> a.dtype
|
| 147 |
+
dtype('int32')
|
| 148 |
+
|
| 149 |
+
"""
|
| 150 |
+
a = masked_array(np.empty(shape, dtype),
|
| 151 |
+
mask=np.ones(shape, make_mask_descr(dtype)))
|
| 152 |
+
return a
|
| 153 |
+
|
| 154 |
+
|
| 155 |
+
def masked_all_like(arr):
|
| 156 |
+
"""
|
| 157 |
+
Empty masked array with the properties of an existing array.
|
| 158 |
+
|
| 159 |
+
Return an empty masked array of the same shape and dtype as
|
| 160 |
+
the array `arr`, where all the data are masked.
|
| 161 |
+
|
| 162 |
+
Parameters
|
| 163 |
+
----------
|
| 164 |
+
arr : ndarray
|
| 165 |
+
An array describing the shape and dtype of the required MaskedArray.
|
| 166 |
+
|
| 167 |
+
Returns
|
| 168 |
+
-------
|
| 169 |
+
a : MaskedArray
|
| 170 |
+
A masked array with all data masked.
|
| 171 |
+
|
| 172 |
+
Raises
|
| 173 |
+
------
|
| 174 |
+
AttributeError
|
| 175 |
+
If `arr` doesn't have a shape attribute (i.e. not an ndarray)
|
| 176 |
+
|
| 177 |
+
See Also
|
| 178 |
+
--------
|
| 179 |
+
masked_all : Empty masked array with all elements masked.
|
| 180 |
+
|
| 181 |
+
Examples
|
| 182 |
+
--------
|
| 183 |
+
>>> import numpy.ma as ma
|
| 184 |
+
>>> arr = np.zeros((2, 3), dtype=np.float32)
|
| 185 |
+
>>> arr
|
| 186 |
+
array([[0., 0., 0.],
|
| 187 |
+
[0., 0., 0.]], dtype=float32)
|
| 188 |
+
>>> ma.masked_all_like(arr)
|
| 189 |
+
masked_array(
|
| 190 |
+
data=[[--, --, --],
|
| 191 |
+
[--, --, --]],
|
| 192 |
+
mask=[[ True, True, True],
|
| 193 |
+
[ True, True, True]],
|
| 194 |
+
fill_value=1e+20,
|
| 195 |
+
dtype=float32)
|
| 196 |
+
|
| 197 |
+
The dtype of the masked array matches the dtype of `arr`.
|
| 198 |
+
|
| 199 |
+
>>> arr.dtype
|
| 200 |
+
dtype('float32')
|
| 201 |
+
>>> ma.masked_all_like(arr).dtype
|
| 202 |
+
dtype('float32')
|
| 203 |
+
|
| 204 |
+
"""
|
| 205 |
+
a = np.empty_like(arr).view(MaskedArray)
|
| 206 |
+
a._mask = np.ones(a.shape, dtype=make_mask_descr(a.dtype))
|
| 207 |
+
return a
|
| 208 |
+
|
| 209 |
+
|
| 210 |
+
#####--------------------------------------------------------------------------
|
| 211 |
+
#---- --- Standard functions ---
|
| 212 |
+
#####--------------------------------------------------------------------------
|
| 213 |
+
class _fromnxfunction:
|
| 214 |
+
"""
|
| 215 |
+
Defines a wrapper to adapt NumPy functions to masked arrays.
|
| 216 |
+
|
| 217 |
+
|
| 218 |
+
An instance of `_fromnxfunction` can be called with the same parameters
|
| 219 |
+
as the wrapped NumPy function. The docstring of `newfunc` is adapted from
|
| 220 |
+
the wrapped function as well, see `getdoc`.
|
| 221 |
+
|
| 222 |
+
This class should not be used directly. Instead, one of its extensions that
|
| 223 |
+
provides support for a specific type of input should be used.
|
| 224 |
+
|
| 225 |
+
Parameters
|
| 226 |
+
----------
|
| 227 |
+
funcname : str
|
| 228 |
+
The name of the function to be adapted. The function should be
|
| 229 |
+
in the NumPy namespace (i.e. ``np.funcname``).
|
| 230 |
+
|
| 231 |
+
"""
|
| 232 |
+
|
| 233 |
+
def __init__(self, funcname):
|
| 234 |
+
self.__name__ = funcname
|
| 235 |
+
self.__doc__ = self.getdoc()
|
| 236 |
+
|
| 237 |
+
def getdoc(self):
|
| 238 |
+
"""
|
| 239 |
+
Retrieve the docstring and signature from the function.
|
| 240 |
+
|
| 241 |
+
The ``__doc__`` attribute of the function is used as the docstring for
|
| 242 |
+
the new masked array version of the function. A note on application
|
| 243 |
+
of the function to the mask is appended.
|
| 244 |
+
|
| 245 |
+
Parameters
|
| 246 |
+
----------
|
| 247 |
+
None
|
| 248 |
+
|
| 249 |
+
"""
|
| 250 |
+
npfunc = getattr(np, self.__name__, None)
|
| 251 |
+
doc = getattr(npfunc, '__doc__', None)
|
| 252 |
+
if doc:
|
| 253 |
+
sig = self.__name__ + ma.get_object_signature(npfunc)
|
| 254 |
+
doc = ma.doc_note(doc, "The function is applied to both the _data "
|
| 255 |
+
"and the _mask, if any.")
|
| 256 |
+
return '\n\n'.join((sig, doc))
|
| 257 |
+
return
|
| 258 |
+
|
| 259 |
+
def __call__(self, *args, **params):
|
| 260 |
+
pass
|
| 261 |
+
|
| 262 |
+
|
| 263 |
+
class _fromnxfunction_single(_fromnxfunction):
|
| 264 |
+
"""
|
| 265 |
+
A version of `_fromnxfunction` that is called with a single array
|
| 266 |
+
argument followed by auxiliary args that are passed verbatim for
|
| 267 |
+
both the data and mask calls.
|
| 268 |
+
"""
|
| 269 |
+
def __call__(self, x, *args, **params):
|
| 270 |
+
func = getattr(np, self.__name__)
|
| 271 |
+
if isinstance(x, ndarray):
|
| 272 |
+
_d = func(x.__array__(), *args, **params)
|
| 273 |
+
_m = func(getmaskarray(x), *args, **params)
|
| 274 |
+
return masked_array(_d, mask=_m)
|
| 275 |
+
else:
|
| 276 |
+
_d = func(np.asarray(x), *args, **params)
|
| 277 |
+
_m = func(getmaskarray(x), *args, **params)
|
| 278 |
+
return masked_array(_d, mask=_m)
|
| 279 |
+
|
| 280 |
+
|
| 281 |
+
class _fromnxfunction_seq(_fromnxfunction):
|
| 282 |
+
"""
|
| 283 |
+
A version of `_fromnxfunction` that is called with a single sequence
|
| 284 |
+
of arrays followed by auxiliary args that are passed verbatim for
|
| 285 |
+
both the data and mask calls.
|
| 286 |
+
"""
|
| 287 |
+
def __call__(self, x, *args, **params):
|
| 288 |
+
func = getattr(np, self.__name__)
|
| 289 |
+
_d = func(tuple([np.asarray(a) for a in x]), *args, **params)
|
| 290 |
+
_m = func(tuple([getmaskarray(a) for a in x]), *args, **params)
|
| 291 |
+
return masked_array(_d, mask=_m)
|
| 292 |
+
|
| 293 |
+
|
| 294 |
+
class _fromnxfunction_args(_fromnxfunction):
|
| 295 |
+
"""
|
| 296 |
+
A version of `_fromnxfunction` that is called with multiple array
|
| 297 |
+
arguments. The first non-array-like input marks the beginning of the
|
| 298 |
+
arguments that are passed verbatim for both the data and mask calls.
|
| 299 |
+
Array arguments are processed independently and the results are
|
| 300 |
+
returned in a list. If only one array is found, the return value is
|
| 301 |
+
just the processed array instead of a list.
|
| 302 |
+
"""
|
| 303 |
+
def __call__(self, *args, **params):
|
| 304 |
+
func = getattr(np, self.__name__)
|
| 305 |
+
arrays = []
|
| 306 |
+
args = list(args)
|
| 307 |
+
while len(args) > 0 and issequence(args[0]):
|
| 308 |
+
arrays.append(args.pop(0))
|
| 309 |
+
res = []
|
| 310 |
+
for x in arrays:
|
| 311 |
+
_d = func(np.asarray(x), *args, **params)
|
| 312 |
+
_m = func(getmaskarray(x), *args, **params)
|
| 313 |
+
res.append(masked_array(_d, mask=_m))
|
| 314 |
+
if len(arrays) == 1:
|
| 315 |
+
return res[0]
|
| 316 |
+
return res
|
| 317 |
+
|
| 318 |
+
|
| 319 |
+
class _fromnxfunction_allargs(_fromnxfunction):
|
| 320 |
+
"""
|
| 321 |
+
A version of `_fromnxfunction` that is called with multiple array
|
| 322 |
+
arguments. Similar to `_fromnxfunction_args` except that all args
|
| 323 |
+
are converted to arrays even if they are not so already. This makes
|
| 324 |
+
it possible to process scalars as 1-D arrays. Only keyword arguments
|
| 325 |
+
are passed through verbatim for the data and mask calls. Arrays
|
| 326 |
+
arguments are processed independently and the results are returned
|
| 327 |
+
in a list. If only one arg is present, the return value is just the
|
| 328 |
+
processed array instead of a list.
|
| 329 |
+
"""
|
| 330 |
+
def __call__(self, *args, **params):
|
| 331 |
+
func = getattr(np, self.__name__)
|
| 332 |
+
res = []
|
| 333 |
+
for x in args:
|
| 334 |
+
_d = func(np.asarray(x), **params)
|
| 335 |
+
_m = func(getmaskarray(x), **params)
|
| 336 |
+
res.append(masked_array(_d, mask=_m))
|
| 337 |
+
if len(args) == 1:
|
| 338 |
+
return res[0]
|
| 339 |
+
return res
|
| 340 |
+
|
| 341 |
+
|
| 342 |
+
atleast_1d = _fromnxfunction_allargs('atleast_1d')
|
| 343 |
+
atleast_2d = _fromnxfunction_allargs('atleast_2d')
|
| 344 |
+
atleast_3d = _fromnxfunction_allargs('atleast_3d')
|
| 345 |
+
|
| 346 |
+
vstack = row_stack = _fromnxfunction_seq('vstack')
|
| 347 |
+
hstack = _fromnxfunction_seq('hstack')
|
| 348 |
+
column_stack = _fromnxfunction_seq('column_stack')
|
| 349 |
+
dstack = _fromnxfunction_seq('dstack')
|
| 350 |
+
stack = _fromnxfunction_seq('stack')
|
| 351 |
+
|
| 352 |
+
hsplit = _fromnxfunction_single('hsplit')
|
| 353 |
+
|
| 354 |
+
diagflat = _fromnxfunction_single('diagflat')
|
| 355 |
+
|
| 356 |
+
|
| 357 |
+
#####--------------------------------------------------------------------------
|
| 358 |
+
#----
|
| 359 |
+
#####--------------------------------------------------------------------------
|
| 360 |
+
def flatten_inplace(seq):
|
| 361 |
+
"""Flatten a sequence in place."""
|
| 362 |
+
k = 0
|
| 363 |
+
while (k != len(seq)):
|
| 364 |
+
while hasattr(seq[k], '__iter__'):
|
| 365 |
+
seq[k:(k + 1)] = seq[k]
|
| 366 |
+
k += 1
|
| 367 |
+
return seq
|
| 368 |
+
|
| 369 |
+
|
| 370 |
+
def apply_along_axis(func1d, axis, arr, *args, **kwargs):
|
| 371 |
+
"""
|
| 372 |
+
(This docstring should be overwritten)
|
| 373 |
+
"""
|
| 374 |
+
arr = array(arr, copy=False, subok=True)
|
| 375 |
+
nd = arr.ndim
|
| 376 |
+
axis = normalize_axis_index(axis, nd)
|
| 377 |
+
ind = [0] * (nd - 1)
|
| 378 |
+
i = np.zeros(nd, 'O')
|
| 379 |
+
indlist = list(range(nd))
|
| 380 |
+
indlist.remove(axis)
|
| 381 |
+
i[axis] = slice(None, None)
|
| 382 |
+
outshape = np.asarray(arr.shape).take(indlist)
|
| 383 |
+
i.put(indlist, ind)
|
| 384 |
+
res = func1d(arr[tuple(i.tolist())], *args, **kwargs)
|
| 385 |
+
# if res is a number, then we have a smaller output array
|
| 386 |
+
asscalar = np.isscalar(res)
|
| 387 |
+
if not asscalar:
|
| 388 |
+
try:
|
| 389 |
+
len(res)
|
| 390 |
+
except TypeError:
|
| 391 |
+
asscalar = True
|
| 392 |
+
# Note: we shouldn't set the dtype of the output from the first result
|
| 393 |
+
# so we force the type to object, and build a list of dtypes. We'll
|
| 394 |
+
# just take the largest, to avoid some downcasting
|
| 395 |
+
dtypes = []
|
| 396 |
+
if asscalar:
|
| 397 |
+
dtypes.append(np.asarray(res).dtype)
|
| 398 |
+
outarr = zeros(outshape, object)
|
| 399 |
+
outarr[tuple(ind)] = res
|
| 400 |
+
Ntot = np.prod(outshape)
|
| 401 |
+
k = 1
|
| 402 |
+
while k < Ntot:
|
| 403 |
+
# increment the index
|
| 404 |
+
ind[-1] += 1
|
| 405 |
+
n = -1
|
| 406 |
+
while (ind[n] >= outshape[n]) and (n > (1 - nd)):
|
| 407 |
+
ind[n - 1] += 1
|
| 408 |
+
ind[n] = 0
|
| 409 |
+
n -= 1
|
| 410 |
+
i.put(indlist, ind)
|
| 411 |
+
res = func1d(arr[tuple(i.tolist())], *args, **kwargs)
|
| 412 |
+
outarr[tuple(ind)] = res
|
| 413 |
+
dtypes.append(asarray(res).dtype)
|
| 414 |
+
k += 1
|
| 415 |
+
else:
|
| 416 |
+
res = array(res, copy=False, subok=True)
|
| 417 |
+
j = i.copy()
|
| 418 |
+
j[axis] = ([slice(None, None)] * res.ndim)
|
| 419 |
+
j.put(indlist, ind)
|
| 420 |
+
Ntot = np.prod(outshape)
|
| 421 |
+
holdshape = outshape
|
| 422 |
+
outshape = list(arr.shape)
|
| 423 |
+
outshape[axis] = res.shape
|
| 424 |
+
dtypes.append(asarray(res).dtype)
|
| 425 |
+
outshape = flatten_inplace(outshape)
|
| 426 |
+
outarr = zeros(outshape, object)
|
| 427 |
+
outarr[tuple(flatten_inplace(j.tolist()))] = res
|
| 428 |
+
k = 1
|
| 429 |
+
while k < Ntot:
|
| 430 |
+
# increment the index
|
| 431 |
+
ind[-1] += 1
|
| 432 |
+
n = -1
|
| 433 |
+
while (ind[n] >= holdshape[n]) and (n > (1 - nd)):
|
| 434 |
+
ind[n - 1] += 1
|
| 435 |
+
ind[n] = 0
|
| 436 |
+
n -= 1
|
| 437 |
+
i.put(indlist, ind)
|
| 438 |
+
j.put(indlist, ind)
|
| 439 |
+
res = func1d(arr[tuple(i.tolist())], *args, **kwargs)
|
| 440 |
+
outarr[tuple(flatten_inplace(j.tolist()))] = res
|
| 441 |
+
dtypes.append(asarray(res).dtype)
|
| 442 |
+
k += 1
|
| 443 |
+
max_dtypes = np.dtype(np.asarray(dtypes).max())
|
| 444 |
+
if not hasattr(arr, '_mask'):
|
| 445 |
+
result = np.asarray(outarr, dtype=max_dtypes)
|
| 446 |
+
else:
|
| 447 |
+
result = asarray(outarr, dtype=max_dtypes)
|
| 448 |
+
result.fill_value = ma.default_fill_value(result)
|
| 449 |
+
return result
|
| 450 |
+
apply_along_axis.__doc__ = np.apply_along_axis.__doc__
|
| 451 |
+
|
| 452 |
+
|
| 453 |
+
def apply_over_axes(func, a, axes):
|
| 454 |
+
"""
|
| 455 |
+
(This docstring will be overwritten)
|
| 456 |
+
"""
|
| 457 |
+
val = asarray(a)
|
| 458 |
+
N = a.ndim
|
| 459 |
+
if array(axes).ndim == 0:
|
| 460 |
+
axes = (axes,)
|
| 461 |
+
for axis in axes:
|
| 462 |
+
if axis < 0:
|
| 463 |
+
axis = N + axis
|
| 464 |
+
args = (val, axis)
|
| 465 |
+
res = func(*args)
|
| 466 |
+
if res.ndim == val.ndim:
|
| 467 |
+
val = res
|
| 468 |
+
else:
|
| 469 |
+
res = ma.expand_dims(res, axis)
|
| 470 |
+
if res.ndim == val.ndim:
|
| 471 |
+
val = res
|
| 472 |
+
else:
|
| 473 |
+
raise ValueError("function is not returning "
|
| 474 |
+
"an array of the correct shape")
|
| 475 |
+
return val
|
| 476 |
+
|
| 477 |
+
|
| 478 |
+
if apply_over_axes.__doc__ is not None:
|
| 479 |
+
apply_over_axes.__doc__ = np.apply_over_axes.__doc__[
|
| 480 |
+
:np.apply_over_axes.__doc__.find('Notes')].rstrip() + \
|
| 481 |
+
"""
|
| 482 |
+
|
| 483 |
+
Examples
|
| 484 |
+
--------
|
| 485 |
+
>>> a = np.ma.arange(24).reshape(2,3,4)
|
| 486 |
+
>>> a[:,0,1] = np.ma.masked
|
| 487 |
+
>>> a[:,1,:] = np.ma.masked
|
| 488 |
+
>>> a
|
| 489 |
+
masked_array(
|
| 490 |
+
data=[[[0, --, 2, 3],
|
| 491 |
+
[--, --, --, --],
|
| 492 |
+
[8, 9, 10, 11]],
|
| 493 |
+
[[12, --, 14, 15],
|
| 494 |
+
[--, --, --, --],
|
| 495 |
+
[20, 21, 22, 23]]],
|
| 496 |
+
mask=[[[False, True, False, False],
|
| 497 |
+
[ True, True, True, True],
|
| 498 |
+
[False, False, False, False]],
|
| 499 |
+
[[False, True, False, False],
|
| 500 |
+
[ True, True, True, True],
|
| 501 |
+
[False, False, False, False]]],
|
| 502 |
+
fill_value=999999)
|
| 503 |
+
>>> np.ma.apply_over_axes(np.ma.sum, a, [0,2])
|
| 504 |
+
masked_array(
|
| 505 |
+
data=[[[46],
|
| 506 |
+
[--],
|
| 507 |
+
[124]]],
|
| 508 |
+
mask=[[[False],
|
| 509 |
+
[ True],
|
| 510 |
+
[False]]],
|
| 511 |
+
fill_value=999999)
|
| 512 |
+
|
| 513 |
+
Tuple axis arguments to ufuncs are equivalent:
|
| 514 |
+
|
| 515 |
+
>>> np.ma.sum(a, axis=(0,2)).reshape((1,-1,1))
|
| 516 |
+
masked_array(
|
| 517 |
+
data=[[[46],
|
| 518 |
+
[--],
|
| 519 |
+
[124]]],
|
| 520 |
+
mask=[[[False],
|
| 521 |
+
[ True],
|
| 522 |
+
[False]]],
|
| 523 |
+
fill_value=999999)
|
| 524 |
+
"""
|
| 525 |
+
|
| 526 |
+
|
| 527 |
+
def average(a, axis=None, weights=None, returned=False, *,
|
| 528 |
+
keepdims=np._NoValue):
|
| 529 |
+
"""
|
| 530 |
+
Return the weighted average of array over the given axis.
|
| 531 |
+
|
| 532 |
+
Parameters
|
| 533 |
+
----------
|
| 534 |
+
a : array_like
|
| 535 |
+
Data to be averaged.
|
| 536 |
+
Masked entries are not taken into account in the computation.
|
| 537 |
+
axis : int, optional
|
| 538 |
+
Axis along which to average `a`. If None, averaging is done over
|
| 539 |
+
the flattened array.
|
| 540 |
+
weights : array_like, optional
|
| 541 |
+
The importance that each element has in the computation of the average.
|
| 542 |
+
The weights array can either be 1-D (in which case its length must be
|
| 543 |
+
the size of `a` along the given axis) or of the same shape as `a`.
|
| 544 |
+
If ``weights=None``, then all data in `a` are assumed to have a
|
| 545 |
+
weight equal to one. The 1-D calculation is::
|
| 546 |
+
|
| 547 |
+
avg = sum(a * weights) / sum(weights)
|
| 548 |
+
|
| 549 |
+
The only constraint on `weights` is that `sum(weights)` must not be 0.
|
| 550 |
+
returned : bool, optional
|
| 551 |
+
Flag indicating whether a tuple ``(result, sum of weights)``
|
| 552 |
+
should be returned as output (True), or just the result (False).
|
| 553 |
+
Default is False.
|
| 554 |
+
keepdims : bool, optional
|
| 555 |
+
If this is set to True, the axes which are reduced are left
|
| 556 |
+
in the result as dimensions with size one. With this option,
|
| 557 |
+
the result will broadcast correctly against the original `a`.
|
| 558 |
+
*Note:* `keepdims` will not work with instances of `numpy.matrix`
|
| 559 |
+
or other classes whose methods do not support `keepdims`.
|
| 560 |
+
|
| 561 |
+
.. versionadded:: 1.23.0
|
| 562 |
+
|
| 563 |
+
Returns
|
| 564 |
+
-------
|
| 565 |
+
average, [sum_of_weights] : (tuple of) scalar or MaskedArray
|
| 566 |
+
The average along the specified axis. When returned is `True`,
|
| 567 |
+
return a tuple with the average as the first element and the sum
|
| 568 |
+
of the weights as the second element. The return type is `np.float64`
|
| 569 |
+
if `a` is of integer type and floats smaller than `float64`, or the
|
| 570 |
+
input data-type, otherwise. If returned, `sum_of_weights` is always
|
| 571 |
+
`float64`.
|
| 572 |
+
|
| 573 |
+
Examples
|
| 574 |
+
--------
|
| 575 |
+
>>> a = np.ma.array([1., 2., 3., 4.], mask=[False, False, True, True])
|
| 576 |
+
>>> np.ma.average(a, weights=[3, 1, 0, 0])
|
| 577 |
+
1.25
|
| 578 |
+
|
| 579 |
+
>>> x = np.ma.arange(6.).reshape(3, 2)
|
| 580 |
+
>>> x
|
| 581 |
+
masked_array(
|
| 582 |
+
data=[[0., 1.],
|
| 583 |
+
[2., 3.],
|
| 584 |
+
[4., 5.]],
|
| 585 |
+
mask=False,
|
| 586 |
+
fill_value=1e+20)
|
| 587 |
+
>>> avg, sumweights = np.ma.average(x, axis=0, weights=[1, 2, 3],
|
| 588 |
+
... returned=True)
|
| 589 |
+
>>> avg
|
| 590 |
+
masked_array(data=[2.6666666666666665, 3.6666666666666665],
|
| 591 |
+
mask=[False, False],
|
| 592 |
+
fill_value=1e+20)
|
| 593 |
+
|
| 594 |
+
With ``keepdims=True``, the following result has shape (3, 1).
|
| 595 |
+
|
| 596 |
+
>>> np.ma.average(x, axis=1, keepdims=True)
|
| 597 |
+
masked_array(
|
| 598 |
+
data=[[0.5],
|
| 599 |
+
[2.5],
|
| 600 |
+
[4.5]],
|
| 601 |
+
mask=False,
|
| 602 |
+
fill_value=1e+20)
|
| 603 |
+
"""
|
| 604 |
+
a = asarray(a)
|
| 605 |
+
m = getmask(a)
|
| 606 |
+
|
| 607 |
+
# inspired by 'average' in numpy/lib/function_base.py
|
| 608 |
+
|
| 609 |
+
if keepdims is np._NoValue:
|
| 610 |
+
# Don't pass on the keepdims argument if one wasn't given.
|
| 611 |
+
keepdims_kw = {}
|
| 612 |
+
else:
|
| 613 |
+
keepdims_kw = {'keepdims': keepdims}
|
| 614 |
+
|
| 615 |
+
if weights is None:
|
| 616 |
+
avg = a.mean(axis, **keepdims_kw)
|
| 617 |
+
scl = avg.dtype.type(a.count(axis))
|
| 618 |
+
else:
|
| 619 |
+
wgt = asarray(weights)
|
| 620 |
+
|
| 621 |
+
if issubclass(a.dtype.type, (np.integer, np.bool_)):
|
| 622 |
+
result_dtype = np.result_type(a.dtype, wgt.dtype, 'f8')
|
| 623 |
+
else:
|
| 624 |
+
result_dtype = np.result_type(a.dtype, wgt.dtype)
|
| 625 |
+
|
| 626 |
+
# Sanity checks
|
| 627 |
+
if a.shape != wgt.shape:
|
| 628 |
+
if axis is None:
|
| 629 |
+
raise TypeError(
|
| 630 |
+
"Axis must be specified when shapes of a and weights "
|
| 631 |
+
"differ.")
|
| 632 |
+
if wgt.ndim != 1:
|
| 633 |
+
raise TypeError(
|
| 634 |
+
"1D weights expected when shapes of a and weights differ.")
|
| 635 |
+
if wgt.shape[0] != a.shape[axis]:
|
| 636 |
+
raise ValueError(
|
| 637 |
+
"Length of weights not compatible with specified axis.")
|
| 638 |
+
|
| 639 |
+
# setup wgt to broadcast along axis
|
| 640 |
+
wgt = np.broadcast_to(wgt, (a.ndim-1)*(1,) + wgt.shape, subok=True)
|
| 641 |
+
wgt = wgt.swapaxes(-1, axis)
|
| 642 |
+
|
| 643 |
+
if m is not nomask:
|
| 644 |
+
wgt = wgt*(~a.mask)
|
| 645 |
+
wgt.mask |= a.mask
|
| 646 |
+
|
| 647 |
+
scl = wgt.sum(axis=axis, dtype=result_dtype, **keepdims_kw)
|
| 648 |
+
avg = np.multiply(a, wgt,
|
| 649 |
+
dtype=result_dtype).sum(axis, **keepdims_kw) / scl
|
| 650 |
+
|
| 651 |
+
if returned:
|
| 652 |
+
if scl.shape != avg.shape:
|
| 653 |
+
scl = np.broadcast_to(scl, avg.shape).copy()
|
| 654 |
+
return avg, scl
|
| 655 |
+
else:
|
| 656 |
+
return avg
|
| 657 |
+
|
| 658 |
+
|
| 659 |
+
def median(a, axis=None, out=None, overwrite_input=False, keepdims=False):
|
| 660 |
+
"""
|
| 661 |
+
Compute the median along the specified axis.
|
| 662 |
+
|
| 663 |
+
Returns the median of the array elements.
|
| 664 |
+
|
| 665 |
+
Parameters
|
| 666 |
+
----------
|
| 667 |
+
a : array_like
|
| 668 |
+
Input array or object that can be converted to an array.
|
| 669 |
+
axis : int, optional
|
| 670 |
+
Axis along which the medians are computed. The default (None) is
|
| 671 |
+
to compute the median along a flattened version of the array.
|
| 672 |
+
out : ndarray, optional
|
| 673 |
+
Alternative output array in which to place the result. It must
|
| 674 |
+
have the same shape and buffer length as the expected output
|
| 675 |
+
but the type will be cast if necessary.
|
| 676 |
+
overwrite_input : bool, optional
|
| 677 |
+
If True, then allow use of memory of input array (a) for
|
| 678 |
+
calculations. The input array will be modified by the call to
|
| 679 |
+
median. This will save memory when you do not need to preserve
|
| 680 |
+
the contents of the input array. Treat the input as undefined,
|
| 681 |
+
but it will probably be fully or partially sorted. Default is
|
| 682 |
+
False. Note that, if `overwrite_input` is True, and the input
|
| 683 |
+
is not already an `ndarray`, an error will be raised.
|
| 684 |
+
keepdims : bool, optional
|
| 685 |
+
If this is set to True, the axes which are reduced are left
|
| 686 |
+
in the result as dimensions with size one. With this option,
|
| 687 |
+
the result will broadcast correctly against the input array.
|
| 688 |
+
|
| 689 |
+
.. versionadded:: 1.10.0
|
| 690 |
+
|
| 691 |
+
Returns
|
| 692 |
+
-------
|
| 693 |
+
median : ndarray
|
| 694 |
+
A new array holding the result is returned unless out is
|
| 695 |
+
specified, in which case a reference to out is returned.
|
| 696 |
+
Return data-type is `float64` for integers and floats smaller than
|
| 697 |
+
`float64`, or the input data-type, otherwise.
|
| 698 |
+
|
| 699 |
+
See Also
|
| 700 |
+
--------
|
| 701 |
+
mean
|
| 702 |
+
|
| 703 |
+
Notes
|
| 704 |
+
-----
|
| 705 |
+
Given a vector ``V`` with ``N`` non masked values, the median of ``V``
|
| 706 |
+
is the middle value of a sorted copy of ``V`` (``Vs``) - i.e.
|
| 707 |
+
``Vs[(N-1)/2]``, when ``N`` is odd, or ``{Vs[N/2 - 1] + Vs[N/2]}/2``
|
| 708 |
+
when ``N`` is even.
|
| 709 |
+
|
| 710 |
+
Examples
|
| 711 |
+
--------
|
| 712 |
+
>>> x = np.ma.array(np.arange(8), mask=[0]*4 + [1]*4)
|
| 713 |
+
>>> np.ma.median(x)
|
| 714 |
+
1.5
|
| 715 |
+
|
| 716 |
+
>>> x = np.ma.array(np.arange(10).reshape(2, 5), mask=[0]*6 + [1]*4)
|
| 717 |
+
>>> np.ma.median(x)
|
| 718 |
+
2.5
|
| 719 |
+
>>> np.ma.median(x, axis=-1, overwrite_input=True)
|
| 720 |
+
masked_array(data=[2.0, 5.0],
|
| 721 |
+
mask=[False, False],
|
| 722 |
+
fill_value=1e+20)
|
| 723 |
+
|
| 724 |
+
"""
|
| 725 |
+
if not hasattr(a, 'mask'):
|
| 726 |
+
m = np.median(getdata(a, subok=True), axis=axis,
|
| 727 |
+
out=out, overwrite_input=overwrite_input,
|
| 728 |
+
keepdims=keepdims)
|
| 729 |
+
if isinstance(m, np.ndarray) and 1 <= m.ndim:
|
| 730 |
+
return masked_array(m, copy=False)
|
| 731 |
+
else:
|
| 732 |
+
return m
|
| 733 |
+
|
| 734 |
+
return _ureduce(a, func=_median, keepdims=keepdims, axis=axis, out=out,
|
| 735 |
+
overwrite_input=overwrite_input)
|
| 736 |
+
|
| 737 |
+
|
| 738 |
+
def _median(a, axis=None, out=None, overwrite_input=False):
|
| 739 |
+
# when an unmasked NaN is present return it, so we need to sort the NaN
|
| 740 |
+
# values behind the mask
|
| 741 |
+
if np.issubdtype(a.dtype, np.inexact):
|
| 742 |
+
fill_value = np.inf
|
| 743 |
+
else:
|
| 744 |
+
fill_value = None
|
| 745 |
+
if overwrite_input:
|
| 746 |
+
if axis is None:
|
| 747 |
+
asorted = a.ravel()
|
| 748 |
+
asorted.sort(fill_value=fill_value)
|
| 749 |
+
else:
|
| 750 |
+
a.sort(axis=axis, fill_value=fill_value)
|
| 751 |
+
asorted = a
|
| 752 |
+
else:
|
| 753 |
+
asorted = sort(a, axis=axis, fill_value=fill_value)
|
| 754 |
+
|
| 755 |
+
if axis is None:
|
| 756 |
+
axis = 0
|
| 757 |
+
else:
|
| 758 |
+
axis = normalize_axis_index(axis, asorted.ndim)
|
| 759 |
+
|
| 760 |
+
if asorted.shape[axis] == 0:
|
| 761 |
+
# for empty axis integer indices fail so use slicing to get same result
|
| 762 |
+
# as median (which is mean of empty slice = nan)
|
| 763 |
+
indexer = [slice(None)] * asorted.ndim
|
| 764 |
+
indexer[axis] = slice(0, 0)
|
| 765 |
+
indexer = tuple(indexer)
|
| 766 |
+
return np.ma.mean(asorted[indexer], axis=axis, out=out)
|
| 767 |
+
|
| 768 |
+
if asorted.ndim == 1:
|
| 769 |
+
idx, odd = divmod(count(asorted), 2)
|
| 770 |
+
mid = asorted[idx + odd - 1:idx + 1]
|
| 771 |
+
if np.issubdtype(asorted.dtype, np.inexact) and asorted.size > 0:
|
| 772 |
+
# avoid inf / x = masked
|
| 773 |
+
s = mid.sum(out=out)
|
| 774 |
+
if not odd:
|
| 775 |
+
s = np.true_divide(s, 2., casting='safe', out=out)
|
| 776 |
+
s = np.lib.utils._median_nancheck(asorted, s, axis)
|
| 777 |
+
else:
|
| 778 |
+
s = mid.mean(out=out)
|
| 779 |
+
|
| 780 |
+
# if result is masked either the input contained enough
|
| 781 |
+
# minimum_fill_value so that it would be the median or all values
|
| 782 |
+
# masked
|
| 783 |
+
if np.ma.is_masked(s) and not np.all(asorted.mask):
|
| 784 |
+
return np.ma.minimum_fill_value(asorted)
|
| 785 |
+
return s
|
| 786 |
+
|
| 787 |
+
counts = count(asorted, axis=axis, keepdims=True)
|
| 788 |
+
h = counts // 2
|
| 789 |
+
|
| 790 |
+
# duplicate high if odd number of elements so mean does nothing
|
| 791 |
+
odd = counts % 2 == 1
|
| 792 |
+
l = np.where(odd, h, h-1)
|
| 793 |
+
|
| 794 |
+
lh = np.concatenate([l,h], axis=axis)
|
| 795 |
+
|
| 796 |
+
# get low and high median
|
| 797 |
+
low_high = np.take_along_axis(asorted, lh, axis=axis)
|
| 798 |
+
|
| 799 |
+
def replace_masked(s):
|
| 800 |
+
# Replace masked entries with minimum_full_value unless it all values
|
| 801 |
+
# are masked. This is required as the sort order of values equal or
|
| 802 |
+
# larger than the fill value is undefined and a valid value placed
|
| 803 |
+
# elsewhere, e.g. [4, --, inf].
|
| 804 |
+
if np.ma.is_masked(s):
|
| 805 |
+
rep = (~np.all(asorted.mask, axis=axis, keepdims=True)) & s.mask
|
| 806 |
+
s.data[rep] = np.ma.minimum_fill_value(asorted)
|
| 807 |
+
s.mask[rep] = False
|
| 808 |
+
|
| 809 |
+
replace_masked(low_high)
|
| 810 |
+
|
| 811 |
+
if np.issubdtype(asorted.dtype, np.inexact):
|
| 812 |
+
# avoid inf / x = masked
|
| 813 |
+
s = np.ma.sum(low_high, axis=axis, out=out)
|
| 814 |
+
np.true_divide(s.data, 2., casting='unsafe', out=s.data)
|
| 815 |
+
|
| 816 |
+
s = np.lib.utils._median_nancheck(asorted, s, axis)
|
| 817 |
+
else:
|
| 818 |
+
s = np.ma.mean(low_high, axis=axis, out=out)
|
| 819 |
+
|
| 820 |
+
return s
|
| 821 |
+
|
| 822 |
+
|
| 823 |
+
def compress_nd(x, axis=None):
|
| 824 |
+
"""Suppress slices from multiple dimensions which contain masked values.
|
| 825 |
+
|
| 826 |
+
Parameters
|
| 827 |
+
----------
|
| 828 |
+
x : array_like, MaskedArray
|
| 829 |
+
The array to operate on. If not a MaskedArray instance (or if no array
|
| 830 |
+
elements are masked), `x` is interpreted as a MaskedArray with `mask`
|
| 831 |
+
set to `nomask`.
|
| 832 |
+
axis : tuple of ints or int, optional
|
| 833 |
+
Which dimensions to suppress slices from can be configured with this
|
| 834 |
+
parameter.
|
| 835 |
+
- If axis is a tuple of ints, those are the axes to suppress slices from.
|
| 836 |
+
- If axis is an int, then that is the only axis to suppress slices from.
|
| 837 |
+
- If axis is None, all axis are selected.
|
| 838 |
+
|
| 839 |
+
Returns
|
| 840 |
+
-------
|
| 841 |
+
compress_array : ndarray
|
| 842 |
+
The compressed array.
|
| 843 |
+
"""
|
| 844 |
+
x = asarray(x)
|
| 845 |
+
m = getmask(x)
|
| 846 |
+
# Set axis to tuple of ints
|
| 847 |
+
if axis is None:
|
| 848 |
+
axis = tuple(range(x.ndim))
|
| 849 |
+
else:
|
| 850 |
+
axis = normalize_axis_tuple(axis, x.ndim)
|
| 851 |
+
|
| 852 |
+
# Nothing is masked: return x
|
| 853 |
+
if m is nomask or not m.any():
|
| 854 |
+
return x._data
|
| 855 |
+
# All is masked: return empty
|
| 856 |
+
if m.all():
|
| 857 |
+
return nxarray([])
|
| 858 |
+
# Filter elements through boolean indexing
|
| 859 |
+
data = x._data
|
| 860 |
+
for ax in axis:
|
| 861 |
+
axes = tuple(list(range(ax)) + list(range(ax + 1, x.ndim)))
|
| 862 |
+
data = data[(slice(None),)*ax + (~m.any(axis=axes),)]
|
| 863 |
+
return data
|
| 864 |
+
|
| 865 |
+
|
| 866 |
+
def compress_rowcols(x, axis=None):
|
| 867 |
+
"""
|
| 868 |
+
Suppress the rows and/or columns of a 2-D array that contain
|
| 869 |
+
masked values.
|
| 870 |
+
|
| 871 |
+
The suppression behavior is selected with the `axis` parameter.
|
| 872 |
+
|
| 873 |
+
- If axis is None, both rows and columns are suppressed.
|
| 874 |
+
- If axis is 0, only rows are suppressed.
|
| 875 |
+
- If axis is 1 or -1, only columns are suppressed.
|
| 876 |
+
|
| 877 |
+
Parameters
|
| 878 |
+
----------
|
| 879 |
+
x : array_like, MaskedArray
|
| 880 |
+
The array to operate on. If not a MaskedArray instance (or if no array
|
| 881 |
+
elements are masked), `x` is interpreted as a MaskedArray with
|
| 882 |
+
`mask` set to `nomask`. Must be a 2D array.
|
| 883 |
+
axis : int, optional
|
| 884 |
+
Axis along which to perform the operation. Default is None.
|
| 885 |
+
|
| 886 |
+
Returns
|
| 887 |
+
-------
|
| 888 |
+
compressed_array : ndarray
|
| 889 |
+
The compressed array.
|
| 890 |
+
|
| 891 |
+
Examples
|
| 892 |
+
--------
|
| 893 |
+
>>> x = np.ma.array(np.arange(9).reshape(3, 3), mask=[[1, 0, 0],
|
| 894 |
+
... [1, 0, 0],
|
| 895 |
+
... [0, 0, 0]])
|
| 896 |
+
>>> x
|
| 897 |
+
masked_array(
|
| 898 |
+
data=[[--, 1, 2],
|
| 899 |
+
[--, 4, 5],
|
| 900 |
+
[6, 7, 8]],
|
| 901 |
+
mask=[[ True, False, False],
|
| 902 |
+
[ True, False, False],
|
| 903 |
+
[False, False, False]],
|
| 904 |
+
fill_value=999999)
|
| 905 |
+
|
| 906 |
+
>>> np.ma.compress_rowcols(x)
|
| 907 |
+
array([[7, 8]])
|
| 908 |
+
>>> np.ma.compress_rowcols(x, 0)
|
| 909 |
+
array([[6, 7, 8]])
|
| 910 |
+
>>> np.ma.compress_rowcols(x, 1)
|
| 911 |
+
array([[1, 2],
|
| 912 |
+
[4, 5],
|
| 913 |
+
[7, 8]])
|
| 914 |
+
|
| 915 |
+
"""
|
| 916 |
+
if asarray(x).ndim != 2:
|
| 917 |
+
raise NotImplementedError("compress_rowcols works for 2D arrays only.")
|
| 918 |
+
return compress_nd(x, axis=axis)
|
| 919 |
+
|
| 920 |
+
|
| 921 |
+
def compress_rows(a):
|
| 922 |
+
"""
|
| 923 |
+
Suppress whole rows of a 2-D array that contain masked values.
|
| 924 |
+
|
| 925 |
+
This is equivalent to ``np.ma.compress_rowcols(a, 0)``, see
|
| 926 |
+
`compress_rowcols` for details.
|
| 927 |
+
|
| 928 |
+
See Also
|
| 929 |
+
--------
|
| 930 |
+
compress_rowcols
|
| 931 |
+
|
| 932 |
+
"""
|
| 933 |
+
a = asarray(a)
|
| 934 |
+
if a.ndim != 2:
|
| 935 |
+
raise NotImplementedError("compress_rows works for 2D arrays only.")
|
| 936 |
+
return compress_rowcols(a, 0)
|
| 937 |
+
|
| 938 |
+
|
| 939 |
+
def compress_cols(a):
|
| 940 |
+
"""
|
| 941 |
+
Suppress whole columns of a 2-D array that contain masked values.
|
| 942 |
+
|
| 943 |
+
This is equivalent to ``np.ma.compress_rowcols(a, 1)``, see
|
| 944 |
+
`compress_rowcols` for details.
|
| 945 |
+
|
| 946 |
+
See Also
|
| 947 |
+
--------
|
| 948 |
+
compress_rowcols
|
| 949 |
+
|
| 950 |
+
"""
|
| 951 |
+
a = asarray(a)
|
| 952 |
+
if a.ndim != 2:
|
| 953 |
+
raise NotImplementedError("compress_cols works for 2D arrays only.")
|
| 954 |
+
return compress_rowcols(a, 1)
|
| 955 |
+
|
| 956 |
+
|
| 957 |
+
def mask_rowcols(a, axis=None):
|
| 958 |
+
"""
|
| 959 |
+
Mask rows and/or columns of a 2D array that contain masked values.
|
| 960 |
+
|
| 961 |
+
Mask whole rows and/or columns of a 2D array that contain
|
| 962 |
+
masked values. The masking behavior is selected using the
|
| 963 |
+
`axis` parameter.
|
| 964 |
+
|
| 965 |
+
- If `axis` is None, rows *and* columns are masked.
|
| 966 |
+
- If `axis` is 0, only rows are masked.
|
| 967 |
+
- If `axis` is 1 or -1, only columns are masked.
|
| 968 |
+
|
| 969 |
+
Parameters
|
| 970 |
+
----------
|
| 971 |
+
a : array_like, MaskedArray
|
| 972 |
+
The array to mask. If not a MaskedArray instance (or if no array
|
| 973 |
+
elements are masked), the result is a MaskedArray with `mask` set
|
| 974 |
+
to `nomask` (False). Must be a 2D array.
|
| 975 |
+
axis : int, optional
|
| 976 |
+
Axis along which to perform the operation. If None, applies to a
|
| 977 |
+
flattened version of the array.
|
| 978 |
+
|
| 979 |
+
Returns
|
| 980 |
+
-------
|
| 981 |
+
a : MaskedArray
|
| 982 |
+
A modified version of the input array, masked depending on the value
|
| 983 |
+
of the `axis` parameter.
|
| 984 |
+
|
| 985 |
+
Raises
|
| 986 |
+
------
|
| 987 |
+
NotImplementedError
|
| 988 |
+
If input array `a` is not 2D.
|
| 989 |
+
|
| 990 |
+
See Also
|
| 991 |
+
--------
|
| 992 |
+
mask_rows : Mask rows of a 2D array that contain masked values.
|
| 993 |
+
mask_cols : Mask cols of a 2D array that contain masked values.
|
| 994 |
+
masked_where : Mask where a condition is met.
|
| 995 |
+
|
| 996 |
+
Notes
|
| 997 |
+
-----
|
| 998 |
+
The input array's mask is modified by this function.
|
| 999 |
+
|
| 1000 |
+
Examples
|
| 1001 |
+
--------
|
| 1002 |
+
>>> import numpy.ma as ma
|
| 1003 |
+
>>> a = np.zeros((3, 3), dtype=int)
|
| 1004 |
+
>>> a[1, 1] = 1
|
| 1005 |
+
>>> a
|
| 1006 |
+
array([[0, 0, 0],
|
| 1007 |
+
[0, 1, 0],
|
| 1008 |
+
[0, 0, 0]])
|
| 1009 |
+
>>> a = ma.masked_equal(a, 1)
|
| 1010 |
+
>>> a
|
| 1011 |
+
masked_array(
|
| 1012 |
+
data=[[0, 0, 0],
|
| 1013 |
+
[0, --, 0],
|
| 1014 |
+
[0, 0, 0]],
|
| 1015 |
+
mask=[[False, False, False],
|
| 1016 |
+
[False, True, False],
|
| 1017 |
+
[False, False, False]],
|
| 1018 |
+
fill_value=1)
|
| 1019 |
+
>>> ma.mask_rowcols(a)
|
| 1020 |
+
masked_array(
|
| 1021 |
+
data=[[0, --, 0],
|
| 1022 |
+
[--, --, --],
|
| 1023 |
+
[0, --, 0]],
|
| 1024 |
+
mask=[[False, True, False],
|
| 1025 |
+
[ True, True, True],
|
| 1026 |
+
[False, True, False]],
|
| 1027 |
+
fill_value=1)
|
| 1028 |
+
|
| 1029 |
+
"""
|
| 1030 |
+
a = array(a, subok=False)
|
| 1031 |
+
if a.ndim != 2:
|
| 1032 |
+
raise NotImplementedError("mask_rowcols works for 2D arrays only.")
|
| 1033 |
+
m = getmask(a)
|
| 1034 |
+
# Nothing is masked: return a
|
| 1035 |
+
if m is nomask or not m.any():
|
| 1036 |
+
return a
|
| 1037 |
+
maskedval = m.nonzero()
|
| 1038 |
+
a._mask = a._mask.copy()
|
| 1039 |
+
if not axis:
|
| 1040 |
+
a[np.unique(maskedval[0])] = masked
|
| 1041 |
+
if axis in [None, 1, -1]:
|
| 1042 |
+
a[:, np.unique(maskedval[1])] = masked
|
| 1043 |
+
return a
|
| 1044 |
+
|
| 1045 |
+
|
| 1046 |
+
def mask_rows(a, axis=np._NoValue):
|
| 1047 |
+
"""
|
| 1048 |
+
Mask rows of a 2D array that contain masked values.
|
| 1049 |
+
|
| 1050 |
+
This function is a shortcut to ``mask_rowcols`` with `axis` equal to 0.
|
| 1051 |
+
|
| 1052 |
+
See Also
|
| 1053 |
+
--------
|
| 1054 |
+
mask_rowcols : Mask rows and/or columns of a 2D array.
|
| 1055 |
+
masked_where : Mask where a condition is met.
|
| 1056 |
+
|
| 1057 |
+
Examples
|
| 1058 |
+
--------
|
| 1059 |
+
>>> import numpy.ma as ma
|
| 1060 |
+
>>> a = np.zeros((3, 3), dtype=int)
|
| 1061 |
+
>>> a[1, 1] = 1
|
| 1062 |
+
>>> a
|
| 1063 |
+
array([[0, 0, 0],
|
| 1064 |
+
[0, 1, 0],
|
| 1065 |
+
[0, 0, 0]])
|
| 1066 |
+
>>> a = ma.masked_equal(a, 1)
|
| 1067 |
+
>>> a
|
| 1068 |
+
masked_array(
|
| 1069 |
+
data=[[0, 0, 0],
|
| 1070 |
+
[0, --, 0],
|
| 1071 |
+
[0, 0, 0]],
|
| 1072 |
+
mask=[[False, False, False],
|
| 1073 |
+
[False, True, False],
|
| 1074 |
+
[False, False, False]],
|
| 1075 |
+
fill_value=1)
|
| 1076 |
+
|
| 1077 |
+
>>> ma.mask_rows(a)
|
| 1078 |
+
masked_array(
|
| 1079 |
+
data=[[0, 0, 0],
|
| 1080 |
+
[--, --, --],
|
| 1081 |
+
[0, 0, 0]],
|
| 1082 |
+
mask=[[False, False, False],
|
| 1083 |
+
[ True, True, True],
|
| 1084 |
+
[False, False, False]],
|
| 1085 |
+
fill_value=1)
|
| 1086 |
+
|
| 1087 |
+
"""
|
| 1088 |
+
if axis is not np._NoValue:
|
| 1089 |
+
# remove the axis argument when this deprecation expires
|
| 1090 |
+
# NumPy 1.18.0, 2019-11-28
|
| 1091 |
+
warnings.warn(
|
| 1092 |
+
"The axis argument has always been ignored, in future passing it "
|
| 1093 |
+
"will raise TypeError", DeprecationWarning, stacklevel=2)
|
| 1094 |
+
return mask_rowcols(a, 0)
|
| 1095 |
+
|
| 1096 |
+
|
| 1097 |
+
def mask_cols(a, axis=np._NoValue):
|
| 1098 |
+
"""
|
| 1099 |
+
Mask columns of a 2D array that contain masked values.
|
| 1100 |
+
|
| 1101 |
+
This function is a shortcut to ``mask_rowcols`` with `axis` equal to 1.
|
| 1102 |
+
|
| 1103 |
+
See Also
|
| 1104 |
+
--------
|
| 1105 |
+
mask_rowcols : Mask rows and/or columns of a 2D array.
|
| 1106 |
+
masked_where : Mask where a condition is met.
|
| 1107 |
+
|
| 1108 |
+
Examples
|
| 1109 |
+
--------
|
| 1110 |
+
>>> import numpy.ma as ma
|
| 1111 |
+
>>> a = np.zeros((3, 3), dtype=int)
|
| 1112 |
+
>>> a[1, 1] = 1
|
| 1113 |
+
>>> a
|
| 1114 |
+
array([[0, 0, 0],
|
| 1115 |
+
[0, 1, 0],
|
| 1116 |
+
[0, 0, 0]])
|
| 1117 |
+
>>> a = ma.masked_equal(a, 1)
|
| 1118 |
+
>>> a
|
| 1119 |
+
masked_array(
|
| 1120 |
+
data=[[0, 0, 0],
|
| 1121 |
+
[0, --, 0],
|
| 1122 |
+
[0, 0, 0]],
|
| 1123 |
+
mask=[[False, False, False],
|
| 1124 |
+
[False, True, False],
|
| 1125 |
+
[False, False, False]],
|
| 1126 |
+
fill_value=1)
|
| 1127 |
+
>>> ma.mask_cols(a)
|
| 1128 |
+
masked_array(
|
| 1129 |
+
data=[[0, --, 0],
|
| 1130 |
+
[0, --, 0],
|
| 1131 |
+
[0, --, 0]],
|
| 1132 |
+
mask=[[False, True, False],
|
| 1133 |
+
[False, True, False],
|
| 1134 |
+
[False, True, False]],
|
| 1135 |
+
fill_value=1)
|
| 1136 |
+
|
| 1137 |
+
"""
|
| 1138 |
+
if axis is not np._NoValue:
|
| 1139 |
+
# remove the axis argument when this deprecation expires
|
| 1140 |
+
# NumPy 1.18.0, 2019-11-28
|
| 1141 |
+
warnings.warn(
|
| 1142 |
+
"The axis argument has always been ignored, in future passing it "
|
| 1143 |
+
"will raise TypeError", DeprecationWarning, stacklevel=2)
|
| 1144 |
+
return mask_rowcols(a, 1)
|
| 1145 |
+
|
| 1146 |
+
|
| 1147 |
+
#####--------------------------------------------------------------------------
|
| 1148 |
+
#---- --- arraysetops ---
|
| 1149 |
+
#####--------------------------------------------------------------------------
|
| 1150 |
+
|
| 1151 |
+
def ediff1d(arr, to_end=None, to_begin=None):
|
| 1152 |
+
"""
|
| 1153 |
+
Compute the differences between consecutive elements of an array.
|
| 1154 |
+
|
| 1155 |
+
This function is the equivalent of `numpy.ediff1d` that takes masked
|
| 1156 |
+
values into account, see `numpy.ediff1d` for details.
|
| 1157 |
+
|
| 1158 |
+
See Also
|
| 1159 |
+
--------
|
| 1160 |
+
numpy.ediff1d : Equivalent function for ndarrays.
|
| 1161 |
+
|
| 1162 |
+
"""
|
| 1163 |
+
arr = ma.asanyarray(arr).flat
|
| 1164 |
+
ed = arr[1:] - arr[:-1]
|
| 1165 |
+
arrays = [ed]
|
| 1166 |
+
#
|
| 1167 |
+
if to_begin is not None:
|
| 1168 |
+
arrays.insert(0, to_begin)
|
| 1169 |
+
if to_end is not None:
|
| 1170 |
+
arrays.append(to_end)
|
| 1171 |
+
#
|
| 1172 |
+
if len(arrays) != 1:
|
| 1173 |
+
# We'll save ourselves a copy of a potentially large array in the common
|
| 1174 |
+
# case where neither to_begin or to_end was given.
|
| 1175 |
+
ed = hstack(arrays)
|
| 1176 |
+
#
|
| 1177 |
+
return ed
|
| 1178 |
+
|
| 1179 |
+
|
| 1180 |
+
def unique(ar1, return_index=False, return_inverse=False):
|
| 1181 |
+
"""
|
| 1182 |
+
Finds the unique elements of an array.
|
| 1183 |
+
|
| 1184 |
+
Masked values are considered the same element (masked). The output array
|
| 1185 |
+
is always a masked array. See `numpy.unique` for more details.
|
| 1186 |
+
|
| 1187 |
+
See Also
|
| 1188 |
+
--------
|
| 1189 |
+
numpy.unique : Equivalent function for ndarrays.
|
| 1190 |
+
|
| 1191 |
+
Examples
|
| 1192 |
+
--------
|
| 1193 |
+
>>> import numpy.ma as ma
|
| 1194 |
+
>>> a = [1, 2, 1000, 2, 3]
|
| 1195 |
+
>>> mask = [0, 0, 1, 0, 0]
|
| 1196 |
+
>>> masked_a = ma.masked_array(a, mask)
|
| 1197 |
+
>>> masked_a
|
| 1198 |
+
masked_array(data=[1, 2, --, 2, 3],
|
| 1199 |
+
mask=[False, False, True, False, False],
|
| 1200 |
+
fill_value=999999)
|
| 1201 |
+
>>> ma.unique(masked_a)
|
| 1202 |
+
masked_array(data=[1, 2, 3, --],
|
| 1203 |
+
mask=[False, False, False, True],
|
| 1204 |
+
fill_value=999999)
|
| 1205 |
+
>>> ma.unique(masked_a, return_index=True)
|
| 1206 |
+
(masked_array(data=[1, 2, 3, --],
|
| 1207 |
+
mask=[False, False, False, True],
|
| 1208 |
+
fill_value=999999), array([0, 1, 4, 2]))
|
| 1209 |
+
>>> ma.unique(masked_a, return_inverse=True)
|
| 1210 |
+
(masked_array(data=[1, 2, 3, --],
|
| 1211 |
+
mask=[False, False, False, True],
|
| 1212 |
+
fill_value=999999), array([0, 1, 3, 1, 2]))
|
| 1213 |
+
>>> ma.unique(masked_a, return_index=True, return_inverse=True)
|
| 1214 |
+
(masked_array(data=[1, 2, 3, --],
|
| 1215 |
+
mask=[False, False, False, True],
|
| 1216 |
+
fill_value=999999), array([0, 1, 4, 2]), array([0, 1, 3, 1, 2]))
|
| 1217 |
+
"""
|
| 1218 |
+
output = np.unique(ar1,
|
| 1219 |
+
return_index=return_index,
|
| 1220 |
+
return_inverse=return_inverse)
|
| 1221 |
+
if isinstance(output, tuple):
|
| 1222 |
+
output = list(output)
|
| 1223 |
+
output[0] = output[0].view(MaskedArray)
|
| 1224 |
+
output = tuple(output)
|
| 1225 |
+
else:
|
| 1226 |
+
output = output.view(MaskedArray)
|
| 1227 |
+
return output
|
| 1228 |
+
|
| 1229 |
+
|
| 1230 |
+
def intersect1d(ar1, ar2, assume_unique=False):
|
| 1231 |
+
"""
|
| 1232 |
+
Returns the unique elements common to both arrays.
|
| 1233 |
+
|
| 1234 |
+
Masked values are considered equal one to the other.
|
| 1235 |
+
The output is always a masked array.
|
| 1236 |
+
|
| 1237 |
+
See `numpy.intersect1d` for more details.
|
| 1238 |
+
|
| 1239 |
+
See Also
|
| 1240 |
+
--------
|
| 1241 |
+
numpy.intersect1d : Equivalent function for ndarrays.
|
| 1242 |
+
|
| 1243 |
+
Examples
|
| 1244 |
+
--------
|
| 1245 |
+
>>> x = np.ma.array([1, 3, 3, 3], mask=[0, 0, 0, 1])
|
| 1246 |
+
>>> y = np.ma.array([3, 1, 1, 1], mask=[0, 0, 0, 1])
|
| 1247 |
+
>>> np.ma.intersect1d(x, y)
|
| 1248 |
+
masked_array(data=[1, 3, --],
|
| 1249 |
+
mask=[False, False, True],
|
| 1250 |
+
fill_value=999999)
|
| 1251 |
+
|
| 1252 |
+
"""
|
| 1253 |
+
if assume_unique:
|
| 1254 |
+
aux = ma.concatenate((ar1, ar2))
|
| 1255 |
+
else:
|
| 1256 |
+
# Might be faster than unique( intersect1d( ar1, ar2 ) )?
|
| 1257 |
+
aux = ma.concatenate((unique(ar1), unique(ar2)))
|
| 1258 |
+
aux.sort()
|
| 1259 |
+
return aux[:-1][aux[1:] == aux[:-1]]
|
| 1260 |
+
|
| 1261 |
+
|
| 1262 |
+
def setxor1d(ar1, ar2, assume_unique=False):
|
| 1263 |
+
"""
|
| 1264 |
+
Set exclusive-or of 1-D arrays with unique elements.
|
| 1265 |
+
|
| 1266 |
+
The output is always a masked array. See `numpy.setxor1d` for more details.
|
| 1267 |
+
|
| 1268 |
+
See Also
|
| 1269 |
+
--------
|
| 1270 |
+
numpy.setxor1d : Equivalent function for ndarrays.
|
| 1271 |
+
|
| 1272 |
+
"""
|
| 1273 |
+
if not assume_unique:
|
| 1274 |
+
ar1 = unique(ar1)
|
| 1275 |
+
ar2 = unique(ar2)
|
| 1276 |
+
|
| 1277 |
+
aux = ma.concatenate((ar1, ar2))
|
| 1278 |
+
if aux.size == 0:
|
| 1279 |
+
return aux
|
| 1280 |
+
aux.sort()
|
| 1281 |
+
auxf = aux.filled()
|
| 1282 |
+
# flag = ediff1d( aux, to_end = 1, to_begin = 1 ) == 0
|
| 1283 |
+
flag = ma.concatenate(([True], (auxf[1:] != auxf[:-1]), [True]))
|
| 1284 |
+
# flag2 = ediff1d( flag ) == 0
|
| 1285 |
+
flag2 = (flag[1:] == flag[:-1])
|
| 1286 |
+
return aux[flag2]
|
| 1287 |
+
|
| 1288 |
+
|
| 1289 |
+
def in1d(ar1, ar2, assume_unique=False, invert=False):
|
| 1290 |
+
"""
|
| 1291 |
+
Test whether each element of an array is also present in a second
|
| 1292 |
+
array.
|
| 1293 |
+
|
| 1294 |
+
The output is always a masked array. See `numpy.in1d` for more details.
|
| 1295 |
+
|
| 1296 |
+
We recommend using :func:`isin` instead of `in1d` for new code.
|
| 1297 |
+
|
| 1298 |
+
See Also
|
| 1299 |
+
--------
|
| 1300 |
+
isin : Version of this function that preserves the shape of ar1.
|
| 1301 |
+
numpy.in1d : Equivalent function for ndarrays.
|
| 1302 |
+
|
| 1303 |
+
Notes
|
| 1304 |
+
-----
|
| 1305 |
+
.. versionadded:: 1.4.0
|
| 1306 |
+
|
| 1307 |
+
"""
|
| 1308 |
+
if not assume_unique:
|
| 1309 |
+
ar1, rev_idx = unique(ar1, return_inverse=True)
|
| 1310 |
+
ar2 = unique(ar2)
|
| 1311 |
+
|
| 1312 |
+
ar = ma.concatenate((ar1, ar2))
|
| 1313 |
+
# We need this to be a stable sort, so always use 'mergesort'
|
| 1314 |
+
# here. The values from the first array should always come before
|
| 1315 |
+
# the values from the second array.
|
| 1316 |
+
order = ar.argsort(kind='mergesort')
|
| 1317 |
+
sar = ar[order]
|
| 1318 |
+
if invert:
|
| 1319 |
+
bool_ar = (sar[1:] != sar[:-1])
|
| 1320 |
+
else:
|
| 1321 |
+
bool_ar = (sar[1:] == sar[:-1])
|
| 1322 |
+
flag = ma.concatenate((bool_ar, [invert]))
|
| 1323 |
+
indx = order.argsort(kind='mergesort')[:len(ar1)]
|
| 1324 |
+
|
| 1325 |
+
if assume_unique:
|
| 1326 |
+
return flag[indx]
|
| 1327 |
+
else:
|
| 1328 |
+
return flag[indx][rev_idx]
|
| 1329 |
+
|
| 1330 |
+
|
| 1331 |
+
def isin(element, test_elements, assume_unique=False, invert=False):
|
| 1332 |
+
"""
|
| 1333 |
+
Calculates `element in test_elements`, broadcasting over
|
| 1334 |
+
`element` only.
|
| 1335 |
+
|
| 1336 |
+
The output is always a masked array of the same shape as `element`.
|
| 1337 |
+
See `numpy.isin` for more details.
|
| 1338 |
+
|
| 1339 |
+
See Also
|
| 1340 |
+
--------
|
| 1341 |
+
in1d : Flattened version of this function.
|
| 1342 |
+
numpy.isin : Equivalent function for ndarrays.
|
| 1343 |
+
|
| 1344 |
+
Notes
|
| 1345 |
+
-----
|
| 1346 |
+
.. versionadded:: 1.13.0
|
| 1347 |
+
|
| 1348 |
+
"""
|
| 1349 |
+
element = ma.asarray(element)
|
| 1350 |
+
return in1d(element, test_elements, assume_unique=assume_unique,
|
| 1351 |
+
invert=invert).reshape(element.shape)
|
| 1352 |
+
|
| 1353 |
+
|
| 1354 |
+
def union1d(ar1, ar2):
|
| 1355 |
+
"""
|
| 1356 |
+
Union of two arrays.
|
| 1357 |
+
|
| 1358 |
+
The output is always a masked array. See `numpy.union1d` for more details.
|
| 1359 |
+
|
| 1360 |
+
See Also
|
| 1361 |
+
--------
|
| 1362 |
+
numpy.union1d : Equivalent function for ndarrays.
|
| 1363 |
+
|
| 1364 |
+
"""
|
| 1365 |
+
return unique(ma.concatenate((ar1, ar2), axis=None))
|
| 1366 |
+
|
| 1367 |
+
|
| 1368 |
+
def setdiff1d(ar1, ar2, assume_unique=False):
|
| 1369 |
+
"""
|
| 1370 |
+
Set difference of 1D arrays with unique elements.
|
| 1371 |
+
|
| 1372 |
+
The output is always a masked array. See `numpy.setdiff1d` for more
|
| 1373 |
+
details.
|
| 1374 |
+
|
| 1375 |
+
See Also
|
| 1376 |
+
--------
|
| 1377 |
+
numpy.setdiff1d : Equivalent function for ndarrays.
|
| 1378 |
+
|
| 1379 |
+
Examples
|
| 1380 |
+
--------
|
| 1381 |
+
>>> x = np.ma.array([1, 2, 3, 4], mask=[0, 1, 0, 1])
|
| 1382 |
+
>>> np.ma.setdiff1d(x, [1, 2])
|
| 1383 |
+
masked_array(data=[3, --],
|
| 1384 |
+
mask=[False, True],
|
| 1385 |
+
fill_value=999999)
|
| 1386 |
+
|
| 1387 |
+
"""
|
| 1388 |
+
if assume_unique:
|
| 1389 |
+
ar1 = ma.asarray(ar1).ravel()
|
| 1390 |
+
else:
|
| 1391 |
+
ar1 = unique(ar1)
|
| 1392 |
+
ar2 = unique(ar2)
|
| 1393 |
+
return ar1[in1d(ar1, ar2, assume_unique=True, invert=True)]
|
| 1394 |
+
|
| 1395 |
+
|
| 1396 |
+
###############################################################################
|
| 1397 |
+
# Covariance #
|
| 1398 |
+
###############################################################################
|
| 1399 |
+
|
| 1400 |
+
|
| 1401 |
+
def _covhelper(x, y=None, rowvar=True, allow_masked=True):
|
| 1402 |
+
"""
|
| 1403 |
+
Private function for the computation of covariance and correlation
|
| 1404 |
+
coefficients.
|
| 1405 |
+
|
| 1406 |
+
"""
|
| 1407 |
+
x = ma.array(x, ndmin=2, copy=True, dtype=float)
|
| 1408 |
+
xmask = ma.getmaskarray(x)
|
| 1409 |
+
# Quick exit if we can't process masked data
|
| 1410 |
+
if not allow_masked and xmask.any():
|
| 1411 |
+
raise ValueError("Cannot process masked data.")
|
| 1412 |
+
#
|
| 1413 |
+
if x.shape[0] == 1:
|
| 1414 |
+
rowvar = True
|
| 1415 |
+
# Make sure that rowvar is either 0 or 1
|
| 1416 |
+
rowvar = int(bool(rowvar))
|
| 1417 |
+
axis = 1 - rowvar
|
| 1418 |
+
if rowvar:
|
| 1419 |
+
tup = (slice(None), None)
|
| 1420 |
+
else:
|
| 1421 |
+
tup = (None, slice(None))
|
| 1422 |
+
#
|
| 1423 |
+
if y is None:
|
| 1424 |
+
xnotmask = np.logical_not(xmask).astype(int)
|
| 1425 |
+
else:
|
| 1426 |
+
y = array(y, copy=False, ndmin=2, dtype=float)
|
| 1427 |
+
ymask = ma.getmaskarray(y)
|
| 1428 |
+
if not allow_masked and ymask.any():
|
| 1429 |
+
raise ValueError("Cannot process masked data.")
|
| 1430 |
+
if xmask.any() or ymask.any():
|
| 1431 |
+
if y.shape == x.shape:
|
| 1432 |
+
# Define some common mask
|
| 1433 |
+
common_mask = np.logical_or(xmask, ymask)
|
| 1434 |
+
if common_mask is not nomask:
|
| 1435 |
+
xmask = x._mask = y._mask = ymask = common_mask
|
| 1436 |
+
x._sharedmask = False
|
| 1437 |
+
y._sharedmask = False
|
| 1438 |
+
x = ma.concatenate((x, y), axis)
|
| 1439 |
+
xnotmask = np.logical_not(np.concatenate((xmask, ymask), axis)).astype(int)
|
| 1440 |
+
x -= x.mean(axis=rowvar)[tup]
|
| 1441 |
+
return (x, xnotmask, rowvar)
|
| 1442 |
+
|
| 1443 |
+
|
| 1444 |
+
def cov(x, y=None, rowvar=True, bias=False, allow_masked=True, ddof=None):
|
| 1445 |
+
"""
|
| 1446 |
+
Estimate the covariance matrix.
|
| 1447 |
+
|
| 1448 |
+
Except for the handling of missing data this function does the same as
|
| 1449 |
+
`numpy.cov`. For more details and examples, see `numpy.cov`.
|
| 1450 |
+
|
| 1451 |
+
By default, masked values are recognized as such. If `x` and `y` have the
|
| 1452 |
+
same shape, a common mask is allocated: if ``x[i,j]`` is masked, then
|
| 1453 |
+
``y[i,j]`` will also be masked.
|
| 1454 |
+
Setting `allow_masked` to False will raise an exception if values are
|
| 1455 |
+
missing in either of the input arrays.
|
| 1456 |
+
|
| 1457 |
+
Parameters
|
| 1458 |
+
----------
|
| 1459 |
+
x : array_like
|
| 1460 |
+
A 1-D or 2-D array containing multiple variables and observations.
|
| 1461 |
+
Each row of `x` represents a variable, and each column a single
|
| 1462 |
+
observation of all those variables. Also see `rowvar` below.
|
| 1463 |
+
y : array_like, optional
|
| 1464 |
+
An additional set of variables and observations. `y` has the same
|
| 1465 |
+
shape as `x`.
|
| 1466 |
+
rowvar : bool, optional
|
| 1467 |
+
If `rowvar` is True (default), then each row represents a
|
| 1468 |
+
variable, with observations in the columns. Otherwise, the relationship
|
| 1469 |
+
is transposed: each column represents a variable, while the rows
|
| 1470 |
+
contain observations.
|
| 1471 |
+
bias : bool, optional
|
| 1472 |
+
Default normalization (False) is by ``(N-1)``, where ``N`` is the
|
| 1473 |
+
number of observations given (unbiased estimate). If `bias` is True,
|
| 1474 |
+
then normalization is by ``N``. This keyword can be overridden by
|
| 1475 |
+
the keyword ``ddof`` in numpy versions >= 1.5.
|
| 1476 |
+
allow_masked : bool, optional
|
| 1477 |
+
If True, masked values are propagated pair-wise: if a value is masked
|
| 1478 |
+
in `x`, the corresponding value is masked in `y`.
|
| 1479 |
+
If False, raises a `ValueError` exception when some values are missing.
|
| 1480 |
+
ddof : {None, int}, optional
|
| 1481 |
+
If not ``None`` normalization is by ``(N - ddof)``, where ``N`` is
|
| 1482 |
+
the number of observations; this overrides the value implied by
|
| 1483 |
+
``bias``. The default value is ``None``.
|
| 1484 |
+
|
| 1485 |
+
.. versionadded:: 1.5
|
| 1486 |
+
|
| 1487 |
+
Raises
|
| 1488 |
+
------
|
| 1489 |
+
ValueError
|
| 1490 |
+
Raised if some values are missing and `allow_masked` is False.
|
| 1491 |
+
|
| 1492 |
+
See Also
|
| 1493 |
+
--------
|
| 1494 |
+
numpy.cov
|
| 1495 |
+
|
| 1496 |
+
"""
|
| 1497 |
+
# Check inputs
|
| 1498 |
+
if ddof is not None and ddof != int(ddof):
|
| 1499 |
+
raise ValueError("ddof must be an integer")
|
| 1500 |
+
# Set up ddof
|
| 1501 |
+
if ddof is None:
|
| 1502 |
+
if bias:
|
| 1503 |
+
ddof = 0
|
| 1504 |
+
else:
|
| 1505 |
+
ddof = 1
|
| 1506 |
+
|
| 1507 |
+
(x, xnotmask, rowvar) = _covhelper(x, y, rowvar, allow_masked)
|
| 1508 |
+
if not rowvar:
|
| 1509 |
+
fact = np.dot(xnotmask.T, xnotmask) * 1. - ddof
|
| 1510 |
+
result = (dot(x.T, x.conj(), strict=False) / fact).squeeze()
|
| 1511 |
+
else:
|
| 1512 |
+
fact = np.dot(xnotmask, xnotmask.T) * 1. - ddof
|
| 1513 |
+
result = (dot(x, x.T.conj(), strict=False) / fact).squeeze()
|
| 1514 |
+
return result
|
| 1515 |
+
|
| 1516 |
+
|
| 1517 |
+
def corrcoef(x, y=None, rowvar=True, bias=np._NoValue, allow_masked=True,
|
| 1518 |
+
ddof=np._NoValue):
|
| 1519 |
+
"""
|
| 1520 |
+
Return Pearson product-moment correlation coefficients.
|
| 1521 |
+
|
| 1522 |
+
Except for the handling of missing data this function does the same as
|
| 1523 |
+
`numpy.corrcoef`. For more details and examples, see `numpy.corrcoef`.
|
| 1524 |
+
|
| 1525 |
+
Parameters
|
| 1526 |
+
----------
|
| 1527 |
+
x : array_like
|
| 1528 |
+
A 1-D or 2-D array containing multiple variables and observations.
|
| 1529 |
+
Each row of `x` represents a variable, and each column a single
|
| 1530 |
+
observation of all those variables. Also see `rowvar` below.
|
| 1531 |
+
y : array_like, optional
|
| 1532 |
+
An additional set of variables and observations. `y` has the same
|
| 1533 |
+
shape as `x`.
|
| 1534 |
+
rowvar : bool, optional
|
| 1535 |
+
If `rowvar` is True (default), then each row represents a
|
| 1536 |
+
variable, with observations in the columns. Otherwise, the relationship
|
| 1537 |
+
is transposed: each column represents a variable, while the rows
|
| 1538 |
+
contain observations.
|
| 1539 |
+
bias : _NoValue, optional
|
| 1540 |
+
Has no effect, do not use.
|
| 1541 |
+
|
| 1542 |
+
.. deprecated:: 1.10.0
|
| 1543 |
+
allow_masked : bool, optional
|
| 1544 |
+
If True, masked values are propagated pair-wise: if a value is masked
|
| 1545 |
+
in `x`, the corresponding value is masked in `y`.
|
| 1546 |
+
If False, raises an exception. Because `bias` is deprecated, this
|
| 1547 |
+
argument needs to be treated as keyword only to avoid a warning.
|
| 1548 |
+
ddof : _NoValue, optional
|
| 1549 |
+
Has no effect, do not use.
|
| 1550 |
+
|
| 1551 |
+
.. deprecated:: 1.10.0
|
| 1552 |
+
|
| 1553 |
+
See Also
|
| 1554 |
+
--------
|
| 1555 |
+
numpy.corrcoef : Equivalent function in top-level NumPy module.
|
| 1556 |
+
cov : Estimate the covariance matrix.
|
| 1557 |
+
|
| 1558 |
+
Notes
|
| 1559 |
+
-----
|
| 1560 |
+
This function accepts but discards arguments `bias` and `ddof`. This is
|
| 1561 |
+
for backwards compatibility with previous versions of this function. These
|
| 1562 |
+
arguments had no effect on the return values of the function and can be
|
| 1563 |
+
safely ignored in this and previous versions of numpy.
|
| 1564 |
+
"""
|
| 1565 |
+
msg = 'bias and ddof have no effect and are deprecated'
|
| 1566 |
+
if bias is not np._NoValue or ddof is not np._NoValue:
|
| 1567 |
+
# 2015-03-15, 1.10
|
| 1568 |
+
warnings.warn(msg, DeprecationWarning, stacklevel=2)
|
| 1569 |
+
# Get the data
|
| 1570 |
+
(x, xnotmask, rowvar) = _covhelper(x, y, rowvar, allow_masked)
|
| 1571 |
+
# Compute the covariance matrix
|
| 1572 |
+
if not rowvar:
|
| 1573 |
+
fact = np.dot(xnotmask.T, xnotmask) * 1.
|
| 1574 |
+
c = (dot(x.T, x.conj(), strict=False) / fact).squeeze()
|
| 1575 |
+
else:
|
| 1576 |
+
fact = np.dot(xnotmask, xnotmask.T) * 1.
|
| 1577 |
+
c = (dot(x, x.T.conj(), strict=False) / fact).squeeze()
|
| 1578 |
+
# Check whether we have a scalar
|
| 1579 |
+
try:
|
| 1580 |
+
diag = ma.diagonal(c)
|
| 1581 |
+
except ValueError:
|
| 1582 |
+
return 1
|
| 1583 |
+
#
|
| 1584 |
+
if xnotmask.all():
|
| 1585 |
+
_denom = ma.sqrt(ma.multiply.outer(diag, diag))
|
| 1586 |
+
else:
|
| 1587 |
+
_denom = diagflat(diag)
|
| 1588 |
+
_denom._sharedmask = False # We know return is always a copy
|
| 1589 |
+
n = x.shape[1 - rowvar]
|
| 1590 |
+
if rowvar:
|
| 1591 |
+
for i in range(n - 1):
|
| 1592 |
+
for j in range(i + 1, n):
|
| 1593 |
+
_x = mask_cols(vstack((x[i], x[j]))).var(axis=1)
|
| 1594 |
+
_denom[i, j] = _denom[j, i] = ma.sqrt(ma.multiply.reduce(_x))
|
| 1595 |
+
else:
|
| 1596 |
+
for i in range(n - 1):
|
| 1597 |
+
for j in range(i + 1, n):
|
| 1598 |
+
_x = mask_cols(
|
| 1599 |
+
vstack((x[:, i], x[:, j]))).var(axis=1)
|
| 1600 |
+
_denom[i, j] = _denom[j, i] = ma.sqrt(ma.multiply.reduce(_x))
|
| 1601 |
+
return c / _denom
|
| 1602 |
+
|
| 1603 |
+
#####--------------------------------------------------------------------------
|
| 1604 |
+
#---- --- Concatenation helpers ---
|
| 1605 |
+
#####--------------------------------------------------------------------------
|
| 1606 |
+
|
| 1607 |
+
class MAxisConcatenator(AxisConcatenator):
|
| 1608 |
+
"""
|
| 1609 |
+
Translate slice objects to concatenation along an axis.
|
| 1610 |
+
|
| 1611 |
+
For documentation on usage, see `mr_class`.
|
| 1612 |
+
|
| 1613 |
+
See Also
|
| 1614 |
+
--------
|
| 1615 |
+
mr_class
|
| 1616 |
+
|
| 1617 |
+
"""
|
| 1618 |
+
concatenate = staticmethod(concatenate)
|
| 1619 |
+
|
| 1620 |
+
@classmethod
|
| 1621 |
+
def makemat(cls, arr):
|
| 1622 |
+
# There used to be a view as np.matrix here, but we may eventually
|
| 1623 |
+
# deprecate that class. In preparation, we use the unmasked version
|
| 1624 |
+
# to construct the matrix (with copy=False for backwards compatibility
|
| 1625 |
+
# with the .view)
|
| 1626 |
+
data = super().makemat(arr.data, copy=False)
|
| 1627 |
+
return array(data, mask=arr.mask)
|
| 1628 |
+
|
| 1629 |
+
def __getitem__(self, key):
|
| 1630 |
+
# matrix builder syntax, like 'a, b; c, d'
|
| 1631 |
+
if isinstance(key, str):
|
| 1632 |
+
raise MAError("Unavailable for masked array.")
|
| 1633 |
+
|
| 1634 |
+
return super().__getitem__(key)
|
| 1635 |
+
|
| 1636 |
+
|
| 1637 |
+
class mr_class(MAxisConcatenator):
|
| 1638 |
+
"""
|
| 1639 |
+
Translate slice objects to concatenation along the first axis.
|
| 1640 |
+
|
| 1641 |
+
This is the masked array version of `lib.index_tricks.RClass`.
|
| 1642 |
+
|
| 1643 |
+
See Also
|
| 1644 |
+
--------
|
| 1645 |
+
lib.index_tricks.RClass
|
| 1646 |
+
|
| 1647 |
+
Examples
|
| 1648 |
+
--------
|
| 1649 |
+
>>> np.ma.mr_[np.ma.array([1,2,3]), 0, 0, np.ma.array([4,5,6])]
|
| 1650 |
+
masked_array(data=[1, 2, 3, ..., 4, 5, 6],
|
| 1651 |
+
mask=False,
|
| 1652 |
+
fill_value=999999)
|
| 1653 |
+
|
| 1654 |
+
"""
|
| 1655 |
+
def __init__(self):
|
| 1656 |
+
MAxisConcatenator.__init__(self, 0)
|
| 1657 |
+
|
| 1658 |
+
mr_ = mr_class()
|
| 1659 |
+
|
| 1660 |
+
|
| 1661 |
+
#####--------------------------------------------------------------------------
|
| 1662 |
+
#---- Find unmasked data ---
|
| 1663 |
+
#####--------------------------------------------------------------------------
|
| 1664 |
+
|
| 1665 |
+
def ndenumerate(a, compressed=True):
|
| 1666 |
+
"""
|
| 1667 |
+
Multidimensional index iterator.
|
| 1668 |
+
|
| 1669 |
+
Return an iterator yielding pairs of array coordinates and values,
|
| 1670 |
+
skipping elements that are masked. With `compressed=False`,
|
| 1671 |
+
`ma.masked` is yielded as the value of masked elements. This
|
| 1672 |
+
behavior differs from that of `numpy.ndenumerate`, which yields the
|
| 1673 |
+
value of the underlying data array.
|
| 1674 |
+
|
| 1675 |
+
Notes
|
| 1676 |
+
-----
|
| 1677 |
+
.. versionadded:: 1.23.0
|
| 1678 |
+
|
| 1679 |
+
Parameters
|
| 1680 |
+
----------
|
| 1681 |
+
a : array_like
|
| 1682 |
+
An array with (possibly) masked elements.
|
| 1683 |
+
compressed : bool, optional
|
| 1684 |
+
If True (default), masked elements are skipped.
|
| 1685 |
+
|
| 1686 |
+
See Also
|
| 1687 |
+
--------
|
| 1688 |
+
numpy.ndenumerate : Equivalent function ignoring any mask.
|
| 1689 |
+
|
| 1690 |
+
Examples
|
| 1691 |
+
--------
|
| 1692 |
+
>>> a = np.ma.arange(9).reshape((3, 3))
|
| 1693 |
+
>>> a[1, 0] = np.ma.masked
|
| 1694 |
+
>>> a[1, 2] = np.ma.masked
|
| 1695 |
+
>>> a[2, 1] = np.ma.masked
|
| 1696 |
+
>>> a
|
| 1697 |
+
masked_array(
|
| 1698 |
+
data=[[0, 1, 2],
|
| 1699 |
+
[--, 4, --],
|
| 1700 |
+
[6, --, 8]],
|
| 1701 |
+
mask=[[False, False, False],
|
| 1702 |
+
[ True, False, True],
|
| 1703 |
+
[False, True, False]],
|
| 1704 |
+
fill_value=999999)
|
| 1705 |
+
>>> for index, x in np.ma.ndenumerate(a):
|
| 1706 |
+
... print(index, x)
|
| 1707 |
+
(0, 0) 0
|
| 1708 |
+
(0, 1) 1
|
| 1709 |
+
(0, 2) 2
|
| 1710 |
+
(1, 1) 4
|
| 1711 |
+
(2, 0) 6
|
| 1712 |
+
(2, 2) 8
|
| 1713 |
+
|
| 1714 |
+
>>> for index, x in np.ma.ndenumerate(a, compressed=False):
|
| 1715 |
+
... print(index, x)
|
| 1716 |
+
(0, 0) 0
|
| 1717 |
+
(0, 1) 1
|
| 1718 |
+
(0, 2) 2
|
| 1719 |
+
(1, 0) --
|
| 1720 |
+
(1, 1) 4
|
| 1721 |
+
(1, 2) --
|
| 1722 |
+
(2, 0) 6
|
| 1723 |
+
(2, 1) --
|
| 1724 |
+
(2, 2) 8
|
| 1725 |
+
"""
|
| 1726 |
+
for it, mask in zip(np.ndenumerate(a), getmaskarray(a).flat):
|
| 1727 |
+
if not mask:
|
| 1728 |
+
yield it
|
| 1729 |
+
elif not compressed:
|
| 1730 |
+
yield it[0], masked
|
| 1731 |
+
|
| 1732 |
+
|
| 1733 |
+
def flatnotmasked_edges(a):
|
| 1734 |
+
"""
|
| 1735 |
+
Find the indices of the first and last unmasked values.
|
| 1736 |
+
|
| 1737 |
+
Expects a 1-D `MaskedArray`, returns None if all values are masked.
|
| 1738 |
+
|
| 1739 |
+
Parameters
|
| 1740 |
+
----------
|
| 1741 |
+
a : array_like
|
| 1742 |
+
Input 1-D `MaskedArray`
|
| 1743 |
+
|
| 1744 |
+
Returns
|
| 1745 |
+
-------
|
| 1746 |
+
edges : ndarray or None
|
| 1747 |
+
The indices of first and last non-masked value in the array.
|
| 1748 |
+
Returns None if all values are masked.
|
| 1749 |
+
|
| 1750 |
+
See Also
|
| 1751 |
+
--------
|
| 1752 |
+
flatnotmasked_contiguous, notmasked_contiguous, notmasked_edges
|
| 1753 |
+
clump_masked, clump_unmasked
|
| 1754 |
+
|
| 1755 |
+
Notes
|
| 1756 |
+
-----
|
| 1757 |
+
Only accepts 1-D arrays.
|
| 1758 |
+
|
| 1759 |
+
Examples
|
| 1760 |
+
--------
|
| 1761 |
+
>>> a = np.ma.arange(10)
|
| 1762 |
+
>>> np.ma.flatnotmasked_edges(a)
|
| 1763 |
+
array([0, 9])
|
| 1764 |
+
|
| 1765 |
+
>>> mask = (a < 3) | (a > 8) | (a == 5)
|
| 1766 |
+
>>> a[mask] = np.ma.masked
|
| 1767 |
+
>>> np.array(a[~a.mask])
|
| 1768 |
+
array([3, 4, 6, 7, 8])
|
| 1769 |
+
|
| 1770 |
+
>>> np.ma.flatnotmasked_edges(a)
|
| 1771 |
+
array([3, 8])
|
| 1772 |
+
|
| 1773 |
+
>>> a[:] = np.ma.masked
|
| 1774 |
+
>>> print(np.ma.flatnotmasked_edges(a))
|
| 1775 |
+
None
|
| 1776 |
+
|
| 1777 |
+
"""
|
| 1778 |
+
m = getmask(a)
|
| 1779 |
+
if m is nomask or not np.any(m):
|
| 1780 |
+
return np.array([0, a.size - 1])
|
| 1781 |
+
unmasked = np.flatnonzero(~m)
|
| 1782 |
+
if len(unmasked) > 0:
|
| 1783 |
+
return unmasked[[0, -1]]
|
| 1784 |
+
else:
|
| 1785 |
+
return None
|
| 1786 |
+
|
| 1787 |
+
|
| 1788 |
+
def notmasked_edges(a, axis=None):
|
| 1789 |
+
"""
|
| 1790 |
+
Find the indices of the first and last unmasked values along an axis.
|
| 1791 |
+
|
| 1792 |
+
If all values are masked, return None. Otherwise, return a list
|
| 1793 |
+
of two tuples, corresponding to the indices of the first and last
|
| 1794 |
+
unmasked values respectively.
|
| 1795 |
+
|
| 1796 |
+
Parameters
|
| 1797 |
+
----------
|
| 1798 |
+
a : array_like
|
| 1799 |
+
The input array.
|
| 1800 |
+
axis : int, optional
|
| 1801 |
+
Axis along which to perform the operation.
|
| 1802 |
+
If None (default), applies to a flattened version of the array.
|
| 1803 |
+
|
| 1804 |
+
Returns
|
| 1805 |
+
-------
|
| 1806 |
+
edges : ndarray or list
|
| 1807 |
+
An array of start and end indexes if there are any masked data in
|
| 1808 |
+
the array. If there are no masked data in the array, `edges` is a
|
| 1809 |
+
list of the first and last index.
|
| 1810 |
+
|
| 1811 |
+
See Also
|
| 1812 |
+
--------
|
| 1813 |
+
flatnotmasked_contiguous, flatnotmasked_edges, notmasked_contiguous
|
| 1814 |
+
clump_masked, clump_unmasked
|
| 1815 |
+
|
| 1816 |
+
Examples
|
| 1817 |
+
--------
|
| 1818 |
+
>>> a = np.arange(9).reshape((3, 3))
|
| 1819 |
+
>>> m = np.zeros_like(a)
|
| 1820 |
+
>>> m[1:, 1:] = 1
|
| 1821 |
+
|
| 1822 |
+
>>> am = np.ma.array(a, mask=m)
|
| 1823 |
+
>>> np.array(am[~am.mask])
|
| 1824 |
+
array([0, 1, 2, 3, 6])
|
| 1825 |
+
|
| 1826 |
+
>>> np.ma.notmasked_edges(am)
|
| 1827 |
+
array([0, 6])
|
| 1828 |
+
|
| 1829 |
+
"""
|
| 1830 |
+
a = asarray(a)
|
| 1831 |
+
if axis is None or a.ndim == 1:
|
| 1832 |
+
return flatnotmasked_edges(a)
|
| 1833 |
+
m = getmaskarray(a)
|
| 1834 |
+
idx = array(np.indices(a.shape), mask=np.asarray([m] * a.ndim))
|
| 1835 |
+
return [tuple([idx[i].min(axis).compressed() for i in range(a.ndim)]),
|
| 1836 |
+
tuple([idx[i].max(axis).compressed() for i in range(a.ndim)]), ]
|
| 1837 |
+
|
| 1838 |
+
|
| 1839 |
+
def flatnotmasked_contiguous(a):
|
| 1840 |
+
"""
|
| 1841 |
+
Find contiguous unmasked data in a masked array.
|
| 1842 |
+
|
| 1843 |
+
Parameters
|
| 1844 |
+
----------
|
| 1845 |
+
a : array_like
|
| 1846 |
+
The input array.
|
| 1847 |
+
|
| 1848 |
+
Returns
|
| 1849 |
+
-------
|
| 1850 |
+
slice_list : list
|
| 1851 |
+
A sorted sequence of `slice` objects (start index, end index).
|
| 1852 |
+
|
| 1853 |
+
.. versionchanged:: 1.15.0
|
| 1854 |
+
Now returns an empty list instead of None for a fully masked array
|
| 1855 |
+
|
| 1856 |
+
See Also
|
| 1857 |
+
--------
|
| 1858 |
+
flatnotmasked_edges, notmasked_contiguous, notmasked_edges
|
| 1859 |
+
clump_masked, clump_unmasked
|
| 1860 |
+
|
| 1861 |
+
Notes
|
| 1862 |
+
-----
|
| 1863 |
+
Only accepts 2-D arrays at most.
|
| 1864 |
+
|
| 1865 |
+
Examples
|
| 1866 |
+
--------
|
| 1867 |
+
>>> a = np.ma.arange(10)
|
| 1868 |
+
>>> np.ma.flatnotmasked_contiguous(a)
|
| 1869 |
+
[slice(0, 10, None)]
|
| 1870 |
+
|
| 1871 |
+
>>> mask = (a < 3) | (a > 8) | (a == 5)
|
| 1872 |
+
>>> a[mask] = np.ma.masked
|
| 1873 |
+
>>> np.array(a[~a.mask])
|
| 1874 |
+
array([3, 4, 6, 7, 8])
|
| 1875 |
+
|
| 1876 |
+
>>> np.ma.flatnotmasked_contiguous(a)
|
| 1877 |
+
[slice(3, 5, None), slice(6, 9, None)]
|
| 1878 |
+
>>> a[:] = np.ma.masked
|
| 1879 |
+
>>> np.ma.flatnotmasked_contiguous(a)
|
| 1880 |
+
[]
|
| 1881 |
+
|
| 1882 |
+
"""
|
| 1883 |
+
m = getmask(a)
|
| 1884 |
+
if m is nomask:
|
| 1885 |
+
return [slice(0, a.size)]
|
| 1886 |
+
i = 0
|
| 1887 |
+
result = []
|
| 1888 |
+
for (k, g) in itertools.groupby(m.ravel()):
|
| 1889 |
+
n = len(list(g))
|
| 1890 |
+
if not k:
|
| 1891 |
+
result.append(slice(i, i + n))
|
| 1892 |
+
i += n
|
| 1893 |
+
return result
|
| 1894 |
+
|
| 1895 |
+
|
| 1896 |
+
def notmasked_contiguous(a, axis=None):
|
| 1897 |
+
"""
|
| 1898 |
+
Find contiguous unmasked data in a masked array along the given axis.
|
| 1899 |
+
|
| 1900 |
+
Parameters
|
| 1901 |
+
----------
|
| 1902 |
+
a : array_like
|
| 1903 |
+
The input array.
|
| 1904 |
+
axis : int, optional
|
| 1905 |
+
Axis along which to perform the operation.
|
| 1906 |
+
If None (default), applies to a flattened version of the array, and this
|
| 1907 |
+
is the same as `flatnotmasked_contiguous`.
|
| 1908 |
+
|
| 1909 |
+
Returns
|
| 1910 |
+
-------
|
| 1911 |
+
endpoints : list
|
| 1912 |
+
A list of slices (start and end indexes) of unmasked indexes
|
| 1913 |
+
in the array.
|
| 1914 |
+
|
| 1915 |
+
If the input is 2d and axis is specified, the result is a list of lists.
|
| 1916 |
+
|
| 1917 |
+
See Also
|
| 1918 |
+
--------
|
| 1919 |
+
flatnotmasked_edges, flatnotmasked_contiguous, notmasked_edges
|
| 1920 |
+
clump_masked, clump_unmasked
|
| 1921 |
+
|
| 1922 |
+
Notes
|
| 1923 |
+
-----
|
| 1924 |
+
Only accepts 2-D arrays at most.
|
| 1925 |
+
|
| 1926 |
+
Examples
|
| 1927 |
+
--------
|
| 1928 |
+
>>> a = np.arange(12).reshape((3, 4))
|
| 1929 |
+
>>> mask = np.zeros_like(a)
|
| 1930 |
+
>>> mask[1:, :-1] = 1; mask[0, 1] = 1; mask[-1, 0] = 0
|
| 1931 |
+
>>> ma = np.ma.array(a, mask=mask)
|
| 1932 |
+
>>> ma
|
| 1933 |
+
masked_array(
|
| 1934 |
+
data=[[0, --, 2, 3],
|
| 1935 |
+
[--, --, --, 7],
|
| 1936 |
+
[8, --, --, 11]],
|
| 1937 |
+
mask=[[False, True, False, False],
|
| 1938 |
+
[ True, True, True, False],
|
| 1939 |
+
[False, True, True, False]],
|
| 1940 |
+
fill_value=999999)
|
| 1941 |
+
>>> np.array(ma[~ma.mask])
|
| 1942 |
+
array([ 0, 2, 3, 7, 8, 11])
|
| 1943 |
+
|
| 1944 |
+
>>> np.ma.notmasked_contiguous(ma)
|
| 1945 |
+
[slice(0, 1, None), slice(2, 4, None), slice(7, 9, None), slice(11, 12, None)]
|
| 1946 |
+
|
| 1947 |
+
>>> np.ma.notmasked_contiguous(ma, axis=0)
|
| 1948 |
+
[[slice(0, 1, None), slice(2, 3, None)], [], [slice(0, 1, None)], [slice(0, 3, None)]]
|
| 1949 |
+
|
| 1950 |
+
>>> np.ma.notmasked_contiguous(ma, axis=1)
|
| 1951 |
+
[[slice(0, 1, None), slice(2, 4, None)], [slice(3, 4, None)], [slice(0, 1, None), slice(3, 4, None)]]
|
| 1952 |
+
|
| 1953 |
+
"""
|
| 1954 |
+
a = asarray(a)
|
| 1955 |
+
nd = a.ndim
|
| 1956 |
+
if nd > 2:
|
| 1957 |
+
raise NotImplementedError("Currently limited to at most 2D array.")
|
| 1958 |
+
if axis is None or nd == 1:
|
| 1959 |
+
return flatnotmasked_contiguous(a)
|
| 1960 |
+
#
|
| 1961 |
+
result = []
|
| 1962 |
+
#
|
| 1963 |
+
other = (axis + 1) % 2
|
| 1964 |
+
idx = [0, 0]
|
| 1965 |
+
idx[axis] = slice(None, None)
|
| 1966 |
+
#
|
| 1967 |
+
for i in range(a.shape[other]):
|
| 1968 |
+
idx[other] = i
|
| 1969 |
+
result.append(flatnotmasked_contiguous(a[tuple(idx)]))
|
| 1970 |
+
return result
|
| 1971 |
+
|
| 1972 |
+
|
| 1973 |
+
def _ezclump(mask):
|
| 1974 |
+
"""
|
| 1975 |
+
Finds the clumps (groups of data with the same values) for a 1D bool array.
|
| 1976 |
+
|
| 1977 |
+
Returns a series of slices.
|
| 1978 |
+
"""
|
| 1979 |
+
if mask.ndim > 1:
|
| 1980 |
+
mask = mask.ravel()
|
| 1981 |
+
idx = (mask[1:] ^ mask[:-1]).nonzero()
|
| 1982 |
+
idx = idx[0] + 1
|
| 1983 |
+
|
| 1984 |
+
if mask[0]:
|
| 1985 |
+
if len(idx) == 0:
|
| 1986 |
+
return [slice(0, mask.size)]
|
| 1987 |
+
|
| 1988 |
+
r = [slice(0, idx[0])]
|
| 1989 |
+
r.extend((slice(left, right)
|
| 1990 |
+
for left, right in zip(idx[1:-1:2], idx[2::2])))
|
| 1991 |
+
else:
|
| 1992 |
+
if len(idx) == 0:
|
| 1993 |
+
return []
|
| 1994 |
+
|
| 1995 |
+
r = [slice(left, right) for left, right in zip(idx[:-1:2], idx[1::2])]
|
| 1996 |
+
|
| 1997 |
+
if mask[-1]:
|
| 1998 |
+
r.append(slice(idx[-1], mask.size))
|
| 1999 |
+
return r
|
| 2000 |
+
|
| 2001 |
+
|
| 2002 |
+
def clump_unmasked(a):
|
| 2003 |
+
"""
|
| 2004 |
+
Return list of slices corresponding to the unmasked clumps of a 1-D array.
|
| 2005 |
+
(A "clump" is defined as a contiguous region of the array).
|
| 2006 |
+
|
| 2007 |
+
Parameters
|
| 2008 |
+
----------
|
| 2009 |
+
a : ndarray
|
| 2010 |
+
A one-dimensional masked array.
|
| 2011 |
+
|
| 2012 |
+
Returns
|
| 2013 |
+
-------
|
| 2014 |
+
slices : list of slice
|
| 2015 |
+
The list of slices, one for each continuous region of unmasked
|
| 2016 |
+
elements in `a`.
|
| 2017 |
+
|
| 2018 |
+
Notes
|
| 2019 |
+
-----
|
| 2020 |
+
.. versionadded:: 1.4.0
|
| 2021 |
+
|
| 2022 |
+
See Also
|
| 2023 |
+
--------
|
| 2024 |
+
flatnotmasked_edges, flatnotmasked_contiguous, notmasked_edges
|
| 2025 |
+
notmasked_contiguous, clump_masked
|
| 2026 |
+
|
| 2027 |
+
Examples
|
| 2028 |
+
--------
|
| 2029 |
+
>>> a = np.ma.masked_array(np.arange(10))
|
| 2030 |
+
>>> a[[0, 1, 2, 6, 8, 9]] = np.ma.masked
|
| 2031 |
+
>>> np.ma.clump_unmasked(a)
|
| 2032 |
+
[slice(3, 6, None), slice(7, 8, None)]
|
| 2033 |
+
|
| 2034 |
+
"""
|
| 2035 |
+
mask = getattr(a, '_mask', nomask)
|
| 2036 |
+
if mask is nomask:
|
| 2037 |
+
return [slice(0, a.size)]
|
| 2038 |
+
return _ezclump(~mask)
|
| 2039 |
+
|
| 2040 |
+
|
| 2041 |
+
def clump_masked(a):
|
| 2042 |
+
"""
|
| 2043 |
+
Returns a list of slices corresponding to the masked clumps of a 1-D array.
|
| 2044 |
+
(A "clump" is defined as a contiguous region of the array).
|
| 2045 |
+
|
| 2046 |
+
Parameters
|
| 2047 |
+
----------
|
| 2048 |
+
a : ndarray
|
| 2049 |
+
A one-dimensional masked array.
|
| 2050 |
+
|
| 2051 |
+
Returns
|
| 2052 |
+
-------
|
| 2053 |
+
slices : list of slice
|
| 2054 |
+
The list of slices, one for each continuous region of masked elements
|
| 2055 |
+
in `a`.
|
| 2056 |
+
|
| 2057 |
+
Notes
|
| 2058 |
+
-----
|
| 2059 |
+
.. versionadded:: 1.4.0
|
| 2060 |
+
|
| 2061 |
+
See Also
|
| 2062 |
+
--------
|
| 2063 |
+
flatnotmasked_edges, flatnotmasked_contiguous, notmasked_edges
|
| 2064 |
+
notmasked_contiguous, clump_unmasked
|
| 2065 |
+
|
| 2066 |
+
Examples
|
| 2067 |
+
--------
|
| 2068 |
+
>>> a = np.ma.masked_array(np.arange(10))
|
| 2069 |
+
>>> a[[0, 1, 2, 6, 8, 9]] = np.ma.masked
|
| 2070 |
+
>>> np.ma.clump_masked(a)
|
| 2071 |
+
[slice(0, 3, None), slice(6, 7, None), slice(8, 10, None)]
|
| 2072 |
+
|
| 2073 |
+
"""
|
| 2074 |
+
mask = ma.getmask(a)
|
| 2075 |
+
if mask is nomask:
|
| 2076 |
+
return []
|
| 2077 |
+
return _ezclump(mask)
|
| 2078 |
+
|
| 2079 |
+
|
| 2080 |
+
###############################################################################
|
| 2081 |
+
# Polynomial fit #
|
| 2082 |
+
###############################################################################
|
| 2083 |
+
|
| 2084 |
+
|
| 2085 |
+
def vander(x, n=None):
|
| 2086 |
+
"""
|
| 2087 |
+
Masked values in the input array result in rows of zeros.
|
| 2088 |
+
|
| 2089 |
+
"""
|
| 2090 |
+
_vander = np.vander(x, n)
|
| 2091 |
+
m = getmask(x)
|
| 2092 |
+
if m is not nomask:
|
| 2093 |
+
_vander[m] = 0
|
| 2094 |
+
return _vander
|
| 2095 |
+
|
| 2096 |
+
vander.__doc__ = ma.doc_note(np.vander.__doc__, vander.__doc__)
|
| 2097 |
+
|
| 2098 |
+
|
| 2099 |
+
def polyfit(x, y, deg, rcond=None, full=False, w=None, cov=False):
|
| 2100 |
+
"""
|
| 2101 |
+
Any masked values in x is propagated in y, and vice-versa.
|
| 2102 |
+
|
| 2103 |
+
"""
|
| 2104 |
+
x = asarray(x)
|
| 2105 |
+
y = asarray(y)
|
| 2106 |
+
|
| 2107 |
+
m = getmask(x)
|
| 2108 |
+
if y.ndim == 1:
|
| 2109 |
+
m = mask_or(m, getmask(y))
|
| 2110 |
+
elif y.ndim == 2:
|
| 2111 |
+
my = getmask(mask_rows(y))
|
| 2112 |
+
if my is not nomask:
|
| 2113 |
+
m = mask_or(m, my[:, 0])
|
| 2114 |
+
else:
|
| 2115 |
+
raise TypeError("Expected a 1D or 2D array for y!")
|
| 2116 |
+
|
| 2117 |
+
if w is not None:
|
| 2118 |
+
w = asarray(w)
|
| 2119 |
+
if w.ndim != 1:
|
| 2120 |
+
raise TypeError("expected a 1-d array for weights")
|
| 2121 |
+
if w.shape[0] != y.shape[0]:
|
| 2122 |
+
raise TypeError("expected w and y to have the same length")
|
| 2123 |
+
m = mask_or(m, getmask(w))
|
| 2124 |
+
|
| 2125 |
+
if m is not nomask:
|
| 2126 |
+
not_m = ~m
|
| 2127 |
+
if w is not None:
|
| 2128 |
+
w = w[not_m]
|
| 2129 |
+
return np.polyfit(x[not_m], y[not_m], deg, rcond, full, w, cov)
|
| 2130 |
+
else:
|
| 2131 |
+
return np.polyfit(x, y, deg, rcond, full, w, cov)
|
| 2132 |
+
|
| 2133 |
+
polyfit.__doc__ = ma.doc_note(np.polyfit.__doc__, polyfit.__doc__)
|
LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/numpy/ma/extras.pyi
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from typing import Any
|
| 2 |
+
from numpy.lib.index_tricks import AxisConcatenator
|
| 3 |
+
|
| 4 |
+
from numpy.ma.core import (
|
| 5 |
+
dot as dot,
|
| 6 |
+
mask_rowcols as mask_rowcols,
|
| 7 |
+
)
|
| 8 |
+
|
| 9 |
+
__all__: list[str]
|
| 10 |
+
|
| 11 |
+
def count_masked(arr, axis=...): ...
|
| 12 |
+
def masked_all(shape, dtype = ...): ...
|
| 13 |
+
def masked_all_like(arr): ...
|
| 14 |
+
|
| 15 |
+
class _fromnxfunction:
|
| 16 |
+
__name__: Any
|
| 17 |
+
__doc__: Any
|
| 18 |
+
def __init__(self, funcname): ...
|
| 19 |
+
def getdoc(self): ...
|
| 20 |
+
def __call__(self, *args, **params): ...
|
| 21 |
+
|
| 22 |
+
class _fromnxfunction_single(_fromnxfunction):
|
| 23 |
+
def __call__(self, x, *args, **params): ...
|
| 24 |
+
|
| 25 |
+
class _fromnxfunction_seq(_fromnxfunction):
|
| 26 |
+
def __call__(self, x, *args, **params): ...
|
| 27 |
+
|
| 28 |
+
class _fromnxfunction_allargs(_fromnxfunction):
|
| 29 |
+
def __call__(self, *args, **params): ...
|
| 30 |
+
|
| 31 |
+
atleast_1d: _fromnxfunction_allargs
|
| 32 |
+
atleast_2d: _fromnxfunction_allargs
|
| 33 |
+
atleast_3d: _fromnxfunction_allargs
|
| 34 |
+
|
| 35 |
+
vstack: _fromnxfunction_seq
|
| 36 |
+
row_stack: _fromnxfunction_seq
|
| 37 |
+
hstack: _fromnxfunction_seq
|
| 38 |
+
column_stack: _fromnxfunction_seq
|
| 39 |
+
dstack: _fromnxfunction_seq
|
| 40 |
+
stack: _fromnxfunction_seq
|
| 41 |
+
|
| 42 |
+
hsplit: _fromnxfunction_single
|
| 43 |
+
diagflat: _fromnxfunction_single
|
| 44 |
+
|
| 45 |
+
def apply_along_axis(func1d, axis, arr, *args, **kwargs): ...
|
| 46 |
+
def apply_over_axes(func, a, axes): ...
|
| 47 |
+
def average(a, axis=..., weights=..., returned=..., keepdims=...): ...
|
| 48 |
+
def median(a, axis=..., out=..., overwrite_input=..., keepdims=...): ...
|
| 49 |
+
def compress_nd(x, axis=...): ...
|
| 50 |
+
def compress_rowcols(x, axis=...): ...
|
| 51 |
+
def compress_rows(a): ...
|
| 52 |
+
def compress_cols(a): ...
|
| 53 |
+
def mask_rows(a, axis = ...): ...
|
| 54 |
+
def mask_cols(a, axis = ...): ...
|
| 55 |
+
def ediff1d(arr, to_end=..., to_begin=...): ...
|
| 56 |
+
def unique(ar1, return_index=..., return_inverse=...): ...
|
| 57 |
+
def intersect1d(ar1, ar2, assume_unique=...): ...
|
| 58 |
+
def setxor1d(ar1, ar2, assume_unique=...): ...
|
| 59 |
+
def in1d(ar1, ar2, assume_unique=..., invert=...): ...
|
| 60 |
+
def isin(element, test_elements, assume_unique=..., invert=...): ...
|
| 61 |
+
def union1d(ar1, ar2): ...
|
| 62 |
+
def setdiff1d(ar1, ar2, assume_unique=...): ...
|
| 63 |
+
def cov(x, y=..., rowvar=..., bias=..., allow_masked=..., ddof=...): ...
|
| 64 |
+
def corrcoef(x, y=..., rowvar=..., bias = ..., allow_masked=..., ddof = ...): ...
|
| 65 |
+
|
| 66 |
+
class MAxisConcatenator(AxisConcatenator):
|
| 67 |
+
concatenate: Any
|
| 68 |
+
@classmethod
|
| 69 |
+
def makemat(cls, arr): ...
|
| 70 |
+
def __getitem__(self, key): ...
|
| 71 |
+
|
| 72 |
+
class mr_class(MAxisConcatenator):
|
| 73 |
+
def __init__(self): ...
|
| 74 |
+
|
| 75 |
+
mr_: mr_class
|
| 76 |
+
|
| 77 |
+
def ndenumerate(a, compressed=...): ...
|
| 78 |
+
def flatnotmasked_edges(a): ...
|
| 79 |
+
def notmasked_edges(a, axis=...): ...
|
| 80 |
+
def flatnotmasked_contiguous(a): ...
|
| 81 |
+
def notmasked_contiguous(a, axis=...): ...
|
| 82 |
+
def clump_unmasked(a): ...
|
| 83 |
+
def clump_masked(a): ...
|
| 84 |
+
def vander(x, n=...): ...
|
| 85 |
+
def polyfit(x, y, deg, rcond=..., full=..., w=..., cov=...): ...
|
LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/numpy/ma/mrecords.py
ADDED
|
@@ -0,0 +1,783 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
""":mod:`numpy.ma..mrecords`
|
| 2 |
+
|
| 3 |
+
Defines the equivalent of :class:`numpy.recarrays` for masked arrays,
|
| 4 |
+
where fields can be accessed as attributes.
|
| 5 |
+
Note that :class:`numpy.ma.MaskedArray` already supports structured datatypes
|
| 6 |
+
and the masking of individual fields.
|
| 7 |
+
|
| 8 |
+
.. moduleauthor:: Pierre Gerard-Marchant
|
| 9 |
+
|
| 10 |
+
"""
|
| 11 |
+
# We should make sure that no field is called '_mask','mask','_fieldmask',
|
| 12 |
+
# or whatever restricted keywords. An idea would be to no bother in the
|
| 13 |
+
# first place, and then rename the invalid fields with a trailing
|
| 14 |
+
# underscore. Maybe we could just overload the parser function ?
|
| 15 |
+
|
| 16 |
+
from numpy.ma import (
|
| 17 |
+
MAError, MaskedArray, masked, nomask, masked_array, getdata,
|
| 18 |
+
getmaskarray, filled
|
| 19 |
+
)
|
| 20 |
+
import numpy.ma as ma
|
| 21 |
+
import warnings
|
| 22 |
+
|
| 23 |
+
import numpy as np
|
| 24 |
+
from numpy import (
|
| 25 |
+
bool_, dtype, ndarray, recarray, array as narray
|
| 26 |
+
)
|
| 27 |
+
from numpy.core.records import (
|
| 28 |
+
fromarrays as recfromarrays, fromrecords as recfromrecords
|
| 29 |
+
)
|
| 30 |
+
|
| 31 |
+
_byteorderconv = np.core.records._byteorderconv
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
_check_fill_value = ma.core._check_fill_value
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
__all__ = [
|
| 38 |
+
'MaskedRecords', 'mrecarray', 'fromarrays', 'fromrecords',
|
| 39 |
+
'fromtextfile', 'addfield',
|
| 40 |
+
]
|
| 41 |
+
|
| 42 |
+
reserved_fields = ['_data', '_mask', '_fieldmask', 'dtype']
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
def _checknames(descr, names=None):
|
| 46 |
+
"""
|
| 47 |
+
Checks that field names ``descr`` are not reserved keywords.
|
| 48 |
+
|
| 49 |
+
If this is the case, a default 'f%i' is substituted. If the argument
|
| 50 |
+
`names` is not None, updates the field names to valid names.
|
| 51 |
+
|
| 52 |
+
"""
|
| 53 |
+
ndescr = len(descr)
|
| 54 |
+
default_names = ['f%i' % i for i in range(ndescr)]
|
| 55 |
+
if names is None:
|
| 56 |
+
new_names = default_names
|
| 57 |
+
else:
|
| 58 |
+
if isinstance(names, (tuple, list)):
|
| 59 |
+
new_names = names
|
| 60 |
+
elif isinstance(names, str):
|
| 61 |
+
new_names = names.split(',')
|
| 62 |
+
else:
|
| 63 |
+
raise NameError(f'illegal input names {names!r}')
|
| 64 |
+
nnames = len(new_names)
|
| 65 |
+
if nnames < ndescr:
|
| 66 |
+
new_names += default_names[nnames:]
|
| 67 |
+
ndescr = []
|
| 68 |
+
for (n, d, t) in zip(new_names, default_names, descr.descr):
|
| 69 |
+
if n in reserved_fields:
|
| 70 |
+
if t[0] in reserved_fields:
|
| 71 |
+
ndescr.append((d, t[1]))
|
| 72 |
+
else:
|
| 73 |
+
ndescr.append(t)
|
| 74 |
+
else:
|
| 75 |
+
ndescr.append((n, t[1]))
|
| 76 |
+
return np.dtype(ndescr)
|
| 77 |
+
|
| 78 |
+
|
| 79 |
+
def _get_fieldmask(self):
|
| 80 |
+
mdescr = [(n, '|b1') for n in self.dtype.names]
|
| 81 |
+
fdmask = np.empty(self.shape, dtype=mdescr)
|
| 82 |
+
fdmask.flat = tuple([False] * len(mdescr))
|
| 83 |
+
return fdmask
|
| 84 |
+
|
| 85 |
+
|
| 86 |
+
class MaskedRecords(MaskedArray):
|
| 87 |
+
"""
|
| 88 |
+
|
| 89 |
+
Attributes
|
| 90 |
+
----------
|
| 91 |
+
_data : recarray
|
| 92 |
+
Underlying data, as a record array.
|
| 93 |
+
_mask : boolean array
|
| 94 |
+
Mask of the records. A record is masked when all its fields are
|
| 95 |
+
masked.
|
| 96 |
+
_fieldmask : boolean recarray
|
| 97 |
+
Record array of booleans, setting the mask of each individual field
|
| 98 |
+
of each record.
|
| 99 |
+
_fill_value : record
|
| 100 |
+
Filling values for each field.
|
| 101 |
+
|
| 102 |
+
"""
|
| 103 |
+
|
| 104 |
+
def __new__(cls, shape, dtype=None, buf=None, offset=0, strides=None,
|
| 105 |
+
formats=None, names=None, titles=None,
|
| 106 |
+
byteorder=None, aligned=False,
|
| 107 |
+
mask=nomask, hard_mask=False, fill_value=None, keep_mask=True,
|
| 108 |
+
copy=False,
|
| 109 |
+
**options):
|
| 110 |
+
|
| 111 |
+
self = recarray.__new__(cls, shape, dtype=dtype, buf=buf, offset=offset,
|
| 112 |
+
strides=strides, formats=formats, names=names,
|
| 113 |
+
titles=titles, byteorder=byteorder,
|
| 114 |
+
aligned=aligned,)
|
| 115 |
+
|
| 116 |
+
mdtype = ma.make_mask_descr(self.dtype)
|
| 117 |
+
if mask is nomask or not np.size(mask):
|
| 118 |
+
if not keep_mask:
|
| 119 |
+
self._mask = tuple([False] * len(mdtype))
|
| 120 |
+
else:
|
| 121 |
+
mask = np.array(mask, copy=copy)
|
| 122 |
+
if mask.shape != self.shape:
|
| 123 |
+
(nd, nm) = (self.size, mask.size)
|
| 124 |
+
if nm == 1:
|
| 125 |
+
mask = np.resize(mask, self.shape)
|
| 126 |
+
elif nm == nd:
|
| 127 |
+
mask = np.reshape(mask, self.shape)
|
| 128 |
+
else:
|
| 129 |
+
msg = "Mask and data not compatible: data size is %i, " + \
|
| 130 |
+
"mask size is %i."
|
| 131 |
+
raise MAError(msg % (nd, nm))
|
| 132 |
+
if not keep_mask:
|
| 133 |
+
self.__setmask__(mask)
|
| 134 |
+
self._sharedmask = True
|
| 135 |
+
else:
|
| 136 |
+
if mask.dtype == mdtype:
|
| 137 |
+
_mask = mask
|
| 138 |
+
else:
|
| 139 |
+
_mask = np.array([tuple([m] * len(mdtype)) for m in mask],
|
| 140 |
+
dtype=mdtype)
|
| 141 |
+
self._mask = _mask
|
| 142 |
+
return self
|
| 143 |
+
|
| 144 |
+
def __array_finalize__(self, obj):
|
| 145 |
+
# Make sure we have a _fieldmask by default
|
| 146 |
+
_mask = getattr(obj, '_mask', None)
|
| 147 |
+
if _mask is None:
|
| 148 |
+
objmask = getattr(obj, '_mask', nomask)
|
| 149 |
+
_dtype = ndarray.__getattribute__(self, 'dtype')
|
| 150 |
+
if objmask is nomask:
|
| 151 |
+
_mask = ma.make_mask_none(self.shape, dtype=_dtype)
|
| 152 |
+
else:
|
| 153 |
+
mdescr = ma.make_mask_descr(_dtype)
|
| 154 |
+
_mask = narray([tuple([m] * len(mdescr)) for m in objmask],
|
| 155 |
+
dtype=mdescr).view(recarray)
|
| 156 |
+
# Update some of the attributes
|
| 157 |
+
_dict = self.__dict__
|
| 158 |
+
_dict.update(_mask=_mask)
|
| 159 |
+
self._update_from(obj)
|
| 160 |
+
if _dict['_baseclass'] == ndarray:
|
| 161 |
+
_dict['_baseclass'] = recarray
|
| 162 |
+
return
|
| 163 |
+
|
| 164 |
+
@property
|
| 165 |
+
def _data(self):
|
| 166 |
+
"""
|
| 167 |
+
Returns the data as a recarray.
|
| 168 |
+
|
| 169 |
+
"""
|
| 170 |
+
return ndarray.view(self, recarray)
|
| 171 |
+
|
| 172 |
+
@property
|
| 173 |
+
def _fieldmask(self):
|
| 174 |
+
"""
|
| 175 |
+
Alias to mask.
|
| 176 |
+
|
| 177 |
+
"""
|
| 178 |
+
return self._mask
|
| 179 |
+
|
| 180 |
+
def __len__(self):
|
| 181 |
+
"""
|
| 182 |
+
Returns the length
|
| 183 |
+
|
| 184 |
+
"""
|
| 185 |
+
# We have more than one record
|
| 186 |
+
if self.ndim:
|
| 187 |
+
return len(self._data)
|
| 188 |
+
# We have only one record: return the nb of fields
|
| 189 |
+
return len(self.dtype)
|
| 190 |
+
|
| 191 |
+
def __getattribute__(self, attr):
|
| 192 |
+
try:
|
| 193 |
+
return object.__getattribute__(self, attr)
|
| 194 |
+
except AttributeError:
|
| 195 |
+
# attr must be a fieldname
|
| 196 |
+
pass
|
| 197 |
+
fielddict = ndarray.__getattribute__(self, 'dtype').fields
|
| 198 |
+
try:
|
| 199 |
+
res = fielddict[attr][:2]
|
| 200 |
+
except (TypeError, KeyError) as e:
|
| 201 |
+
raise AttributeError(
|
| 202 |
+
f'record array has no attribute {attr}') from e
|
| 203 |
+
# So far, so good
|
| 204 |
+
_localdict = ndarray.__getattribute__(self, '__dict__')
|
| 205 |
+
_data = ndarray.view(self, _localdict['_baseclass'])
|
| 206 |
+
obj = _data.getfield(*res)
|
| 207 |
+
if obj.dtype.names is not None:
|
| 208 |
+
raise NotImplementedError("MaskedRecords is currently limited to"
|
| 209 |
+
"simple records.")
|
| 210 |
+
# Get some special attributes
|
| 211 |
+
# Reset the object's mask
|
| 212 |
+
hasmasked = False
|
| 213 |
+
_mask = _localdict.get('_mask', None)
|
| 214 |
+
if _mask is not None:
|
| 215 |
+
try:
|
| 216 |
+
_mask = _mask[attr]
|
| 217 |
+
except IndexError:
|
| 218 |
+
# Couldn't find a mask: use the default (nomask)
|
| 219 |
+
pass
|
| 220 |
+
tp_len = len(_mask.dtype)
|
| 221 |
+
hasmasked = _mask.view((bool, ((tp_len,) if tp_len else ()))).any()
|
| 222 |
+
if (obj.shape or hasmasked):
|
| 223 |
+
obj = obj.view(MaskedArray)
|
| 224 |
+
obj._baseclass = ndarray
|
| 225 |
+
obj._isfield = True
|
| 226 |
+
obj._mask = _mask
|
| 227 |
+
# Reset the field values
|
| 228 |
+
_fill_value = _localdict.get('_fill_value', None)
|
| 229 |
+
if _fill_value is not None:
|
| 230 |
+
try:
|
| 231 |
+
obj._fill_value = _fill_value[attr]
|
| 232 |
+
except ValueError:
|
| 233 |
+
obj._fill_value = None
|
| 234 |
+
else:
|
| 235 |
+
obj = obj.item()
|
| 236 |
+
return obj
|
| 237 |
+
|
| 238 |
+
def __setattr__(self, attr, val):
|
| 239 |
+
"""
|
| 240 |
+
Sets the attribute attr to the value val.
|
| 241 |
+
|
| 242 |
+
"""
|
| 243 |
+
# Should we call __setmask__ first ?
|
| 244 |
+
if attr in ['mask', 'fieldmask']:
|
| 245 |
+
self.__setmask__(val)
|
| 246 |
+
return
|
| 247 |
+
# Create a shortcut (so that we don't have to call getattr all the time)
|
| 248 |
+
_localdict = object.__getattribute__(self, '__dict__')
|
| 249 |
+
# Check whether we're creating a new field
|
| 250 |
+
newattr = attr not in _localdict
|
| 251 |
+
try:
|
| 252 |
+
# Is attr a generic attribute ?
|
| 253 |
+
ret = object.__setattr__(self, attr, val)
|
| 254 |
+
except Exception:
|
| 255 |
+
# Not a generic attribute: exit if it's not a valid field
|
| 256 |
+
fielddict = ndarray.__getattribute__(self, 'dtype').fields or {}
|
| 257 |
+
optinfo = ndarray.__getattribute__(self, '_optinfo') or {}
|
| 258 |
+
if not (attr in fielddict or attr in optinfo):
|
| 259 |
+
raise
|
| 260 |
+
else:
|
| 261 |
+
# Get the list of names
|
| 262 |
+
fielddict = ndarray.__getattribute__(self, 'dtype').fields or {}
|
| 263 |
+
# Check the attribute
|
| 264 |
+
if attr not in fielddict:
|
| 265 |
+
return ret
|
| 266 |
+
if newattr:
|
| 267 |
+
# We just added this one or this setattr worked on an
|
| 268 |
+
# internal attribute.
|
| 269 |
+
try:
|
| 270 |
+
object.__delattr__(self, attr)
|
| 271 |
+
except Exception:
|
| 272 |
+
return ret
|
| 273 |
+
# Let's try to set the field
|
| 274 |
+
try:
|
| 275 |
+
res = fielddict[attr][:2]
|
| 276 |
+
except (TypeError, KeyError) as e:
|
| 277 |
+
raise AttributeError(
|
| 278 |
+
f'record array has no attribute {attr}') from e
|
| 279 |
+
|
| 280 |
+
if val is masked:
|
| 281 |
+
_fill_value = _localdict['_fill_value']
|
| 282 |
+
if _fill_value is not None:
|
| 283 |
+
dval = _localdict['_fill_value'][attr]
|
| 284 |
+
else:
|
| 285 |
+
dval = val
|
| 286 |
+
mval = True
|
| 287 |
+
else:
|
| 288 |
+
dval = filled(val)
|
| 289 |
+
mval = getmaskarray(val)
|
| 290 |
+
obj = ndarray.__getattribute__(self, '_data').setfield(dval, *res)
|
| 291 |
+
_localdict['_mask'].__setitem__(attr, mval)
|
| 292 |
+
return obj
|
| 293 |
+
|
| 294 |
+
def __getitem__(self, indx):
|
| 295 |
+
"""
|
| 296 |
+
Returns all the fields sharing the same fieldname base.
|
| 297 |
+
|
| 298 |
+
The fieldname base is either `_data` or `_mask`.
|
| 299 |
+
|
| 300 |
+
"""
|
| 301 |
+
_localdict = self.__dict__
|
| 302 |
+
_mask = ndarray.__getattribute__(self, '_mask')
|
| 303 |
+
_data = ndarray.view(self, _localdict['_baseclass'])
|
| 304 |
+
# We want a field
|
| 305 |
+
if isinstance(indx, str):
|
| 306 |
+
# Make sure _sharedmask is True to propagate back to _fieldmask
|
| 307 |
+
# Don't use _set_mask, there are some copies being made that
|
| 308 |
+
# break propagation Don't force the mask to nomask, that wreaks
|
| 309 |
+
# easy masking
|
| 310 |
+
obj = _data[indx].view(MaskedArray)
|
| 311 |
+
obj._mask = _mask[indx]
|
| 312 |
+
obj._sharedmask = True
|
| 313 |
+
fval = _localdict['_fill_value']
|
| 314 |
+
if fval is not None:
|
| 315 |
+
obj._fill_value = fval[indx]
|
| 316 |
+
# Force to masked if the mask is True
|
| 317 |
+
if not obj.ndim and obj._mask:
|
| 318 |
+
return masked
|
| 319 |
+
return obj
|
| 320 |
+
# We want some elements.
|
| 321 |
+
# First, the data.
|
| 322 |
+
obj = np.array(_data[indx], copy=False).view(mrecarray)
|
| 323 |
+
obj._mask = np.array(_mask[indx], copy=False).view(recarray)
|
| 324 |
+
return obj
|
| 325 |
+
|
| 326 |
+
def __setitem__(self, indx, value):
|
| 327 |
+
"""
|
| 328 |
+
Sets the given record to value.
|
| 329 |
+
|
| 330 |
+
"""
|
| 331 |
+
MaskedArray.__setitem__(self, indx, value)
|
| 332 |
+
if isinstance(indx, str):
|
| 333 |
+
self._mask[indx] = ma.getmaskarray(value)
|
| 334 |
+
|
| 335 |
+
def __str__(self):
|
| 336 |
+
"""
|
| 337 |
+
Calculates the string representation.
|
| 338 |
+
|
| 339 |
+
"""
|
| 340 |
+
if self.size > 1:
|
| 341 |
+
mstr = [f"({','.join([str(i) for i in s])})"
|
| 342 |
+
for s in zip(*[getattr(self, f) for f in self.dtype.names])]
|
| 343 |
+
return f"[{', '.join(mstr)}]"
|
| 344 |
+
else:
|
| 345 |
+
mstr = [f"{','.join([str(i) for i in s])}"
|
| 346 |
+
for s in zip([getattr(self, f) for f in self.dtype.names])]
|
| 347 |
+
return f"({', '.join(mstr)})"
|
| 348 |
+
|
| 349 |
+
def __repr__(self):
|
| 350 |
+
"""
|
| 351 |
+
Calculates the repr representation.
|
| 352 |
+
|
| 353 |
+
"""
|
| 354 |
+
_names = self.dtype.names
|
| 355 |
+
fmt = "%%%is : %%s" % (max([len(n) for n in _names]) + 4,)
|
| 356 |
+
reprstr = [fmt % (f, getattr(self, f)) for f in self.dtype.names]
|
| 357 |
+
reprstr.insert(0, 'masked_records(')
|
| 358 |
+
reprstr.extend([fmt % (' fill_value', self.fill_value),
|
| 359 |
+
' )'])
|
| 360 |
+
return str("\n".join(reprstr))
|
| 361 |
+
|
| 362 |
+
def view(self, dtype=None, type=None):
|
| 363 |
+
"""
|
| 364 |
+
Returns a view of the mrecarray.
|
| 365 |
+
|
| 366 |
+
"""
|
| 367 |
+
# OK, basic copy-paste from MaskedArray.view.
|
| 368 |
+
if dtype is None:
|
| 369 |
+
if type is None:
|
| 370 |
+
output = ndarray.view(self)
|
| 371 |
+
else:
|
| 372 |
+
output = ndarray.view(self, type)
|
| 373 |
+
# Here again.
|
| 374 |
+
elif type is None:
|
| 375 |
+
try:
|
| 376 |
+
if issubclass(dtype, ndarray):
|
| 377 |
+
output = ndarray.view(self, dtype)
|
| 378 |
+
else:
|
| 379 |
+
output = ndarray.view(self, dtype)
|
| 380 |
+
# OK, there's the change
|
| 381 |
+
except TypeError:
|
| 382 |
+
dtype = np.dtype(dtype)
|
| 383 |
+
# we need to revert to MaskedArray, but keeping the possibility
|
| 384 |
+
# of subclasses (eg, TimeSeriesRecords), so we'll force a type
|
| 385 |
+
# set to the first parent
|
| 386 |
+
if dtype.fields is None:
|
| 387 |
+
basetype = self.__class__.__bases__[0]
|
| 388 |
+
output = self.__array__().view(dtype, basetype)
|
| 389 |
+
output._update_from(self)
|
| 390 |
+
else:
|
| 391 |
+
output = ndarray.view(self, dtype)
|
| 392 |
+
output._fill_value = None
|
| 393 |
+
else:
|
| 394 |
+
output = ndarray.view(self, dtype, type)
|
| 395 |
+
# Update the mask, just like in MaskedArray.view
|
| 396 |
+
if (getattr(output, '_mask', nomask) is not nomask):
|
| 397 |
+
mdtype = ma.make_mask_descr(output.dtype)
|
| 398 |
+
output._mask = self._mask.view(mdtype, ndarray)
|
| 399 |
+
output._mask.shape = output.shape
|
| 400 |
+
return output
|
| 401 |
+
|
| 402 |
+
def harden_mask(self):
|
| 403 |
+
"""
|
| 404 |
+
Forces the mask to hard.
|
| 405 |
+
|
| 406 |
+
"""
|
| 407 |
+
self._hardmask = True
|
| 408 |
+
|
| 409 |
+
def soften_mask(self):
|
| 410 |
+
"""
|
| 411 |
+
Forces the mask to soft
|
| 412 |
+
|
| 413 |
+
"""
|
| 414 |
+
self._hardmask = False
|
| 415 |
+
|
| 416 |
+
def copy(self):
|
| 417 |
+
"""
|
| 418 |
+
Returns a copy of the masked record.
|
| 419 |
+
|
| 420 |
+
"""
|
| 421 |
+
copied = self._data.copy().view(type(self))
|
| 422 |
+
copied._mask = self._mask.copy()
|
| 423 |
+
return copied
|
| 424 |
+
|
| 425 |
+
def tolist(self, fill_value=None):
|
| 426 |
+
"""
|
| 427 |
+
Return the data portion of the array as a list.
|
| 428 |
+
|
| 429 |
+
Data items are converted to the nearest compatible Python type.
|
| 430 |
+
Masked values are converted to fill_value. If fill_value is None,
|
| 431 |
+
the corresponding entries in the output list will be ``None``.
|
| 432 |
+
|
| 433 |
+
"""
|
| 434 |
+
if fill_value is not None:
|
| 435 |
+
return self.filled(fill_value).tolist()
|
| 436 |
+
result = narray(self.filled().tolist(), dtype=object)
|
| 437 |
+
mask = narray(self._mask.tolist())
|
| 438 |
+
result[mask] = None
|
| 439 |
+
return result.tolist()
|
| 440 |
+
|
| 441 |
+
def __getstate__(self):
|
| 442 |
+
"""Return the internal state of the masked array.
|
| 443 |
+
|
| 444 |
+
This is for pickling.
|
| 445 |
+
|
| 446 |
+
"""
|
| 447 |
+
state = (1,
|
| 448 |
+
self.shape,
|
| 449 |
+
self.dtype,
|
| 450 |
+
self.flags.fnc,
|
| 451 |
+
self._data.tobytes(),
|
| 452 |
+
self._mask.tobytes(),
|
| 453 |
+
self._fill_value,
|
| 454 |
+
)
|
| 455 |
+
return state
|
| 456 |
+
|
| 457 |
+
def __setstate__(self, state):
|
| 458 |
+
"""
|
| 459 |
+
Restore the internal state of the masked array.
|
| 460 |
+
|
| 461 |
+
This is for pickling. ``state`` is typically the output of the
|
| 462 |
+
``__getstate__`` output, and is a 5-tuple:
|
| 463 |
+
|
| 464 |
+
- class name
|
| 465 |
+
- a tuple giving the shape of the data
|
| 466 |
+
- a typecode for the data
|
| 467 |
+
- a binary string for the data
|
| 468 |
+
- a binary string for the mask.
|
| 469 |
+
|
| 470 |
+
"""
|
| 471 |
+
(ver, shp, typ, isf, raw, msk, flv) = state
|
| 472 |
+
ndarray.__setstate__(self, (shp, typ, isf, raw))
|
| 473 |
+
mdtype = dtype([(k, bool_) for (k, _) in self.dtype.descr])
|
| 474 |
+
self.__dict__['_mask'].__setstate__((shp, mdtype, isf, msk))
|
| 475 |
+
self.fill_value = flv
|
| 476 |
+
|
| 477 |
+
def __reduce__(self):
|
| 478 |
+
"""
|
| 479 |
+
Return a 3-tuple for pickling a MaskedArray.
|
| 480 |
+
|
| 481 |
+
"""
|
| 482 |
+
return (_mrreconstruct,
|
| 483 |
+
(self.__class__, self._baseclass, (0,), 'b',),
|
| 484 |
+
self.__getstate__())
|
| 485 |
+
|
| 486 |
+
|
| 487 |
+
def _mrreconstruct(subtype, baseclass, baseshape, basetype,):
|
| 488 |
+
"""
|
| 489 |
+
Build a new MaskedArray from the information stored in a pickle.
|
| 490 |
+
|
| 491 |
+
"""
|
| 492 |
+
_data = ndarray.__new__(baseclass, baseshape, basetype).view(subtype)
|
| 493 |
+
_mask = ndarray.__new__(ndarray, baseshape, 'b1')
|
| 494 |
+
return subtype.__new__(subtype, _data, mask=_mask, dtype=basetype,)
|
| 495 |
+
|
| 496 |
+
mrecarray = MaskedRecords
|
| 497 |
+
|
| 498 |
+
|
| 499 |
+
###############################################################################
|
| 500 |
+
# Constructors #
|
| 501 |
+
###############################################################################
|
| 502 |
+
|
| 503 |
+
|
| 504 |
+
def fromarrays(arraylist, dtype=None, shape=None, formats=None,
|
| 505 |
+
names=None, titles=None, aligned=False, byteorder=None,
|
| 506 |
+
fill_value=None):
|
| 507 |
+
"""
|
| 508 |
+
Creates a mrecarray from a (flat) list of masked arrays.
|
| 509 |
+
|
| 510 |
+
Parameters
|
| 511 |
+
----------
|
| 512 |
+
arraylist : sequence
|
| 513 |
+
A list of (masked) arrays. Each element of the sequence is first converted
|
| 514 |
+
to a masked array if needed. If a 2D array is passed as argument, it is
|
| 515 |
+
processed line by line
|
| 516 |
+
dtype : {None, dtype}, optional
|
| 517 |
+
Data type descriptor.
|
| 518 |
+
shape : {None, integer}, optional
|
| 519 |
+
Number of records. If None, shape is defined from the shape of the
|
| 520 |
+
first array in the list.
|
| 521 |
+
formats : {None, sequence}, optional
|
| 522 |
+
Sequence of formats for each individual field. If None, the formats will
|
| 523 |
+
be autodetected by inspecting the fields and selecting the highest dtype
|
| 524 |
+
possible.
|
| 525 |
+
names : {None, sequence}, optional
|
| 526 |
+
Sequence of the names of each field.
|
| 527 |
+
fill_value : {None, sequence}, optional
|
| 528 |
+
Sequence of data to be used as filling values.
|
| 529 |
+
|
| 530 |
+
Notes
|
| 531 |
+
-----
|
| 532 |
+
Lists of tuples should be preferred over lists of lists for faster processing.
|
| 533 |
+
|
| 534 |
+
"""
|
| 535 |
+
datalist = [getdata(x) for x in arraylist]
|
| 536 |
+
masklist = [np.atleast_1d(getmaskarray(x)) for x in arraylist]
|
| 537 |
+
_array = recfromarrays(datalist,
|
| 538 |
+
dtype=dtype, shape=shape, formats=formats,
|
| 539 |
+
names=names, titles=titles, aligned=aligned,
|
| 540 |
+
byteorder=byteorder).view(mrecarray)
|
| 541 |
+
_array._mask.flat = list(zip(*masklist))
|
| 542 |
+
if fill_value is not None:
|
| 543 |
+
_array.fill_value = fill_value
|
| 544 |
+
return _array
|
| 545 |
+
|
| 546 |
+
|
| 547 |
+
def fromrecords(reclist, dtype=None, shape=None, formats=None, names=None,
|
| 548 |
+
titles=None, aligned=False, byteorder=None,
|
| 549 |
+
fill_value=None, mask=nomask):
|
| 550 |
+
"""
|
| 551 |
+
Creates a MaskedRecords from a list of records.
|
| 552 |
+
|
| 553 |
+
Parameters
|
| 554 |
+
----------
|
| 555 |
+
reclist : sequence
|
| 556 |
+
A list of records. Each element of the sequence is first converted
|
| 557 |
+
to a masked array if needed. If a 2D array is passed as argument, it is
|
| 558 |
+
processed line by line
|
| 559 |
+
dtype : {None, dtype}, optional
|
| 560 |
+
Data type descriptor.
|
| 561 |
+
shape : {None,int}, optional
|
| 562 |
+
Number of records. If None, ``shape`` is defined from the shape of the
|
| 563 |
+
first array in the list.
|
| 564 |
+
formats : {None, sequence}, optional
|
| 565 |
+
Sequence of formats for each individual field. If None, the formats will
|
| 566 |
+
be autodetected by inspecting the fields and selecting the highest dtype
|
| 567 |
+
possible.
|
| 568 |
+
names : {None, sequence}, optional
|
| 569 |
+
Sequence of the names of each field.
|
| 570 |
+
fill_value : {None, sequence}, optional
|
| 571 |
+
Sequence of data to be used as filling values.
|
| 572 |
+
mask : {nomask, sequence}, optional.
|
| 573 |
+
External mask to apply on the data.
|
| 574 |
+
|
| 575 |
+
Notes
|
| 576 |
+
-----
|
| 577 |
+
Lists of tuples should be preferred over lists of lists for faster processing.
|
| 578 |
+
|
| 579 |
+
"""
|
| 580 |
+
# Grab the initial _fieldmask, if needed:
|
| 581 |
+
_mask = getattr(reclist, '_mask', None)
|
| 582 |
+
# Get the list of records.
|
| 583 |
+
if isinstance(reclist, ndarray):
|
| 584 |
+
# Make sure we don't have some hidden mask
|
| 585 |
+
if isinstance(reclist, MaskedArray):
|
| 586 |
+
reclist = reclist.filled().view(ndarray)
|
| 587 |
+
# Grab the initial dtype, just in case
|
| 588 |
+
if dtype is None:
|
| 589 |
+
dtype = reclist.dtype
|
| 590 |
+
reclist = reclist.tolist()
|
| 591 |
+
mrec = recfromrecords(reclist, dtype=dtype, shape=shape, formats=formats,
|
| 592 |
+
names=names, titles=titles,
|
| 593 |
+
aligned=aligned, byteorder=byteorder).view(mrecarray)
|
| 594 |
+
# Set the fill_value if needed
|
| 595 |
+
if fill_value is not None:
|
| 596 |
+
mrec.fill_value = fill_value
|
| 597 |
+
# Now, let's deal w/ the mask
|
| 598 |
+
if mask is not nomask:
|
| 599 |
+
mask = np.array(mask, copy=False)
|
| 600 |
+
maskrecordlength = len(mask.dtype)
|
| 601 |
+
if maskrecordlength:
|
| 602 |
+
mrec._mask.flat = mask
|
| 603 |
+
elif mask.ndim == 2:
|
| 604 |
+
mrec._mask.flat = [tuple(m) for m in mask]
|
| 605 |
+
else:
|
| 606 |
+
mrec.__setmask__(mask)
|
| 607 |
+
if _mask is not None:
|
| 608 |
+
mrec._mask[:] = _mask
|
| 609 |
+
return mrec
|
| 610 |
+
|
| 611 |
+
|
| 612 |
+
def _guessvartypes(arr):
|
| 613 |
+
"""
|
| 614 |
+
Tries to guess the dtypes of the str_ ndarray `arr`.
|
| 615 |
+
|
| 616 |
+
Guesses by testing element-wise conversion. Returns a list of dtypes.
|
| 617 |
+
The array is first converted to ndarray. If the array is 2D, the test
|
| 618 |
+
is performed on the first line. An exception is raised if the file is
|
| 619 |
+
3D or more.
|
| 620 |
+
|
| 621 |
+
"""
|
| 622 |
+
vartypes = []
|
| 623 |
+
arr = np.asarray(arr)
|
| 624 |
+
if arr.ndim == 2:
|
| 625 |
+
arr = arr[0]
|
| 626 |
+
elif arr.ndim > 2:
|
| 627 |
+
raise ValueError("The array should be 2D at most!")
|
| 628 |
+
# Start the conversion loop.
|
| 629 |
+
for f in arr:
|
| 630 |
+
try:
|
| 631 |
+
int(f)
|
| 632 |
+
except (ValueError, TypeError):
|
| 633 |
+
try:
|
| 634 |
+
float(f)
|
| 635 |
+
except (ValueError, TypeError):
|
| 636 |
+
try:
|
| 637 |
+
complex(f)
|
| 638 |
+
except (ValueError, TypeError):
|
| 639 |
+
vartypes.append(arr.dtype)
|
| 640 |
+
else:
|
| 641 |
+
vartypes.append(np.dtype(complex))
|
| 642 |
+
else:
|
| 643 |
+
vartypes.append(np.dtype(float))
|
| 644 |
+
else:
|
| 645 |
+
vartypes.append(np.dtype(int))
|
| 646 |
+
return vartypes
|
| 647 |
+
|
| 648 |
+
|
| 649 |
+
def openfile(fname):
|
| 650 |
+
"""
|
| 651 |
+
Opens the file handle of file `fname`.
|
| 652 |
+
|
| 653 |
+
"""
|
| 654 |
+
# A file handle
|
| 655 |
+
if hasattr(fname, 'readline'):
|
| 656 |
+
return fname
|
| 657 |
+
# Try to open the file and guess its type
|
| 658 |
+
try:
|
| 659 |
+
f = open(fname)
|
| 660 |
+
except FileNotFoundError as e:
|
| 661 |
+
raise FileNotFoundError(f"No such file: '{fname}'") from e
|
| 662 |
+
if f.readline()[:2] != "\\x":
|
| 663 |
+
f.seek(0, 0)
|
| 664 |
+
return f
|
| 665 |
+
f.close()
|
| 666 |
+
raise NotImplementedError("Wow, binary file")
|
| 667 |
+
|
| 668 |
+
|
| 669 |
+
def fromtextfile(fname, delimiter=None, commentchar='#', missingchar='',
|
| 670 |
+
varnames=None, vartypes=None,
|
| 671 |
+
*, delimitor=np._NoValue): # backwards compatibility
|
| 672 |
+
"""
|
| 673 |
+
Creates a mrecarray from data stored in the file `filename`.
|
| 674 |
+
|
| 675 |
+
Parameters
|
| 676 |
+
----------
|
| 677 |
+
fname : {file name/handle}
|
| 678 |
+
Handle of an opened file.
|
| 679 |
+
delimiter : {None, string}, optional
|
| 680 |
+
Alphanumeric character used to separate columns in the file.
|
| 681 |
+
If None, any (group of) white spacestring(s) will be used.
|
| 682 |
+
commentchar : {'#', string}, optional
|
| 683 |
+
Alphanumeric character used to mark the start of a comment.
|
| 684 |
+
missingchar : {'', string}, optional
|
| 685 |
+
String indicating missing data, and used to create the masks.
|
| 686 |
+
varnames : {None, sequence}, optional
|
| 687 |
+
Sequence of the variable names. If None, a list will be created from
|
| 688 |
+
the first non empty line of the file.
|
| 689 |
+
vartypes : {None, sequence}, optional
|
| 690 |
+
Sequence of the variables dtypes. If None, it will be estimated from
|
| 691 |
+
the first non-commented line.
|
| 692 |
+
|
| 693 |
+
|
| 694 |
+
Ultra simple: the varnames are in the header, one line"""
|
| 695 |
+
if delimitor is not np._NoValue:
|
| 696 |
+
if delimiter is not None:
|
| 697 |
+
raise TypeError("fromtextfile() got multiple values for argument "
|
| 698 |
+
"'delimiter'")
|
| 699 |
+
# NumPy 1.22.0, 2021-09-23
|
| 700 |
+
warnings.warn("The 'delimitor' keyword argument of "
|
| 701 |
+
"numpy.ma.mrecords.fromtextfile() is deprecated "
|
| 702 |
+
"since NumPy 1.22.0, use 'delimiter' instead.",
|
| 703 |
+
DeprecationWarning, stacklevel=2)
|
| 704 |
+
delimiter = delimitor
|
| 705 |
+
|
| 706 |
+
# Try to open the file.
|
| 707 |
+
ftext = openfile(fname)
|
| 708 |
+
|
| 709 |
+
# Get the first non-empty line as the varnames
|
| 710 |
+
while True:
|
| 711 |
+
line = ftext.readline()
|
| 712 |
+
firstline = line[:line.find(commentchar)].strip()
|
| 713 |
+
_varnames = firstline.split(delimiter)
|
| 714 |
+
if len(_varnames) > 1:
|
| 715 |
+
break
|
| 716 |
+
if varnames is None:
|
| 717 |
+
varnames = _varnames
|
| 718 |
+
|
| 719 |
+
# Get the data.
|
| 720 |
+
_variables = masked_array([line.strip().split(delimiter) for line in ftext
|
| 721 |
+
if line[0] != commentchar and len(line) > 1])
|
| 722 |
+
(_, nfields) = _variables.shape
|
| 723 |
+
ftext.close()
|
| 724 |
+
|
| 725 |
+
# Try to guess the dtype.
|
| 726 |
+
if vartypes is None:
|
| 727 |
+
vartypes = _guessvartypes(_variables[0])
|
| 728 |
+
else:
|
| 729 |
+
vartypes = [np.dtype(v) for v in vartypes]
|
| 730 |
+
if len(vartypes) != nfields:
|
| 731 |
+
msg = "Attempting to %i dtypes for %i fields!"
|
| 732 |
+
msg += " Reverting to default."
|
| 733 |
+
warnings.warn(msg % (len(vartypes), nfields), stacklevel=2)
|
| 734 |
+
vartypes = _guessvartypes(_variables[0])
|
| 735 |
+
|
| 736 |
+
# Construct the descriptor.
|
| 737 |
+
mdescr = [(n, f) for (n, f) in zip(varnames, vartypes)]
|
| 738 |
+
mfillv = [ma.default_fill_value(f) for f in vartypes]
|
| 739 |
+
|
| 740 |
+
# Get the data and the mask.
|
| 741 |
+
# We just need a list of masked_arrays. It's easier to create it like that:
|
| 742 |
+
_mask = (_variables.T == missingchar)
|
| 743 |
+
_datalist = [masked_array(a, mask=m, dtype=t, fill_value=f)
|
| 744 |
+
for (a, m, t, f) in zip(_variables.T, _mask, vartypes, mfillv)]
|
| 745 |
+
|
| 746 |
+
return fromarrays(_datalist, dtype=mdescr)
|
| 747 |
+
|
| 748 |
+
|
| 749 |
+
def addfield(mrecord, newfield, newfieldname=None):
|
| 750 |
+
"""Adds a new field to the masked record array
|
| 751 |
+
|
| 752 |
+
Uses `newfield` as data and `newfieldname` as name. If `newfieldname`
|
| 753 |
+
is None, the new field name is set to 'fi', where `i` is the number of
|
| 754 |
+
existing fields.
|
| 755 |
+
|
| 756 |
+
"""
|
| 757 |
+
_data = mrecord._data
|
| 758 |
+
_mask = mrecord._mask
|
| 759 |
+
if newfieldname is None or newfieldname in reserved_fields:
|
| 760 |
+
newfieldname = 'f%i' % len(_data.dtype)
|
| 761 |
+
newfield = ma.array(newfield)
|
| 762 |
+
# Get the new data.
|
| 763 |
+
# Create a new empty recarray
|
| 764 |
+
newdtype = np.dtype(_data.dtype.descr + [(newfieldname, newfield.dtype)])
|
| 765 |
+
newdata = recarray(_data.shape, newdtype)
|
| 766 |
+
# Add the existing field
|
| 767 |
+
[newdata.setfield(_data.getfield(*f), *f)
|
| 768 |
+
for f in _data.dtype.fields.values()]
|
| 769 |
+
# Add the new field
|
| 770 |
+
newdata.setfield(newfield._data, *newdata.dtype.fields[newfieldname])
|
| 771 |
+
newdata = newdata.view(MaskedRecords)
|
| 772 |
+
# Get the new mask
|
| 773 |
+
# Create a new empty recarray
|
| 774 |
+
newmdtype = np.dtype([(n, bool_) for n in newdtype.names])
|
| 775 |
+
newmask = recarray(_data.shape, newmdtype)
|
| 776 |
+
# Add the old masks
|
| 777 |
+
[newmask.setfield(_mask.getfield(*f), *f)
|
| 778 |
+
for f in _mask.dtype.fields.values()]
|
| 779 |
+
# Add the mask of the new field
|
| 780 |
+
newmask.setfield(getmaskarray(newfield),
|
| 781 |
+
*newmask.dtype.fields[newfieldname])
|
| 782 |
+
newdata._mask = newmask
|
| 783 |
+
return newdata
|
LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/numpy/ma/mrecords.pyi
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from typing import Any, TypeVar
|
| 2 |
+
|
| 3 |
+
from numpy import dtype
|
| 4 |
+
from numpy.ma import MaskedArray
|
| 5 |
+
|
| 6 |
+
__all__: list[str]
|
| 7 |
+
|
| 8 |
+
# TODO: Set the `bound` to something more suitable once we
|
| 9 |
+
# have proper shape support
|
| 10 |
+
_ShapeType = TypeVar("_ShapeType", bound=Any)
|
| 11 |
+
_DType_co = TypeVar("_DType_co", bound=dtype[Any], covariant=True)
|
| 12 |
+
|
| 13 |
+
class MaskedRecords(MaskedArray[_ShapeType, _DType_co]):
|
| 14 |
+
def __new__(
|
| 15 |
+
cls,
|
| 16 |
+
shape,
|
| 17 |
+
dtype=...,
|
| 18 |
+
buf=...,
|
| 19 |
+
offset=...,
|
| 20 |
+
strides=...,
|
| 21 |
+
formats=...,
|
| 22 |
+
names=...,
|
| 23 |
+
titles=...,
|
| 24 |
+
byteorder=...,
|
| 25 |
+
aligned=...,
|
| 26 |
+
mask=...,
|
| 27 |
+
hard_mask=...,
|
| 28 |
+
fill_value=...,
|
| 29 |
+
keep_mask=...,
|
| 30 |
+
copy=...,
|
| 31 |
+
**options,
|
| 32 |
+
): ...
|
| 33 |
+
_mask: Any
|
| 34 |
+
_fill_value: Any
|
| 35 |
+
@property
|
| 36 |
+
def _data(self): ...
|
| 37 |
+
@property
|
| 38 |
+
def _fieldmask(self): ...
|
| 39 |
+
def __array_finalize__(self, obj): ...
|
| 40 |
+
def __len__(self): ...
|
| 41 |
+
def __getattribute__(self, attr): ...
|
| 42 |
+
def __setattr__(self, attr, val): ...
|
| 43 |
+
def __getitem__(self, indx): ...
|
| 44 |
+
def __setitem__(self, indx, value): ...
|
| 45 |
+
def view(self, dtype=..., type=...): ...
|
| 46 |
+
def harden_mask(self): ...
|
| 47 |
+
def soften_mask(self): ...
|
| 48 |
+
def copy(self): ...
|
| 49 |
+
def tolist(self, fill_value=...): ...
|
| 50 |
+
def __reduce__(self): ...
|
| 51 |
+
|
| 52 |
+
mrecarray = MaskedRecords
|
| 53 |
+
|
| 54 |
+
def fromarrays(
|
| 55 |
+
arraylist,
|
| 56 |
+
dtype=...,
|
| 57 |
+
shape=...,
|
| 58 |
+
formats=...,
|
| 59 |
+
names=...,
|
| 60 |
+
titles=...,
|
| 61 |
+
aligned=...,
|
| 62 |
+
byteorder=...,
|
| 63 |
+
fill_value=...,
|
| 64 |
+
): ...
|
| 65 |
+
|
| 66 |
+
def fromrecords(
|
| 67 |
+
reclist,
|
| 68 |
+
dtype=...,
|
| 69 |
+
shape=...,
|
| 70 |
+
formats=...,
|
| 71 |
+
names=...,
|
| 72 |
+
titles=...,
|
| 73 |
+
aligned=...,
|
| 74 |
+
byteorder=...,
|
| 75 |
+
fill_value=...,
|
| 76 |
+
mask=...,
|
| 77 |
+
): ...
|
| 78 |
+
|
| 79 |
+
def fromtextfile(
|
| 80 |
+
fname,
|
| 81 |
+
delimiter=...,
|
| 82 |
+
commentchar=...,
|
| 83 |
+
missingchar=...,
|
| 84 |
+
varnames=...,
|
| 85 |
+
vartypes=...,
|
| 86 |
+
# NOTE: deprecated: NumPy 1.22.0, 2021-09-23
|
| 87 |
+
# delimitor=...,
|
| 88 |
+
): ...
|
| 89 |
+
|
| 90 |
+
def addfield(mrecord, newfield, newfieldname=...): ...
|
LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/numpy/ma/setup.py
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
def configuration(parent_package='',top_path=None):
|
| 3 |
+
from numpy.distutils.misc_util import Configuration
|
| 4 |
+
config = Configuration('ma', parent_package, top_path)
|
| 5 |
+
config.add_subpackage('tests')
|
| 6 |
+
config.add_data_files('*.pyi')
|
| 7 |
+
return config
|
| 8 |
+
|
| 9 |
+
if __name__ == "__main__":
|
| 10 |
+
from numpy.distutils.core import setup
|
| 11 |
+
config = configuration(top_path='').todict()
|
| 12 |
+
setup(**config)
|
LTA_openwebtext_dualt/mini_owt_logdirichlet/.venv_qwen35_uv/lib/python3.12/site-packages/transformers/models/qwen3_vl_moe/configuration_qwen3_vl_moe.py
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
|
| 2 |
+
# This file was automatically generated from src/transformers/models/qwen3_vl_moe/modular_qwen3_vl_moe.py.
|
| 3 |
+
# Do NOT edit this file manually as any edits will be overwritten by the generation of
|
| 4 |
+
# the file from the modular. If any change should be done, please apply the change to the
|
| 5 |
+
# modular_qwen3_vl_moe.py file directly. One of our CI enforces this.
|
| 6 |
+
# 🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
|
| 7 |
+
# Copyright 2025 The Qwen Team and The HuggingFace Inc. team. All rights reserved.
|
| 8 |
+
#
|
| 9 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 10 |
+
# you may not use this file except in compliance with the License.
|
| 11 |
+
# You may obtain a copy of the License at
|
| 12 |
+
#
|
| 13 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 14 |
+
#
|
| 15 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 16 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 17 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 18 |
+
# See the License for the specific language governing permissions and
|
| 19 |
+
# limitations under the License.
|
| 20 |
+
from huggingface_hub.dataclasses import strict
|
| 21 |
+
|
| 22 |
+
from ...configuration_utils import PreTrainedConfig
|
| 23 |
+
from ...modeling_rope_utils import RopeParameters
|
| 24 |
+
from ...utils import auto_docstring
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
@auto_docstring(checkpoint="Qwen/Qwen3-VL-30B-A3B-Instruct")
|
| 28 |
+
@strict
|
| 29 |
+
class Qwen3VLMoeTextConfig(PreTrainedConfig):
|
| 30 |
+
r"""
|
| 31 |
+
decoder_sparse_step (`int`, *optional*, defaults to 1):
|
| 32 |
+
The frequency of the MoE layer.
|
| 33 |
+
mlp_only_layers (`List[int]`, *optional*, defaults to `[]`):
|
| 34 |
+
Indicate which layers use Qwen3VLMoeMLP rather than Qwen3VLMoeSparseMoeBlock
|
| 35 |
+
The list contains layer index, from 0 to num_layers-1 if we have num_layers layers
|
| 36 |
+
If `mlp_only_layers` is empty, `decoder_sparse_step` is used to determine the sparsity.
|
| 37 |
+
|
| 38 |
+
```python
|
| 39 |
+
>>> from transformers import Qwen3VLMoeForConditionalGeneration, Qwen3VLMoeConfig
|
| 40 |
+
|
| 41 |
+
>>> # Initializing a Qwen3VLMoe style configuration
|
| 42 |
+
>>> configuration = Qwen3VLMoeConfig()
|
| 43 |
+
|
| 44 |
+
>>> # Initializing a model from the Qwen3-VL-30B-A3B style configuration
|
| 45 |
+
>>> model = Qwen3VLMoeForConditionalGeneration(configuration)
|
| 46 |
+
|
| 47 |
+
>>> # Accessing the model configuration
|
| 48 |
+
>>> configuration = model.config
|
| 49 |
+
```"""
|
| 50 |
+
|
| 51 |
+
model_type = "qwen3_vl_moe_text"
|
| 52 |
+
keys_to_ignore_at_inference = ["past_key_values"]
|
| 53 |
+
|
| 54 |
+
attribute_map = {
|
| 55 |
+
"num_experts": "num_local_experts",
|
| 56 |
+
}
|
| 57 |
+
# Default tensor parallel plan for base model `Qwen3VLMoe`
|
| 58 |
+
base_model_tp_plan = {
|
| 59 |
+
"layers.*.self_attn.q_proj": "colwise",
|
| 60 |
+
"layers.*.self_attn.k_proj": "colwise",
|
| 61 |
+
"layers.*.self_attn.v_proj": "colwise",
|
| 62 |
+
"layers.*.self_attn.o_proj": "rowwise",
|
| 63 |
+
"layers.*.mlp.gate_proj": "colwise",
|
| 64 |
+
"layers.*.mlp.up_proj": "colwise",
|
| 65 |
+
"layers.*.mlp.down_proj": "rowwise",
|
| 66 |
+
}
|
| 67 |
+
base_model_ep_plan = {
|
| 68 |
+
"layers.*.mlp.gate": "ep_router",
|
| 69 |
+
"layers.*.mlp.experts.gate_up_proj": "grouped_gemm",
|
| 70 |
+
"layers.*.mlp.experts.down_proj": "grouped_gemm",
|
| 71 |
+
"layers.*.mlp.experts": "moe_tp_experts",
|
| 72 |
+
}
|
| 73 |
+
base_model_pp_plan = {
|
| 74 |
+
"embed_tokens": (["input_ids"], ["inputs_embeds"]),
|
| 75 |
+
"layers": (["hidden_states", "attention_mask"], ["hidden_states"]),
|
| 76 |
+
"norm": (["hidden_states"], ["hidden_states"]),
|
| 77 |
+
}
|
| 78 |
+
|
| 79 |
+
vocab_size: int = 151936
|
| 80 |
+
hidden_size: int = 2048
|
| 81 |
+
|
| 82 |
+
intermediate_size: int = 5632
|
| 83 |
+
num_hidden_layers: int = 24
|
| 84 |
+
num_attention_heads: int = 16
|
| 85 |
+
num_key_value_heads: int = 16
|
| 86 |
+
hidden_act: str = "silu"
|
| 87 |
+
max_position_embeddings: int = 128000
|
| 88 |
+
initializer_range: float = 0.02
|
| 89 |
+
rms_norm_eps: float = 1e-6
|
| 90 |
+
use_cache: bool = True
|
| 91 |
+
tie_word_embeddings: bool = True
|
| 92 |
+
rope_parameters: RopeParameters | dict | None = None
|
| 93 |
+
attention_bias: bool = False
|
| 94 |
+
attention_dropout: float | int = 0.0
|
| 95 |
+
decoder_sparse_step: int = 1
|
| 96 |
+
moe_intermediate_size: int = 1408
|
| 97 |
+
num_experts_per_tok: int = 4
|
| 98 |
+
num_experts: int = 60
|
| 99 |
+
router_aux_loss_coef: float = 0.001
|
| 100 |
+
mlp_only_layers: list[int] | None = None
|
| 101 |
+
pad_token_id: int | None = None
|
| 102 |
+
bos_token_id: int | None = None
|
| 103 |
+
eos_token_id: int | list[int] | None = None
|
| 104 |
+
base_config_key = "text_config"
|
| 105 |
+
default_theta = 500000.0
|
| 106 |
+
ignore_keys_at_rope_validation = {"mrope_section", "mrope_interleaved"}
|
| 107 |
+
head_dim: int | None = None
|
| 108 |
+
|
| 109 |
+
def __post_init__(self, **kwargs):
|
| 110 |
+
if self.num_key_value_heads is None:
|
| 111 |
+
self.num_key_value_heads = self.num_attention_heads
|
| 112 |
+
|
| 113 |
+
self.head_dim = self.head_dim or self.hidden_size // self.num_attention_heads
|
| 114 |
+
self.sliding_window = None
|
| 115 |
+
self.mlp_only_layers = [] if self.mlp_only_layers is None else self.mlp_only_layers
|
| 116 |
+
super().__post_init__(**kwargs)
|
| 117 |
+
|
| 118 |
+
|
| 119 |
+
@auto_docstring(checkpoint="Qwen/Qwen3-VL-30B-A3B-Instruct")
|
| 120 |
+
@strict
|
| 121 |
+
class Qwen3VLMoeVisionConfig(PreTrainedConfig):
|
| 122 |
+
r"""
|
| 123 |
+
out_hidden_size (`int`, *optional*, defaults to 3584):
|
| 124 |
+
The output hidden size of the vision model.
|
| 125 |
+
num_position_embeddings (`int`, *optional*, defaults to 2304):
|
| 126 |
+
The maximum sequence length that this model might ever be used with
|
| 127 |
+
deepstack_visual_indexes (`list[int]`, *optional*, defaults to `[8, 16, 24]`):
|
| 128 |
+
Indexed of layers for deepstack embeddings.
|
| 129 |
+
"""
|
| 130 |
+
|
| 131 |
+
model_type = "qwen3_vl_moe_vision"
|
| 132 |
+
base_config_key = "vision_config"
|
| 133 |
+
|
| 134 |
+
depth: int = 27
|
| 135 |
+
hidden_size: int = 1152
|
| 136 |
+
hidden_act: str = "gelu_pytorch_tanh"
|
| 137 |
+
intermediate_size: int = 4304
|
| 138 |
+
num_heads: int = 16
|
| 139 |
+
in_channels: int = 3
|
| 140 |
+
patch_size: int | list[int] | tuple[int, int] = 16
|
| 141 |
+
spatial_merge_size: int = 2
|
| 142 |
+
temporal_patch_size: int | list[int] | tuple[int, int] = 2
|
| 143 |
+
out_hidden_size: int = 3584
|
| 144 |
+
num_position_embeddings: int = 2304
|
| 145 |
+
deepstack_visual_indexes: list[int] | tuple[int, ...] = (8, 16, 24)
|
| 146 |
+
initializer_range: float = 0.02
|
| 147 |
+
|
| 148 |
+
|
| 149 |
+
@auto_docstring(checkpoint="Qwen/Qwen3-VL-30B-A3B-Instruct")
|
| 150 |
+
@strict
|
| 151 |
+
class Qwen3VLMoeConfig(PreTrainedConfig):
|
| 152 |
+
r"""
|
| 153 |
+
Example:
|
| 154 |
+
|
| 155 |
+
```python
|
| 156 |
+
>>> from transformers import Qwen3VLMoeForConditionalGeneration, Qwen3VLMoeConfig
|
| 157 |
+
|
| 158 |
+
>>> # Initializing a Qwen3-VL-MOE style configuration
|
| 159 |
+
>>> configuration = Qwen3VLMoeConfig()
|
| 160 |
+
|
| 161 |
+
>>> # Initializing a model from the Qwen3-VL-30B-A3B style configuration
|
| 162 |
+
>>> model = Qwen3VLMoeForConditionalGeneration(configuration)
|
| 163 |
+
|
| 164 |
+
>>> # Accessing the model configuration
|
| 165 |
+
>>> configuration = model.config
|
| 166 |
+
```"""
|
| 167 |
+
|
| 168 |
+
model_type = "qwen3_vl_moe"
|
| 169 |
+
sub_configs = {"vision_config": Qwen3VLMoeVisionConfig, "text_config": Qwen3VLMoeTextConfig}
|
| 170 |
+
keys_to_ignore_at_inference = ["past_key_values"]
|
| 171 |
+
|
| 172 |
+
text_config: dict | PreTrainedConfig | None = None
|
| 173 |
+
vision_config: dict | PreTrainedConfig | None = None
|
| 174 |
+
image_token_id: int = 151655
|
| 175 |
+
video_token_id: int = 151656
|
| 176 |
+
vision_start_token_id: int = 151652
|
| 177 |
+
vision_end_token_id: int = 151653
|
| 178 |
+
tie_word_embeddings: bool = False
|
| 179 |
+
|
| 180 |
+
def __post_init__(self, **kwargs):
|
| 181 |
+
if isinstance(self.vision_config, dict):
|
| 182 |
+
self.vision_config = self.sub_configs["vision_config"](**self.vision_config)
|
| 183 |
+
elif self.vision_config is None:
|
| 184 |
+
self.vision_config = self.sub_configs["vision_config"]()
|
| 185 |
+
|
| 186 |
+
if isinstance(self.text_config, dict):
|
| 187 |
+
self.text_config = self.sub_configs["text_config"](**self.text_config)
|
| 188 |
+
elif self.text_config is None:
|
| 189 |
+
self.text_config = self.sub_configs["text_config"]()
|
| 190 |
+
|
| 191 |
+
super().__post_init__(**kwargs)
|
| 192 |
+
|
| 193 |
+
|
| 194 |
+
__all__ = ["Qwen3VLMoeConfig", "Qwen3VLMoeTextConfig", "Qwen3VLMoeVisionConfig"]
|
LTA_openwebtext_dualt/mini_owt_logdirichlet/logs/infer_not5_bottleneck128_170k_decode32_ema_20260611/lr2e3.log
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
checkpoint=runs/owt_t5_elftokenized_full_len1024_C1_to_1024_pow1_d768_l12_h12_gbs512_2x8gpu_50ep_lr2e3_ema0p9999_elfopt_not5_bottleneck128_unfixed_norm_stateprobadd_selfcond_ce_fast_20260609_150828/step_170000.pt
|
| 2 |
+
use_ema=1
|
| 3 |
+
step=170000
|
| 4 |
+
decode_steps=32
|
| 5 |
+
n=64 chunk_n=8 gpu=1
|
| 6 |
+
out_base=/e2e-data/evad-tech-vla/wanghan58/workspace/LTA_openwebtext_dualt/docs/lta_samples/metrics_20260611
|
| 7 |
+
[2026-06-11T21:37:16+00:00] infer step=170000 decode=32 -> /e2e-data/evad-tech-vla/wanghan58/workspace/LTA_openwebtext_dualt/docs/lta_samples/metrics_20260611/owt_t5_not5_bottleneck128_norm_stateprobadd_selfcond_ce_fast_lr2e3_ema0p9999_step170000_ema_sc1p0_decode32_n64
|
| 8 |
+
[2026-06-11T21:37:16+00:00] run decode=32 chunk=0 n=8 seed=123
|
| 9 |
+
[2026-06-11T21:37:23+00:00] done decode=32 chunk=0
|
| 10 |
+
[2026-06-11T21:37:23+00:00] run decode=32 chunk=1 n=8 seed=124
|
| 11 |
+
[2026-06-11T21:37:30+00:00] done decode=32 chunk=1
|
| 12 |
+
[2026-06-11T21:37:30+00:00] run decode=32 chunk=2 n=8 seed=125
|
| 13 |
+
[2026-06-11T21:37:37+00:00] done decode=32 chunk=2
|
| 14 |
+
[2026-06-11T21:37:37+00:00] run decode=32 chunk=3 n=8 seed=126
|
| 15 |
+
[2026-06-11T21:37:43+00:00] done decode=32 chunk=3
|
| 16 |
+
[2026-06-11T21:37:43+00:00] run decode=32 chunk=4 n=8 seed=127
|
| 17 |
+
[2026-06-11T21:37:50+00:00] done decode=32 chunk=4
|
| 18 |
+
[2026-06-11T21:37:50+00:00] run decode=32 chunk=5 n=8 seed=128
|
| 19 |
+
[2026-06-11T21:37:57+00:00] done decode=32 chunk=5
|
| 20 |
+
[2026-06-11T21:37:57+00:00] run decode=32 chunk=6 n=8 seed=129
|
| 21 |
+
[2026-06-11T21:38:04+00:00] done decode=32 chunk=6
|
| 22 |
+
[2026-06-11T21:38:04+00:00] run decode=32 chunk=7 n=8 seed=130
|
| 23 |
+
[2026-06-11T21:38:11+00:00] done decode=32 chunk=7
|
| 24 |
+
merged 64 samples -> /e2e-data/evad-tech-vla/wanghan58/workspace/LTA_openwebtext_dualt/docs/lta_samples/metrics_20260611/owt_t5_not5_bottleneck128_norm_stateprobadd_selfcond_ce_fast_lr2e3_ema0p9999_step170000_ema_sc1p0_decode32_n64/sc1p0/samples64.txt
|
| 25 |
+
loading scorer /e2e-data/evad-tech-vla/wanghan58/models/flowtext_scorers/gpt2-large-standard dtype=fp32 device=cuda
|
| 26 |
+
run kind ppl mean_entropy distinct_1 distinct_2 top_token_mass eos_rows eos_total ppl_tokens t5_tokens path
|
| 27 |
+
sc1p0 raw_full 36.813703657387094 5.18392545332874 0.08469329900856587 0.5129332802108554 0.026417812102545242 62 63 60904 65259 /e2e-data/evad-tech-vla/wanghan58/workspace/LTA_openwebtext_dualt/docs/lta_samples/metrics_20260611/owt_t5_not5_bottleneck128_norm_stateprobadd_selfcond_ce_fast_lr2e3_ema0p9999_step170000_ema_sc1p0_decode32_n64/sc1p0
|
| 28 |
+
sc1p0 pre_eos 40.30085154584371 5.192043916306752 0.08625290656845457 0.5223477636630357 0.02690429001701025 0 0 58501 64079 /e2e-data/evad-tech-vla/wanghan58/workspace/LTA_openwebtext_dualt/docs/lta_samples/metrics_20260611/owt_t5_not5_bottleneck128_norm_stateprobadd_selfcond_ce_fast_lr2e3_ema0p9999_step170000_ema_sc1p0_decode32_n64/sc1p0
|
| 29 |
+
[2026-06-11T21:38:24+00:00] done
|