Skip to content

Add package disdantic to handle Pydantic polymorphic registries#919

Open
SkiHatDuckie wants to merge 13 commits into
vllm-project:mainfrom
SkiHatDuckie:disdantic
Open

Add package disdantic to handle Pydantic polymorphic registries#919
SkiHatDuckie wants to merge 13 commits into
vllm-project:mainfrom
SkiHatDuckie:disdantic

Conversation

@SkiHatDuckie

@SkiHatDuckie SkiHatDuckie commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds the disdantic package to supply the functionality for Pydantic subclass registries, dynamic polymorphism unions and automatic model discovery. This replaces multiple Pydantic utility classes that are currently GuideLLM's responsibility to maintain.

The motive for these changes was to assist in making GuideLLM simpler for maintainers and community members to contribute to by offloading functionality that is not necessarily the point of the software to elsewhere.

Many files have been changed, but many of those changes are just the switching around of imports. Files with substantial changes are mentioned in Details.

Details

pyproject.toml & tests/unit/test_settings.py

  • Added disdantic as a dependency
  • Disabled parent schema rebuilding
    • Added test to ensure this is applied globally

schemas/base.py

  • Removed PydanticClassRegistryMixin. Replaced with a subclass of the same name which inherits disdantic.PydanticClassRegistryMixin, imported as BasePydanticClassRegistryMixin. Includes a couple methods that portions of GuideLLM expect which disdantic's version currently does not support:
    • Preventing direct instantiation of base classes that use the mixin
    • Getting a list of all registered names from the registry
  • Removed ReloadableBaseModel. Replaced with disdantic.ReloadableBaseModel

utils/registry.py

  • Removed RegistryMixin. Replaced with disdantic.RegistryMixin
  • TypeVar's RegisterT and RegistryObjT remain. Although disdantic has equivalents to these, they are not included in __all__ which makes me think they're not intended to be public facing

tests/unit/schemas/test_base.py & tests/unit/utils/registry.py

  • Several tests removed

benchmark/benchmarker.py

  • Added metaclass BenchmarkerMeta. This solely exists to avoid a metaclass conflict between disdantic.SingletonMeta and ABCMeta in Benchmarker
  • Thread lock now stored directly in Benchmarker

scheduler/scheduler.py & tests/integration/scheduler/test_scheduler.py & tests/unit/scheduler/test_scheduler.py

  • Replaced ThreadSafeSingletonMixin with disdantic.SingletonMeta in Scheduler
  • Thread lock now stored directly in Scheduler
  • Update tests to work with new interface

Removed files:

  • utils/mixins.py (replaced by disdantic.InfoMixin)
  • utils/auto_importer.py (replaced by disdantic.AutoImporterMixin)
  • utils/singleton.py (replaced by disdantic.SingletonMeta)
  • tests/unit/utils/test_mixins.py
  • tests/unit/utils/test_auto_importer.py
  • tests/unit/utils/test_singleton.py

Misc

  • Updated uv.lock

Test Plan

  • uv sync --frozen, or some other means to update the local venv
  • tox

Related Issues


  • "I certify that all code in this PR is my own, except as noted below."

Use of AI

  • Includes code generated or substantially modified by an AI agent
  • Includes tests generated or substantially modified by an AI agent

NOTE: the Generated-by or Assisted-by trailers should be used in git commit messages when code or tests were generated or substantially modified by an AI agent, as described in the project's DEVELOPING.md file.


git log

commit e9c993f
Author: SkiHatDuckie SkiHatDuckie@gmail.com
Date: Thu Jul 2 09:24:46 2026 -0400

Include disdantic

Signed-off-by: SkiHatDuckie <SkiHatDuckie@gmail.com>

commit 42fc629
Author: SkiHatDuckie SkiHatDuckie@gmail.com
Date: Thu Jul 2 09:26:01 2026 -0400

Swapout PydanticClassRegistryMixin, RegistryMixin and ReloadableBaseModel with disdantic versions

Signed-off-by: SkiHatDuckie <SkiHatDuckie@gmail.com>

