Implementation:Bentoml BentoML Internal Types
| Knowledge Sources | |
|---|---|
| Domains | Type System, Lazy Loading, File I/O |
| Last Updated | 2026-02-13 15:00 GMT |
Overview
The Internal Types module defines foundational type aliases, the LazyType utility class for deferred type checking without eager imports, the FileLike wrapper for file-like objects, and the is_compatible_type compatibility checker used throughout BentoML's internals.
Description
This module provides core type infrastructure used extensively across BentoML's codebase. Key components include:
Type aliases and constants:
MetadataType: A recursive TypeAlias for metadata values (str, bytes, bool, int, float, complex, datetime variants, and nested lists/tuples/dicts).MetadataDict:Dict[str, MetadataType].JSONSerializable: Union of JSON-compatible types (str, int, float, bool, None, list, dict).PathType:str | os.PathLike[str].ModelSignatureDict: TypedDict for model signature configuration (batchable, batch_dim, input_spec, output_spec).LifecycleHook: Callable type for Starlette lifecycle hooks.BATCH_HEADER,HEADER_CHARSET,JSON_CHARSET: Protocol constants.AnyType: Union ofType[Any],UnionType, andLazyType[Any](runtime fallback toAny).
LazyType[T] (Generic class): A deferred type reference that resolves classes lazily. Solves three key conflicts:
- Lazy isinstance:
LazyType("numpy.ndarray").isinstance(obj)avoids importing numpy at check time. The class is only resolved fromsys.moduleswhen needed (without triggering an import unlessimport_module=True). - Type narrowing: Works with
TypeGuard[T](PEP 647) so thatLazyType["NDArray"]("numpy.ndarray").isinstance(obj)narrows the type for type checkers. - Type comparison:
LazyType("numpy.ndarray") == numpy.ndarrayworks by comparing module and qualname strings. Hashable, so usable as dictionary keys.
Construction supports three forms:
LazyType("numpy", "ndarray"): Module and qualname as separate strings.LazyType("numpy.ndarray"): Dotted path auto-split on last dot.LazyType(numpy.ndarray): From an already-imported class.
Methods:
get_class(import_module=True): Resolves and returns the actual class, optionally importing the module.isinstance(obj): Checks isinstance without importing (returns False if module not loaded).issubclass(klass): Checks issubclass without importing.from_type(cls, typ_): Factory that wraps a raw type in LazyType or returns an existing LazyType.__instancecheck__: Enablesisinstance(obj, LazyType(...))syntax.
is_compatible_type(t1, t2): Checks whether two types could share instances. Handles Union types by recursing into their args. Resolves LazyTypes. For concrete types, checks mutual subclass relationship. Returns True for unsupported cases as a safe default.
FileLike[AnyStr] (dataclass, extends io.IOBase): A generic wrapper for file-like objects that adds a custom name property. Delegates all IO operations (read, write, seek, tell, close, etc.) to the wrapped _wrapped object. Supports both text and binary modes via the AnyStr type variable.
Usage
LazyType is used extensively in IO descriptors and runner containers for type checking without eagerly importing heavy dependencies like NumPy, Pandas, or PIL. FileLike is used for wrapping file objects with custom names. The type aliases provide consistent typing across the codebase.
Code Reference
Source Location
- Repository: Bentoml_BentoML
- File: src/bentoml/_internal/types.py
- Lines: 1-331
Signature
class LazyType(t.Generic[T]):
module: str
qualname: str
@t.overload
def __init__(self, module_or_cls: str, qualname: str) -> None: ...
@t.overload
def __init__(self, module_or_cls: t.Type[T]) -> None: ...
@t.overload
def __init__(self, module_or_cls: str) -> None: ...
@classmethod
def from_type(cls, typ_: t.Union[LazyType[T], t.Type[T]]) -> LazyType[T]: ...
def get_class(self, import_module: bool = True) -> t.Type[T]: ...
def isinstance(self, obj: t.Any) -> t.TypeGuard[T]: ...
def issubclass(self, klass: type) -> bool: ...
def is_compatible_type(t1: AnyType, t2: AnyType) -> bool: ...
@dataclass(frozen=False)
class FileLike(t.Generic[t.AnyStr], io.IOBase):
_wrapped: t.IO[t.AnyStr]
_name: str
def read(self, size: int = -1) -> t.AnyStr: ...
def write(self, s: t.AnyStr) -> int: ...
def seek(self, offset: int, whence: int = io.SEEK_SET) -> int: ...
# ... (all standard IO methods delegated to _wrapped)
Import
from bentoml._internal.types import LazyType
from bentoml._internal.types import FileLike
from bentoml._internal.types import is_compatible_type
from bentoml._internal.types import MetadataDict
from bentoml._internal.types import JSONSerializable
I/O Contract
Inputs (LazyType)
| Name | Type | Required | Description |
|---|---|---|---|
| module_or_cls | str or Type[T] | Yes | Module path string (e.g., "numpy.ndarray"), module and qualname pair, or an actual class reference. |
| qualname | str or None | No | Class qualname when module is provided as a separate string. |
Outputs (LazyType)
| Name | Type | Description |
|---|---|---|
| LazyType[T] | LazyType | A lazy type reference that can check isinstance/issubclass without importing and resolves to the actual class on demand. |
Inputs (FileLike)
| Name | Type | Required | Description |
|---|---|---|---|
| _wrapped | IO[AnyStr] | Yes | The underlying file-like object to delegate operations to. |
| _name | str | Yes | Custom name for the file-like object. |
Outputs (FileLike)
| Name | Type | Description |
|---|---|---|
| FileLike[AnyStr] | FileLike | A file-like wrapper that delegates all IO operations to the wrapped object with a custom name. |
Usage Examples
from bentoml._internal.types import LazyType, FileLike, is_compatible_type
import io
# LazyType usage - isinstance without importing numpy
obj = [1, 2, 3]
if LazyType("numpy.ndarray").isinstance(obj):
print("It's an ndarray")
else:
print("Not an ndarray")
# LazyType as dictionary key
HANDLER_MAP = {
LazyType("numpy.ndarray"): lambda x: "ndarray_handler",
LazyType("pandas.DataFrame"): lambda x: "dataframe_handler",
}
# LazyType comparison
import numpy as np
assert LazyType("numpy", "ndarray") == np.ndarray
# is_compatible_type check
assert is_compatible_type(int, int) is True
assert is_compatible_type(int, str) is False
# FileLike wrapper
buffer = io.BytesIO(b"hello world")
f = FileLike(_wrapped=buffer, _name="my_file.bin")
assert f.name == "my_file.bin"
data = f.read() # b"hello world"