TensorPlay
Copy
View Markdown

Source code for tensorplay.serialization.policy

"""Runtime policy and safety controls for checkpoint loading."""

from __future__ import annotations

import io
import mmap as _mmap
import os
import pickletools
import threading
import zipfile
from contextlib import contextmanager
from enum import Enum
from typing import Any


class LoadEndianness(Enum):
    NATIVE = 1
    LITTLE = 2
    BIG = 3


class _SerializationState(threading.local):
    def __init__(self):
        super().__init__()
        self.skip_data = False
        self.materialize_fake_tensors = False


_serialization_state = _SerializationState()
_default_load_endianness: LoadEndianness | None = None
_compute_crc32 = True
_default_mmap_options = getattr(_mmap, "MAP_PRIVATE", None)
_user_safe_globals: dict[str, Any] = {}


def _get_safe_global(module: str, name: str):
    return _user_safe_globals.get(f"{module}.{name}")


def _skip_payload_data() -> bool:
    return bool(_serialization_state.skip_data)



[docs]
def get_default_load_endianness() -> LoadEndianness | None:
    return _default_load_endianness




[docs]
def set_default_load_endianness(endianness):
    global _default_load_endianness
    if endianness is not None and not isinstance(endianness, LoadEndianness):
        raise TypeError("endianness must be LoadEndianness or None")
    _default_load_endianness = endianness




[docs]
def get_crc32_options() -> bool:
    return _compute_crc32




[docs]
def set_crc32_options(compute_crc32: bool):
    global _compute_crc32
    if not isinstance(compute_crc32, bool):
        raise TypeError("compute_crc32 must be bool")
    _compute_crc32 = compute_crc32




[docs]
def get_default_mmap_options() -> int | None:
    return _default_mmap_options



def _mmap_access():
    """Translate the public mapping flags into the Python mmap access mode."""

    if _default_mmap_options == getattr(_mmap, "MAP_SHARED", None):
        return _mmap.ACCESS_WRITE
    return _mmap.ACCESS_COPY


def _mmap_file(fd: int, *, filename: str | os.PathLike[str] | None = None):
    access = _mmap_access()
    try:
        return _mmap.mmap(fd, 0, access=access)
    except (OSError, ValueError):
        if access != _mmap.ACCESS_WRITE or filename is None:
            raise
        flags = os.O_RDWR | int(getattr(os, "O_BINARY", 0))
        writable_fd = os.open(os.fspath(filename), flags)
        try:
            return _mmap.mmap(writable_fd, 0, access=access)
        finally:
            os.close(writable_fd)



[docs]
class set_default_mmap_options:
    def __init__(self, flags: int):
        global _default_mmap_options
        private = getattr(_mmap, "MAP_PRIVATE", None)
        shared = getattr(_mmap, "MAP_SHARED", None)
        if flags not in {private, shared}:
            raise ValueError("flags must be mmap.MAP_PRIVATE or mmap.MAP_SHARED")
        self.previous = _default_mmap_options
        _default_mmap_options = flags

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        global _default_mmap_options
        _default_mmap_options = self.previous



def _global_name(value: Any) -> str:
    module = getattr(value, "__module__", None)
    qualname = getattr(value, "__qualname__", None)
    if not module or not qualname:
        raise TypeError("safe globals must expose __module__ and __qualname__")
    return f"{module}.{qualname}"


def _normalize_safe_globals(values) -> dict[str, Any]:
    if isinstance(values, (str, bytes)):
        raise TypeError("safe_globals must be an iterable of objects")
    normalized = {}
    for value in values:
        if isinstance(value, tuple):
            if len(value) != 2:
                raise ValueError("safe global tuples must contain two items")
            obj, name = value
            if not isinstance(name, str) or not name:
                raise TypeError("safe global names must be non-empty strings")
        else:
            obj, name = value, _global_name(value)
        normalized[name] = obj
    return normalized



[docs]
def clear_safe_globals() -> None:
    _user_safe_globals.clear()




[docs]
def get_safe_globals() -> list[Any]:
    return list(_user_safe_globals.values())




[docs]
def add_safe_globals(values) -> None:
    _user_safe_globals.update(_normalize_safe_globals(values))




[docs]
class safe_globals:
    def __init__(self, values):
        self.values = _normalize_safe_globals(values)
        self.previous = None

    def __enter__(self):
        self.previous = dict(_user_safe_globals)
        _user_safe_globals.update(self.values)
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        _user_safe_globals.clear()
        _user_safe_globals.update(self.previous or {})



_DEFAULT_SAFE_GLOBAL_NAMES = {
    "tensorplay.Tensor",
    "tensorplay.Size",
    "tensorplay.device",
    "tensorplay.strided",
    "tensorplay.sparse_coo",
    "tensorplay.sparse_csr",
    "tensorplay.sparse_csc",
    "tensorplay.sparse_bsr",
    "tensorplay.sparse_bsc",
    "tensorplay._utils._rebuild_tensor",
    "tensorplay._utils._rebuild_tensor_v2",
    "tensorplay._utils._rebuild_tensor_v3",
    "tensorplay._utils._rebuild_parameter",
    "tensorplay._utils._rebuild_parameter_with_state",
    "tensorplay.nn.parameter._rebuild_parameter",
    "tensorplay.nn.parameter.Parameter",
    "tensorplay.serialization._get_layout",
    "tensorplay.storage.TypedStorage",
    "tensorplay.storage.UntypedStorage",
    "collections.OrderedDict",
    "collections.defaultdict",
    "collections.Counter",
    "_codecs.encode",
    "builtins.bytearray",
    "builtins.complex",
    "builtins.frozenset",
    "builtins.set",
    "builtins.slice",
    "copyreg._reconstructor",
    "copyreg.__newobj__",
    "numpy.dtype",
    "numpy.core.multiarray._reconstruct",
    "numpy._core.multiarray._reconstruct",
}


def _checkpoint_data_pickle(fileobj) -> bytes:
    start = fileobj.tell()
    try:
        fileobj.seek(0)
        with zipfile.ZipFile(fileobj) as archive:
            names = set(archive.namelist())
            if "data.pkl" in names:
                return archive.read("data.pkl")
            suffix = "/data.pkl"
            roots = {name[:-len("data.pkl")] for name in names if name.endswith(suffix)}
            if len(roots) == 1:
                return archive.read(next(iter(roots)) + "data.pkl")
    except (OSError, ValueError, zipfile.BadZipFile, KeyError) as error:
        raise ValueError("expected a zip checkpoint with data.pkl") from error
    finally:
        fileobj.seek(start)
    raise ValueError("checkpoint does not contain data.pkl")



[docs]
def get_unsafe_globals_in_checkpoint(f) -> list[str]:
    should_close = False
    if isinstance(f, (str, os.PathLike)):
        f = open(os.fspath(f), "rb")
        should_close = True
    try:
        data = _checkpoint_data_pickle(f)
        names = set()
        string_stack = []
        for opcode, arg, _position in pickletools.genops(data):
            if opcode.name == "GLOBAL" and isinstance(arg, str):
                module, name = arg.split(" ", 1)
                names.add(f"{module}.{name}")
            elif opcode.name in {
                "BINSTRING",
                "SHORT_BINSTRING",
                "BINUNICODE",
                "SHORT_BINUNICODE",
                "UNICODE",
            }:
                if isinstance(arg, bytes):
                    try:
                        arg = arg.decode("utf-8")
                    except UnicodeDecodeError:
                        arg = None
                string_stack.append(arg if isinstance(arg, str) else None)
            elif opcode.name == "STACK_GLOBAL" and len(string_stack) >= 2:
                module, name = string_stack[-2:]
                if isinstance(module, str) and isinstance(name, str):
                    names.add(f"{module}.{name}")
                del string_stack[-2:]
        return sorted(names - _DEFAULT_SAFE_GLOBAL_NAMES - set(_user_safe_globals))
    finally:
        if should_close:
            f.close()




[docs]
class skip_data:
    def __init__(self, materialize_fake_tensors: bool = False):
        if not isinstance(materialize_fake_tensors, bool):
            raise TypeError("materialize_fake_tensors must be bool")
        self.materialize_fake_tensors = materialize_fake_tensors
        self.previous = None

    def __enter__(self):
        self.previous = (
            _serialization_state.skip_data,
            _serialization_state.materialize_fake_tensors,
        )
        _serialization_state.skip_data = True
        _serialization_state.materialize_fake_tensors = self.materialize_fake_tensors
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        old_skip, old_materialize = self.previous
        _serialization_state.skip_data = old_skip
        _serialization_state.materialize_fake_tensors = old_materialize



@contextmanager
def serialization_state():
    yield _serialization_state


__all__ = [
    "LoadEndianness",
    "add_safe_globals",
    "clear_safe_globals",
    "get_crc32_options",
    "get_default_load_endianness",
    "get_default_mmap_options",
    "get_safe_globals",
    "get_unsafe_globals_in_checkpoint",
    "safe_globals",
    "serialization_state",
    "set_crc32_options",
    "set_default_load_endianness",
    "set_default_mmap_options",
    "skip_data",
]
Ask DeepWiki