commit 7fb7ea0
Author: SkiHatDuckie SkiHatDuckie@gmail.com
Date: Thu Jul 2 09:50:35 2026 -0400

Replace InfoMixin w/ disdantic version

Signed-off-by: SkiHatDuckie <SkiHatDuckie@gmail.com>

commit c0cf7a4
Author: SkiHatDuckie SkiHatDuckie@gmail.com
Date: Thu Jul 2 09:56:22 2026 -0400

Remove AutoImporterMixin

Signed-off-by: SkiHatDuckie <SkiHatDuckie@gmail.com>

commit 8118bd6
Author: SkiHatDuckie SkiHatDuckie@gmail.com
Date: Mon Jul 6 14:28:51 2026 -0400

Update files after rebase

Signed-off-by: SkiHatDuckie <SkiHatDuckie@gmail.com>

commit 98f5880
Author: SkiHatDuckie SkiHatDuckie@gmail.com
Date: Tue Jul 7 10:39:55 2026 -0400

Disable parent schema rebuilding

Signed-off-by: SkiHatDuckie <SkiHatDuckie@gmail.com>

commit cad523e
Author: SkiHatDuckie SkiHatDuckie@gmail.com
Date: Tue Jul 7 15:26:02 2026 -0400

Lint fix

Signed-off-by: SkiHatDuckie <SkiHatDuckie@gmail.com>

commit de57e93
Author: SkiHatDuckie SkiHatDuckie@gmail.com
Date: Wed Jul 8 14:32:40 2026 -0400

Replace Singleton classes with disdantic SingletonMeta

Signed-off-by: SkiHatDuckie <SkiHatDuckie@gmail.com>

commit a758165
Author: SkiHatDuckie SkiHatDuckie@gmail.com
Date: Wed Jul 8 15:05:20 2026 -0400

Fix typing

Signed-off-by: SkiHatDuckie <SkiHatDuckie@gmail.com>

commit 11f66ff
Author: SkiHatDuckie SkiHatDuckie@gmail.com
Date: Wed Jul 8 16:30:03 2026 -0400

Update uv lock

Signed-off-by: SkiHatDuckie <SkiHatDuckie@gmail.com>

commit a14b49f
Author: SkiHatDuckie SkiHatDuckie@gmail.com
Date: Wed Jul 8 16:42:34 2026 -0400

Update docs

Signed-off-by: SkiHatDuckie <SkiHatDuckie@gmail.com>

commit 511699c
Author: SkiHatDuckie SkiHatDuckie@gmail.com
Date: Thu Jul 9 10:41:49 2026 -0400

Remove "_" from PydanticClassRegistryMixin

Signed-off-by: SkiHatDuckie <SkiHatDuckie@gmail.com>

Signed-off-by: SkiHatDuckie SkiHatDuckie@gmail.com

SkiHatDuckie and others added 13 commits July 8, 2026 16:10
Signed-off-by: SkiHatDuckie <SkiHatDuckie@gmail.com>
…odel with disdantic versions

Signed-off-by: SkiHatDuckie <SkiHatDuckie@gmail.com>
Signed-off-by: SkiHatDuckie <SkiHatDuckie@gmail.com>
Signed-off-by: SkiHatDuckie <SkiHatDuckie@gmail.com>
Signed-off-by: SkiHatDuckie <SkiHatDuckie@gmail.com>
Signed-off-by: SkiHatDuckie <SkiHatDuckie@gmail.com>
Signed-off-by: SkiHatDuckie <SkiHatDuckie@gmail.com>
Signed-off-by: SkiHatDuckie <SkiHatDuckie@gmail.com>
Signed-off-by: SkiHatDuckie <SkiHatDuckie@gmail.com>
Signed-off-by: SkiHatDuckie <SkiHatDuckie@gmail.com>
Signed-off-by: SkiHatDuckie <SkiHatDuckie@gmail.com>
Signed-off-by: SkiHatDuckie <SkiHatDuckie@gmail.com>
@dbutenhof dbutenhof added dependencies Pull requests that update a dependency file internal filed by core contributor or associate cleanup Internal refactoring or improvement, including CI, that's not directly user-visible. labels Jul 9, 2026

