Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/guidellm/benchmark/progress.py
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ def format_progress_display(
decimal_places: Optional[int] = None,
) -> str:
if decimal_places is None and digits_places is None:
formatted_number = f"{value}:.0f"
formatted_number = f"{value:.0f}"
elif digits_places is None:
formatted_number = f"{value:.{decimal_places}f}"
elif decimal_places is None:
Expand Down
1 change: 0 additions & 1 deletion src/guidellm/objects/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from .pydantic import StandardBaseModel, StatusBreakdown
from .statistics import (
DistributionSummary,
Percentiles,
Expand Down
89 changes: 0 additions & 89 deletions src/guidellm/objects/pydantic.py

This file was deleted.

100 changes: 93 additions & 7 deletions src/guidellm/utils/__init__.py
Original file line number Diff line number Diff line change
@@ -1,39 +1,125 @@
from .colors import Colors
from .auto_importer import AutoImporterMixin
from .console import Colors, Console, ConsoleUpdateStep, StatusIcons, StatusStyles
from .default_group import DefaultGroupHandler
from .dict import recursive_key_update
from .encoding import (
Encoder,
EncodingTypesAlias,
MessageEncoding,
SerializationTypesAlias,
Serializer,
)
from .functions import (
all_defined,
safe_add,
safe_divide,
safe_format_timestamp,
safe_getattr,
safe_multiply,
)
from .hf_datasets import (
SUPPORTED_TYPES,
save_dataset_to_file,
)
from .hf_transformers import (
check_load_processor,
)
from .messaging import (
InterProcessMessaging,
InterProcessMessagingManagerQueue,
InterProcessMessagingPipe,
InterProcessMessagingQueue,
SendMessageT,
)
from .mixins import InfoMixin
from .pydantic_utils import (
PydanticClassRegistryMixin,
ReloadableBaseModel,
StandardBaseDict,
StandardBaseModel,
StatusBreakdown,
)
from .random import IntegerRangeSampler
from .registry import RegistryMixin, RegistryObjT
from .singleton import SingletonMixin, ThreadSafeSingletonMixin
from .statistics import (
DistributionSummary,
Percentiles,
RunningStats,
StatusDistributionSummary,
TimeRunningStats,
)
from .synchronous import (
wait_for_sync_barrier,
wait_for_sync_event,
wait_for_sync_objects,
)
from .text import (
EndlessTextCreator,
camelize_str,
clean_text,
filter_text,
is_puncutation,
format_value_display,
is_punctuation,
load_text,
split_text,
split_text_list_by_length,
)
from .typing import get_literal_vals

__all__ = [
"SUPPORTED_TYPES",
"AutoImporterMixin",
"Colors",
"Colors",
"Console",
"ConsoleUpdateStep",
"DefaultGroupHandler",
"DistributionSummary",
"Encoder",
"EncodingTypesAlias",
"EndlessTextCreator",
"InfoMixin",
"IntegerRangeSampler",
"camelize_str",
"InterProcessMessaging",
"InterProcessMessagingManagerQueue",
"InterProcessMessagingPipe",
"InterProcessMessagingQueue",
"MessageEncoding",
"MessageEncoding",
"Percentiles",
"PydanticClassRegistryMixin",
"RegistryMixin",
"RegistryObjT",
"ReloadableBaseModel",
"RunningStats",
"SendMessageT",
"SerializationTypesAlias",
"Serializer",
"SingletonMixin",
"StandardBaseDict",
"StandardBaseModel",
"StatusBreakdown",
"StatusDistributionSummary",
"StatusIcons",
"StatusStyles",
"ThreadSafeSingletonMixin",
"TimeRunningStats",
"all_defined",
"check_load_processor",
"clean_text",
"filter_text",
"is_puncutation",
"format_value_display",
"get_literal_vals",
"is_punctuation",
"load_text",
"recursive_key_update",
"safe_add",
"safe_divide",
"safe_format_timestamp",
"safe_getattr",
"safe_multiply",
"save_dataset_to_file",
"split_text",
"split_text_list_by_length",
"wait_for_sync_barrier",
"wait_for_sync_event",
"wait_for_sync_objects",
]
98 changes: 98 additions & 0 deletions src/guidellm/utils/auto_importer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
"""
Automatic module importing utilities for dynamic class discovery.

This module provides a mixin class for automatic module importing within a package,
enabling dynamic discovery of classes and implementations without explicit imports.
It is particularly useful for auto-registering classes in a registry pattern where
subclasses need to be discoverable at runtime.

The AutoImporterMixin can be combined with registration mechanisms to create
extensible systems where new implementations are automatically discovered and
registered when they are placed in the correct package structure.
"""

from __future__ import annotations

import importlib
import pkgutil
import sys
from typing import ClassVar

__all__ = ["AutoImporterMixin"]


class AutoImporterMixin:
"""
Mixin class for automatic module importing within packages.

This mixin enables dynamic discovery of classes and implementations without
explicit imports by automatically importing all modules within specified
packages. It is designed for use with class registration mechanisms to enable
automatic discovery and registration of classes when they are placed in the
correct package structure.

Example:
::
from guidellm.utils import AutoImporterMixin

class MyRegistry(AutoImporterMixin):
auto_package = "my_package.implementations"

MyRegistry.auto_import_package_modules()

:cvar auto_package: Package name or tuple of package names to import modules from
:cvar auto_ignore_modules: Module names to ignore during import
:cvar auto_imported_modules: List tracking which modules have been imported
"""

auto_package: ClassVar[str | tuple[str, ...] | None] = None
auto_ignore_modules: ClassVar[tuple[str, ...] | None] = None
auto_imported_modules: ClassVar[list[str] | None] = None

@classmethod
def auto_import_package_modules(cls) -> None:
"""
Automatically import all modules within the specified package(s).

Scans the package(s) defined in the `auto_package` class variable and imports
all modules found, tracking them in `auto_imported_modules`. Skips packages
(directories) and any modules listed in `auto_ignore_modules`.

:raises ValueError: If the `auto_package` class variable is not set
"""
if cls.auto_package is None:
raise ValueError(
"The class variable 'auto_package' must be set to the package name to "
"import modules from."
)

cls.auto_imported_modules = []
packages = (
cls.auto_package
if isinstance(cls.auto_package, tuple)
else (cls.auto_package,)
)

for package_name in packages:
package = importlib.import_module(package_name)

for _, module_name, is_pkg in pkgutil.walk_packages(
package.__path__, package.__name__ + "."
):
if (
is_pkg
or (
cls.auto_ignore_modules is not None
and module_name in cls.auto_ignore_modules
)
or module_name in cls.auto_imported_modules
):
# Skip packages and ignored modules
continue

if module_name in sys.modules:
# Avoid circular imports
cls.auto_imported_modules.append(module_name)
else:
importlib.import_module(module_name)
cls.auto_imported_modules.append(module_name)
2 changes: 1 addition & 1 deletion src/guidellm/utils/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def __init__(self, *types: click.ParamType):
self.types = types
self.name = "".join(t.name for t in types)

def convert(self, value, param, ctx): # noqa: RET503
def convert(self, value, param, ctx):
fails = []
for t in self.types:
try:
Expand Down
Loading
Loading