Files
sglang/.claude/rules/no-getattr-defensive.md

1.2 KiB

paths
paths
**/*.py

Don't use getattr / hasattr for defensive access

Over-defensive getattr(obj, "field", default) / hasattr(obj, "field") hide errors and defeat strict type checking. If a field is always present, accessing it defensively is confusing and masks real bugs. Prefer:

  1. isinstance for type narrowing — check the type, then access fields directly:

    if (
        isinstance(obj, (TokenizedGenerateReqInput, TokenizedEmbeddingReqInput))
        and obj.mm_inputs
    ):
    

    (see python/sglang/srt/managers/mm_utils.py)

  2. Always set the field (to None if needed), then do a None check — the field should always exist, so a None / non-None check is enough:

    obj.field = None   # in __init__ / construction
    ...
    if obj.field is not None:
        ...
    

Bad — server_args always has revision, so getattr is misleading and swallows a real AttributeError if the field is ever renamed:

revision=getattr(server_args, "revision", None),   # BAD
revision=server_args.revision,                     # GOOD

(see python/sglang/srt/managers/template_detection.py)