@dbutenhof dbutenhof left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well that's interesting. I pulled this an ran a few tests. Something in this (I'm not quite sure what) has broken Sam's discovery-based CLI help code. A normal GuideLLM run works fine, but guidellm run --help generates this less than helpful message:

$ uv run guidellm run --help
usage: guidellm [-h] [--disdantic_.project_root Path] [--disdantic_.default_schema_discriminator str] [--disdantic_.registry_auto_discovery bool] [--disdantic_.auto_packages list[str]] [--disdantic_.auto_ignore_modules list[str]]
                [--disdantic_.enable_schema_rebuilding bool] [--disdantic_.schema_rebuild_parents bool] [--disdantic_.info_exclude_keys list[str]]

Central configuration store and validation schema for the disdantic package.

This class serves as the single source of truth for runtime configurations,
defining default options and loading overrides dynamically across modules.
It integrates with Pydantic's BaseSettings to enforce type validation,
coercion, and environment prefixing.

Example:
    .. code-block:: python

        from disdantic.settings import Settings, get_settings

        # Initialize a localized settings instance
        settings = Settings(default_schema_discriminator="custom_type")
        assert settings.default_schema_discriminator == "custom_type"

        # Retrieve the global settings singleton instance
        global_settings = get_settings()
        print(global_settings.project_root)

options:
  -h, --help            show this help message and exit
  --disdantic_.project_root Path
                        Maps the file system paths and resolves relative configuration files. (default factory: method)
  --disdantic_.default_schema_discriminator str
                        Maps and retrieves model types within Pydantic registries using this key name. (default: model_type)
  --disdantic_.registry_auto_discovery bool
                        Enables automatic scanning and loading of subclasses during registry initialization. (default: False)
  --disdantic_.auto_packages list[str]
                        Configures target package namespaces to scan, enabling dynamic model discovery across submodules. (default factory: list)
  --disdantic_.auto_ignore_modules list[str]
                        Configures submodule import paths to skip, mapping excluded modules during dynamic scanning. (default factory: list)
  --disdantic_.enable_schema_rebuilding bool
                        Enables dynamic rebuilding of validation schemas, triggering Pydantic model schema rebuilds. (default: True)
  --disdantic_.schema_rebuild_parents bool
                        Enables parent propagation, mapping validation schema updates up the subclass MRO hierarchy. (default: True)
  --disdantic_.info_exclude_keys list[str]
                        Maps specific fields to skip and exclude during InfoMixin logging. (default factory: Settings.<lambda>)

@sjmonson sjmonson left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not really seeing a benefit to this change. Looking at the disdantic package upstream it hasn't really bench touched outside the initial code dump and it doesn't look like anyone else is using it yet. The other project I know of that has this code is speculators and they still carry the code in-tree.

Not going to block but I think if we do merge (assuming Dave's comment is fixed). We likely want someone from GuideLLM to have maintainer access on that project.

@dbutenhof

Copy link
Copy Markdown
Collaborator

I am not really seeing a benefit to this change. Looking at the disdantic package upstream it hasn't really bench touched outside the initial code dump and it doesn't look like anyone else is using it yet.

I had much the same thought after looking through the repo. Doesn't necessarily mean it's a bad idea to use a package -- but you've got a good point about maintainer access to disdantic, and that power comes with the implication that we have to be willing to actually maintain our dependencies there given the lack of any real community around it. I'm not convinced that's a good idea.

@SkiHatDuckie

SkiHatDuckie commented Jul 10, 2026

Copy link
Copy Markdown
Collaborator Author

I'm personally fine with us sitting on this PR just to see if anything changes.

As for the issue with --help getting hijacked: I've been doing some debugging and seems to be caused by disdantic's Pydantic Settings enabling the cli_parse_args in it's config... with no way of disabling it via argument passing. I'll try couple ideas to patch this today, and if they don't work I'll take a break and work on something more important.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cleanup Internal refactoring or improvement, including CI, that's not directly user-visible. dependencies Pull requests that update a dependency file internal filed by core contributor or associate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants