-
Notifications
You must be signed in to change notification settings - Fork 6.7k
[modular] add auto_docstring & more doc related refactors #12958
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
The docs for this PR live here. All of your documentation changes will be reflected on that endpoint. The docs are available until 30 days after the last update. |
| # ====================================================== | ||
|
|
||
| @classmethod | ||
| def prompt(cls) -> "InputParam": |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
our pipeline parameter are pretty consistent across different pipelines, e.g. you always have prompt, height, width, num_inference_steps, etc. I made template for these common ones, so that it is easier to define
before you need
InputParam(
name="prompt",
type_hint=str,
required=True,
description="The prompt or prompts to guide image generation."
)now you do
InputParam.prompt()
InputParam.height(default=1024)
InputParam.num_inference_steps(default=28)
InputParam.generator()There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a bit apprehensive about introducing dedicated class methods for common parameters in this way. I think the class can become quite large as common inputs expand.
I would prefer to keep current syntax (IMO this ensures InputParams are defined in a consistent way) and use post init on the dataclass to automatically add a description. e.g
# centralised descriptions would live somewhere like constants.py
# can be used for modular + non-modular
INPUT_PARAM_TEMPLATES = {
"prompt": {"type_hint": str, "required": True, "description": "The prompt or prompts to guide image generation."},
"height": {"type_hint": int, "description": "The height in pixels of the generated image."},
"width": {"type_hint": int, "description": "The width in pixels of the generated image."},
"generator": {"type_hint": torch.Generator, "description": "Torch generator for deterministic generation."},
# ...
}
@dataclass
class InputParam:
name: str = None
type_hint: Any = None
required: bool = False
default: Any = None
description: str = None
def __post_init__(self):
if not self.name or self.name not in INPUT_PARAM_TEMPLATES:
return
template = INPUT_PARAM_TEMPLATES[self.name]
if self.type_hint is None:
self.type_hint = template.get("type_hint")
if self.description is None:
self.description = template.get("description")If we feel that methods for these inputs are necessary, one way to address it without adding individual methods to the InputParam is to use a metaclass. It would result in the InputParam object being less crowded.
class InputParamMeta(type):
def __getattr__(cls, name: str):
if name in INPUT_PARAM_TEMPLATES:
def factory(**overrides):
return cls(name=name, **overrides)
return factory
raise AttributeError(f"No template named '{name}'")
@dataclass
class InputParam(metaclass=InputParamMeta):|
|
||
| # auto_docstring | ||
| class QwenImageAutoTextEncoderStep(AutoPipelineBlocks): | ||
| """ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these are all auto generated docstring
| # ==================== | ||
|
|
||
|
|
||
| # auto_docstring |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add this mark and then run
python utils/modular_auto_docstring.py --fix_and_overwrite| prompt (`str`, *optional*): | ||
| The prompt or prompts to guide image generation. | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit but I would format so that there's no newline between fields.
| # auto_docstring | ||
| class QwenImageAutoTextEncoderStep(AutoPipelineBlocks): | ||
| """ | ||
| class QwenImageAutoTextEncoderStep |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would remove this line being generated in the auto doc
| Components: | ||
| image_mask_processor (`InpaintProcessor`) [subfolder=] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO just the type hint for the component is sufficient. No need for subfolder information
| # ====================================================== | ||
|
|
||
| @classmethod | ||
| def prompt(cls) -> "InputParam": |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a bit apprehensive about introducing dedicated class methods for common parameters in this way. I think the class can become quite large as common inputs expand.
I would prefer to keep current syntax (IMO this ensures InputParams are defined in a consistent way) and use post init on the dataclass to automatically add a description. e.g
# centralised descriptions would live somewhere like constants.py
# can be used for modular + non-modular
INPUT_PARAM_TEMPLATES = {
"prompt": {"type_hint": str, "required": True, "description": "The prompt or prompts to guide image generation."},
"height": {"type_hint": int, "description": "The height in pixels of the generated image."},
"width": {"type_hint": int, "description": "The width in pixels of the generated image."},
"generator": {"type_hint": torch.Generator, "description": "Torch generator for deterministic generation."},
# ...
}
@dataclass
class InputParam:
name: str = None
type_hint: Any = None
required: bool = False
default: Any = None
description: str = None
def __post_init__(self):
if not self.name or self.name not in INPUT_PARAM_TEMPLATES:
return
template = INPUT_PARAM_TEMPLATES[self.name]
if self.type_hint is None:
self.type_hint = template.get("type_hint")
if self.description is None:
self.description = template.get("description")If we feel that methods for these inputs are necessary, one way to address it without adding individual methods to the InputParam is to use a metaclass. It would result in the InputParam object being less crowded.
class InputParamMeta(type):
def __getattr__(cls, name: str):
if name in INPUT_PARAM_TEMPLATES:
def factory(**overrides):
return cls(name=name, **overrides)
return factory
raise AttributeError(f"No template named '{name}'")
@dataclass
class InputParam(metaclass=InputParamMeta):
This PR adds a utility script
utils/modular_auto_docstring.pythat automatically generates docstrings for modular pipeline block classes from theirdocproperty.Usage
Mark classes with
# auto_docstringcomment:Run the script to insert docstrings: