Source code for polyxios

from polyxios import transforms
from polyxios._io import Source, open_target
from polyxios._registry import Codec, build_default_registry, resolve
from polyxios._scene import (
    SceneData,
    SceneImage,
    SceneMaterial,
    SceneNode,
    SceneTexture,
)
from polyxios._types import PolyData, make_polydata
from polyxios.exceptions import UnsupportedFormatError
from polyxios.fetcher import fetch
from polyxios.helper import read_polydata, visualize_mesh
from polyxios.validate import validate
from polyxios.version import version as __version__

_REGISTRY: dict[str, Codec] = build_default_registry()


def supported_extensions(*, registry: dict | None = None) -> list[str]:
    """List the file extensions the registry resolves.

    Almost every one of them both reads and writes. Three kinds do not, and
    are listed all the same because resolving to a message that names the
    problem beats resolving to nothing:

    - an extension several formats share, such as ``.dat``, reads by content
      and needs ``fmt=`` to write;
    - ``.plt`` resolves only to the error saying binary Tecplot is not read;
    - the ParaView meta-file extensions read but raise on write.

    Parameters
    ----------
    registry
        Custom codec registry. Uses the built-in registry if None.

    Returns
    -------
    list of str
        Sorted extensions, each with its leading dot (e.g. '.obj').
    """
    return sorted(registry or _REGISTRY)


def read(
    path: Source,
    *,
    fmt: str | None = None,
    lazy: bool = False,
    registry: dict | None = None,
    **opts: object,
) -> PolyData:
    """Read a mesh file and return a PolyData.

    Parameters
    ----------
    path
        File path to read, or an open binary file object - anything with a
        ``read``, such as ``io.BytesIO`` or a socket's ``makefile('rb')``.
        A handle is read from wherever it stands and is never closed here.
    fmt
        Format override (e.g. '.vtk'). The leading dot and the case are
        both optional, and a trailing '.gz' names the compression rather
        than the format. Inferred from the file extension if None, which a
        file object only has when it carries a usable ``name``; pass ``fmt``
        for any other buffer.
    lazy
        If True and the format supports it, use mmap for the binary data
        section so pages are loaded on demand. A file object has to be
        backed by a real file for that; an in-memory buffer raises
        LazyReadError.
    registry
        Custom codec registry. Uses the built-in registry if None.
    **opts
        Format-specific options passed to the codec's read function.

    Returns
    -------
    PolyData
        Parsed mesh data.

    Raises
    ------
    UnsupportedFormatError
        If no codec matches, or if a nameless file object was passed
        without ``fmt``.
    CodecError
        If the file object is open in text mode where the format is read as
        bytes, or if it is a stream that cannot seek where the format needs
        to look twice - at the file's size, or at its opening to tell two
        formats sharing an extension apart.
    LazyReadError
        If ``lazy`` is set and the source cannot be mapped.
    TypeError
        If an option is passed that the chosen codec's reader does not take.
    """
    codec = resolve(path, fmt, registry or _REGISTRY)
    return codec.read(path=path, lazy=lazy, **opts)


def write(
    poly: PolyData,
    path: Source,
    *,
    fmt: str | None = None,
    registry: dict | None = None,
    **opts: object,
) -> None:
    """Write a PolyData to a mesh file.

    Parameters
    ----------
    poly
        PolyData to write.
    path
        Output file path, or an open binary file object - anything with a
        ``write``, such as ``io.BytesIO``. A handle is written at wherever
        it stands and is never closed here, so a caller can keep appending
        to it afterwards.
    fmt
        Format override (e.g. '.vtk'). The leading dot and the case are
        both optional, and a trailing '.gz' compresses the output - which is
        the only way to ask a nameless buffer for gzip. Inferred from the
        file extension if None, which a file object only has when it carries
        a usable ``name``; pass ``fmt`` for any other buffer.
    registry
        Custom codec registry. Uses the built-in registry if None.
    **opts
        Format-specific options passed to the codec's write function.

    Raises
    ------
    UnsupportedFormatError
        If no codec matches, or if a nameless file object was passed
        without ``fmt``.
    CodecError
        If the file object is open in text mode where the format is written
        as bytes, or if the format refuses the destination it was given.
    """
    codec = resolve(path, fmt, registry or _REGISTRY)
    with open_target(path, fmt=fmt) as target:
        codec.write(poly=poly, path=target, **opts)


[docs] def read_scene( path: Source, *, fmt: str | None = None, registry: dict | None = None, **opts: object, ) -> SceneData: """Read a scene-graph file and return a SceneData. Parameters ---------- path Path to the scene file (e.g. ``.gltf`` or ``.glb``). fmt Format override (e.g. ``'.glb'``). Inferred from the file extension when ``None``. registry Custom codec registry. Uses the built-in registry if ``None``. **opts Format-specific options passed to the codec's ``read_scene`` function. Returns ------- SceneData Full scene graph with meshes, nodes, materials, textures, and images. Raises ------ UnsupportedFormatError If the format does not carry scene data. Use :func:`read` for flat single-mesh formats. """ codec = resolve(path, fmt, registry or _REGISTRY) if codec.read_scene is None: raise UnsupportedFormatError( "Format does not carry scene data; use polyxios.read()." ) return codec.read_scene(path=path, **opts)
[docs] def write_scene( scene: SceneData, path: Source, *, fmt: str | None = None, registry: dict | None = None, **opts: object, ) -> None: """Write a SceneData to a scene-graph file. Parameters ---------- scene SceneData to serialize. path Output file path. fmt Format override (e.g. ``'.glb'``). Inferred from the file extension when ``None``. registry Custom codec registry. Uses the built-in registry if ``None``. **opts Format-specific options passed to the codec's ``write_scene`` function (e.g. ``binary=False`` for ``.gltf`` + ``.bin``). Raises ------ UnsupportedFormatError If the format does not support scene writing. Use :func:`write` to write a flat PolyData instead. """ codec = resolve(path, fmt, registry or _REGISTRY) if codec.write_scene is None: raise UnsupportedFormatError( "Format does not support scene writing; use polyxios.write()." ) with open_target(path, fmt=fmt) as target: codec.write_scene(scene=scene, path=target, **opts)
__all__ = [ "Codec", "PolyData", "SceneData", "SceneImage", "SceneMaterial", "SceneNode", "SceneTexture", "Source", "__version__", "fetch", "make_polydata", "read", "read_polydata", "read_scene", "supported_extensions", "transforms", "validate", "visualize_mesh", "write", "write_scene", ]