Skip to content

feat(lfx): Add type stubs for IDE autocomplete#10810

Open
ogabrielluiz wants to merge 5 commits into
mainfrom
feat/add-type-stubs
Open

feat(lfx): Add type stubs for IDE autocomplete#10810
ogabrielluiz wants to merge 5 commits into
mainfrom
feat/add-type-stubs

Conversation

@ogabrielluiz
Copy link
Copy Markdown
Contributor

@ogabrielluiz ogabrielluiz commented Dec 1, 2025

Summary

  • Add type stub generator for lfx components to enable IDE autocomplete (VSCode/PyCharm)
  • Add Component DX methods (__dir__, describe(), dynamic set() signature) for runtime introspection
  • Configure CI to generate stubs at build time before release
  • Stubs are gitignored and generated fresh each release

What this enables

Users installing lfx via pip will get:

  • Autocomplete for component.set(...) parameters
  • Type hints for output method return types (e.g., -> Message instead of -> Any)
  • py.typed marker for PEP 561 compliance

Test plan

  • Run stub generator tests: cd src/lfx && uv sync && uv run pytest tests/unit/stubs/
  • Run component DX tests: cd src/lfx && uv sync && uv run pytest tests/unit/custom/component/test_component_dx.py
  • Build wheel and verify stubs included: uv run python scripts/generate_lfx_stubs.py --inline && cd src/lfx && uv build --wheel
  • Verify IDE autocomplete works after installation

Summary by CodeRabbit

  • New Features

    • Enhanced IDE support with dynamic autocomplete for component inputs and method signatures.
    • Added component introspection capabilities to explore available inputs and outputs programmatically.
  • Build & Distribution

    • Type stub files now included in package distributions for improved type checking compatibility.
  • Tests

    • Added tests for type stub generation and IDE integration features.

✏️ Tip: You can customize this high-level summary in your review settings.

Add runtime methods to Component class for better developer experience:
- __dir__() to expose inputs and output methods for autocomplete
- _update_set_signature() to show set() parameters in IDE hints
- describe() for REPL exploration of component structure
Add stub generator that creates .pyi files for all lfx components:
- Generates set() method signatures with input parameters
- Extracts return types from method annotations
- Handles optional dependencies gracefully
- Script at scripts/generate_lfx_stubs.py with --inline flag for releases
Add PEP 561 py.typed marker and update hatch build config to include
.pyi files in the wheel distribution.
Add step to generate type stubs before wheel build, and verify
the wheel contains at least 100 stub files.
Stubs are generated at build time and should not be committed.
@github-actions github-actions Bot added the community Pull Request from an external contributor label Dec 1, 2025
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Dec 1, 2025

Walkthrough

This PR introduces type stub (.pyi) file generation for the lfx package to improve IDE autocomplete support. It adds a stub generator that discovers Component subclasses, generates type-annotated stubs for their inputs/outputs, integrates stub generation into the build pipeline, and includes stubs in wheel distributions. Component classes gain IDE-friendly features including dynamic signature updates and introspection methods.

Changes

Cohort / File(s) Summary
CI/CD & Build Configuration
.github/workflows/release-lfx.yml, src/lfx/pyproject.toml, .gitignore
Adds workflow steps to generate type stubs via scripts/generate_lfx_stubs.py --inline before building, verifies ≥100 stub files in wheel artifacts; updates wheel build config to include .pyi files and py.typed marker; extends .gitignore to exclude generated stub files.
Stub Generation Implementation
scripts/generate_lfx_stubs.py, src/lfx/src/lfx/stubs/__init__.py, src/lfx/src/lfx/stubs/generator.py
Introduces new stub generator system: script entry point supports --inline and custom output paths; generator discovers Component subclasses, infers input/output types from definitions and annotations, generates .pyi files with method signatures including async support, manages imports, and writes results to disk.
Component DX Enhancement
src/lfx/src/lfx/custom/custom_component/component.py
Adds _update_set_signature() to dynamically reconstruct set() method signature based on current inputs; implements describe() for human-readable input/output introspection; implements __dir__() for IDE autocomplete exposure of dynamic inputs/outputs.
Tests
src/lfx/tests/unit/custom/component/test_component_dx.py, src/lfx/tests/unit/stubs/test_stub_generator.py
Adds unit tests verifying __dir__ inclusion of input names and output methods; validates set() signature exposure, defaults, and keyword-only parameters; tests describe() output structure and content; validates ChatOutput and ChatInput stub generation with proper type annotations.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Key areas requiring attention:
    • src/lfx/src/lfx/stubs/generator.py: Type inference logic, handling of union/optional/generic types, component discovery mechanism, and import collection
    • src/lfx/src/lfx/custom/custom_component/component.py: Dynamic signature mutation via inspect.Signature, potential edge cases in _update_set_signature(), and correctness of __dir__() implementation
    • .github/workflows/release-lfx.yml: Verification logic for stub file count threshold (≥100 files), placement and integration of generation steps
    • Test coverage across both stub generation and DX features to ensure signatures and introspection behave as expected

Possibly related PRs

Suggested reviewers

  • jordanrfrazier

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Excessive Mock Usage Warning ❓ Inconclusive Test files mentioned in PR summary (test_component_dx.py, test_stub_generator.py) cannot be located in repository to assess mock usage patterns. Provide access to the actual test files or ensure they are committed to the standard repository locations for direct code inspection and mock usage assessment.
✅ Passed checks (6 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely summarizes the primary change: adding type stubs to enable IDE autocomplete for the lfx package, which is the main objective of this PR.
Docstring Coverage ✅ Passed Docstring coverage is 85.71% which is sufficient. The required threshold is 80.00%.
Test Coverage For New Implementations ✅ Passed PR includes comprehensive test coverage with 23 tests across 2 new test files covering stub generation, parameter handling, type annotations, and Component DX features.
Test Quality And Coverage ✅ Passed PR includes 2 test files with 22+ test methods using pytest, covering main DX features: dir dynamic attributes, set() signature inspection, describe() generation, and stub creation for real components.
Test File Naming And Structure ✅ Passed Test files follow pytest naming conventions (test_*.py) with descriptive test function names, proper directory structure mirroring source code, organized test classes, and comprehensive coverage of positive scenarios with appropriate assertions.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/add-type-stubs

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added enhancement New feature or request and removed enhancement New feature or request labels Dec 1, 2025
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (10)
scripts/generate_lfx_stubs.py (1)

28-73: CLI behavior is sound; consider failing fast when no stubs are generated in --inline mode

The path setup and mode handling (--inline, explicit dir, or default typings/) look good and integrate cleanly with the release workflow.

For better feedback, especially in CI, you might want to treat “zero generated stubs” as an error when running with --inline (and optionally when an explicit output dir is provided), e.g.:

-    stubs = generate_stubs(output_dir)
-
-    console.print(f"[green]Generated {len(stubs)} stub files[/green]")
+    stubs = generate_stubs(output_dir)
+
+    if inline_mode and not stubs:
+        console.print("[red]No stubs were generated in inline mode. Failing.[/red]")
+        raise SystemExit(1)
+
+    console.print(f"[green]Generated {len(stubs)} stub files[/green]")

That would surface misconfigurations (e.g., lfx.components import issues) at the stub-generation step instead of only at wheel verification.

src/lfx/pyproject.toml (1)

56-63: Wheel include patterns correctly capture sources, stubs, and typing marker

Including src/lfx/**/*.py, src/lfx/**/*.pyi, and src/lfx/py.typed under [tool.hatch.build] aligns with the stub-generation flow and guarantees stubs are present in built wheels. The empty [tool.hatch.build.targets.wheel.shared-data] section is currently unused; you can drop it later if no shared-data mappings are needed, but it doesn’t cause a problem as-is.

src/lfx/tests/unit/stubs/test_stub_generator.py (1)

1-62: Stub generator tests cover key DX guarantees

These tests hit the important behaviors of generate_stubs_for_component: presence of set() with Self return, inclusion of input names, output method stubs, basic type annotations, and default values, plus a sanity check for ChatInput. The pytest style and placement under tests/unit/stubs/ fit the project’s testing guidelines.

If you ever want to harden this further, a lightweight addition would be to ast.parse(stub) in one test to assert that generated stubs are syntactically valid, but that’s optional for this PR.

.github/workflows/release-lfx.yml (1)

167-190: Release workflow correctly enforces presence of type stubs in wheels

The new steps to:

  • run scripts/generate_lfx_stubs.py --inline before building, and
  • assert a minimum number of .pyi entries in the wheel

provide a solid safety net that stubs are both generated and packaged. The unzip | grep -c '\.pyi$' check is straightforward and will fail loudly if stubs disappear.

If you ever need to tune this for different component counts, consider making the 100 threshold a small env/config variable, but it’s fine as a hard-coded sanity check for now.

src/lfx/src/lfx/custom/custom_component/component.py (2)

183-469: Dynamic set() signature works but is effectively global across components

The _update_set_signature approach is clever and gives nice runtime signatures for set():

  • Parameters are keyword-only, deduped by input name.
  • Defaults come from inp.value when present.
  • Annotations are derived from input_types when available.

There are a couple of design caveats worth being aware of:

  1. Signature is shared across all Component subclasses

    self.set.__func__ refers to the underlying function object defined on Component, so assigning __signature__ there makes the last component instance to call _update_set_signature() determine the signature for all components. In practice your DX tests work because each test re-instantiates the component type it inspects, but in a long-lived process, inspect.signature(SomeOtherComponent().set) can reflect whatever component was initialized most recently.

    If you want per-class signatures, you’d likely need to move this logic to __init_subclass__ (or a metaclass) and attach a distinct set wrapper per subclass before instances are created.

  2. Signature isn’t updated when new inputs are added at runtime

    Methods like _get_or_create_input can append new Input objects to self.inputs and _inputs after initialization (e.g., via set(extra_param=...) creating a fallback input). The current implementation only runs in __init__, so those dynamically-added inputs won’t show up in inspect.signature(self.set) unless _update_set_signature() is called again (e.g., at the end of set() or map_inputs).

Neither point is a blocker for this PR—IDE autocomplete will still primarily lean on the generated stubs—but it’s worth keeping in mind if you intend runtime inspect.signature to be authoritative per component. If you’d like, I can sketch a __init_subclass__-based variant that produces a per-class set wrapper with its own __signature__.


470-1030: describe() and __dir__() implementations are clear and match the intended DX

  • describe() produces a concise, human-readable summary of inputs (names, types, required/optional, defaults) and outputs (names, types, bound methods), which aligns well with the tests and helps REPL users.
  • __dir__() starts from super().__dir__(), then unions in dynamic input names and output method names from _inputs / _outputs_map, giving IDEs and interactive shells the right surface for autocomplete.

One tiny nit: set()’s docstring still claims it returns None, but the method actually returns self. Updating that return description later would avoid confusion, though it’s not critical for this change set.

src/lfx/src/lfx/stubs/generator.py (4)

68-89: Consider escaping newlines and other control characters in string defaults

Right now, string defaults only escape backslashes and double quotes. A default containing \n or other control characters would be emitted literally, likely breaking the generated .pyi syntax:

default = "line1\nline2"
# becomes
param: str = "line1
line2"

Using repr(value) (with minor post‑processing if needed) or explicitly escaping common control characters (\n, \r, \t) would make stub output safer without changing behavior for simple strings.


163-224: generate_stubs_for_component is well structured; minor defaults/base‑class nits

The overall structure (class header, set(...) with keyword‑only inputs, then output methods with async detection) is clean and should give good IDE experiences.

Two small refinements to consider:

  1. Base class name imports
    When bases is empty you fall back to "Component", but the stub files never import Component. Type checkers usually treat unknown bases as Any, but importing Component (or whatever base is actually used at runtime) in the generated stub would make things more precise.

  2. Preserving None defaults
    Parameters whose runtime default is None are currently emitted as = ... instead of = None (since you only call _get_default_repr when value is not None). This loses information in the stubs for optional inputs. If feasible, you might treat None separately and emit = None for those, while keeping ... for “no default provided”.

Neither of these is blocking but they would tighten the fidelity between runtime behavior and stubs.


227-255: Import collection does the job; substring checks are slightly coarse

_collect_imports correctly ensures Any and Self are always imported and adds schema imports for Data, DataFrame, and Message based on the rendered type strings.

Using substring checks ("Data" in py_type, etc.) is a pragmatic shortcut, but note it could pick up unrelated identifiers containing those substrings. That’s usually harmless (extra imports in stubs are OK), but if you later introduce types like Metadata, you may get an unnecessary Data import.

If you want to tighten this, you could parse the type string for whole‑word matches or track the concrete type names before formatting, but it’s fine to keep as‑is if the current inputs/outputs are constrained.


308-406: Global stub generation is robust; consider logging and richer __init__.pyi stubs

The walk over lfx.components with broad exception handling makes the generator resilient to optional dependencies and lazy attributes, which is appropriate for a release‑time tool.

Two non‑blocking improvements to consider:

  1. Visibility into skipped modules/attributes
    Swallowing all Exception during module import and attribute access is safe but opaque. Lightweight logging (even at debug level) of the module name or attribute that failed would aid debugging if certain components unexpectedly lack stubs.

  2. Package __init__.pyi re‑exports
    Auto‑generated __init__.pyi files currently only contain a comment. That means from lfx.components import SomeComponent may not get autocomplete/type info even if SomeComponent is defined in a submodule stub. Generating basic re‑exports for classes within the same package (or mirroring the runtime package’s __all__) would improve the DX when importing from package roots.

Neither is required for correctness of the current PR, but both would strengthen the long‑term utility of the stub generator.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9b9e353 and 224f6ee.

📒 Files selected for processing (9)
  • .github/workflows/release-lfx.yml (2 hunks)
  • .gitignore (1 hunks)
  • scripts/generate_lfx_stubs.py (1 hunks)
  • src/lfx/pyproject.toml (1 hunks)
  • src/lfx/src/lfx/custom/custom_component/component.py (4 hunks)
  • src/lfx/src/lfx/stubs/__init__.py (1 hunks)
  • src/lfx/src/lfx/stubs/generator.py (1 hunks)
  • src/lfx/tests/unit/custom/component/test_component_dx.py (1 hunks)
  • src/lfx/tests/unit/stubs/test_stub_generator.py (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/{test_*.py,*.test.ts,*.test.tsx}

📄 CodeRabbit inference engine (Custom checks)

Check that test files follow the project's naming conventions (test_*.py for backend, *.test.ts for frontend)

Files:

  • src/lfx/tests/unit/custom/component/test_component_dx.py
  • src/lfx/tests/unit/stubs/test_stub_generator.py
**/test_*.py

📄 CodeRabbit inference engine (Custom checks)

**/test_*.py: Backend tests should follow pytest structure with proper test_*.py naming
For async functions, ensure proper async testing patterns are used with pytest for backend

Files:

  • src/lfx/tests/unit/custom/component/test_component_dx.py
  • src/lfx/tests/unit/stubs/test_stub_generator.py
🧠 Learnings (8)
📚 Learning: 2025-11-24T19:47:28.997Z
Learnt from: CR
Repo: langflow-ai/langflow PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-24T19:47:28.997Z
Learning: Applies to src/backend/tests/**/*.py : Inherit from the correct `ComponentTestBase` family class located in `src/backend/tests/base.py` based on API access needs: `ComponentTestBase` (no API), `ComponentTestBaseWithClient` (needs API), or `ComponentTestBaseWithoutClient` (pure logic). Provide three required fixtures: `component_class`, `default_kwargs`, and `file_names_mapping`

Applied to files:

  • src/lfx/tests/unit/custom/component/test_component_dx.py
📚 Learning: 2025-11-24T19:46:09.104Z
Learnt from: CR
Repo: langflow-ai/langflow PR: 0
File: .cursor/rules/backend_development.mdc:0-0
Timestamp: 2025-11-24T19:46:09.104Z
Learning: Applies to tests/unit/components/**/*.py : Create unit tests in `src/backend/tests/unit/components/` mirroring the component directory structure, using `ComponentTestBaseWithClient` or `ComponentTestBaseWithoutClient` base classes

Applied to files:

  • src/lfx/tests/unit/custom/component/test_component_dx.py
📚 Learning: 2025-11-24T19:47:28.997Z
Learnt from: CR
Repo: langflow-ai/langflow PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-24T19:47:28.997Z
Learning: When adding a new component test, inherit from the correct `ComponentTestBase` class and provide the three required fixtures (`component_class`, `default_kwargs`, `file_names_mapping`) to greatly reduce boilerplate and enforce version compatibility

Applied to files:

  • src/lfx/tests/unit/custom/component/test_component_dx.py
📚 Learning: 2025-08-05T22:51:27.961Z
Learnt from: edwinjosechittilappilly
Repo: langflow-ai/langflow PR: 0
File: :0-0
Timestamp: 2025-08-05T22:51:27.961Z
Learning: The TestComposioComponentAuth test in src/backend/tests/unit/components/bundles/composio/test_base_composio.py demonstrates proper integration testing patterns for external API components, including real API calls with mocking for OAuth completion, comprehensive resource cleanup, and proper environment variable handling with pytest.skip() fallbacks.

Applied to files:

  • src/lfx/tests/unit/custom/component/test_component_dx.py
📚 Learning: 2025-11-24T19:47:28.997Z
Learnt from: CR
Repo: langflow-ai/langflow PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-24T19:47:28.997Z
Learning: Applies to src/backend/tests/**/*.py : Test both sync and async code paths, mock external dependencies appropriately, test error handling and edge cases, validate input/output behavior, and test component initialization and configuration

Applied to files:

  • src/lfx/tests/unit/stubs/test_stub_generator.py
📚 Learning: 2025-11-24T19:47:28.997Z
Learnt from: CR
Repo: langflow-ai/langflow PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-24T19:47:28.997Z
Learning: Applies to src/backend/tests/**/*.py : Create comprehensive unit tests for all new backend components. If unit tests are incomplete, create a corresponding Markdown file documenting manual testing steps and expected outcomes

Applied to files:

  • src/lfx/tests/unit/stubs/test_stub_generator.py
📚 Learning: 2025-11-24T19:47:28.997Z
Learnt from: CR
Repo: langflow-ai/langflow PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-24T19:47:28.997Z
Learning: Applies to src/backend/tests/**/*.py : Use `pytest.mark.api_key_required` and `pytest.mark.no_blockbuster` markers for components that need external APIs; use `MockLanguageModel` from `tests.unit.mock_language_model` for testing without external API keys

Applied to files:

  • src/lfx/tests/unit/stubs/test_stub_generator.py
📚 Learning: 2025-11-24T19:47:28.997Z
Learnt from: CR
Repo: langflow-ai/langflow PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-11-24T19:47:28.997Z
Learning: Applies to src/backend/tests/**/*.py : Be aware of ContextVar propagation in async tests; test both direct event loop execution and `asyncio.to_thread` scenarios; ensure proper context isolation between test cases

Applied to files:

  • src/lfx/src/lfx/custom/custom_component/component.py
🧬 Code graph analysis (4)
src/lfx/src/lfx/stubs/__init__.py (1)
src/lfx/src/lfx/stubs/generator.py (2)
  • generate_stubs (308-406)
  • generate_stubs_for_component (163-224)
scripts/generate_lfx_stubs.py (1)
src/lfx/src/lfx/stubs/generator.py (1)
  • generate_stubs (308-406)
src/lfx/src/lfx/stubs/generator.py (1)
src/lfx/src/lfx/base/tools/flow_tool.py (1)
  • args (32-34)
src/lfx/tests/unit/stubs/test_stub_generator.py (2)
src/lfx/src/lfx/components/input_output/chat_output.py (1)
  • ChatOutput (22-184)
src/lfx/src/lfx/stubs/generator.py (1)
  • generate_stubs_for_component (163-224)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Update Starter Projects
  • GitHub Check: Run Ruff Check and Format
  • GitHub Check: Update Component Index
🔇 Additional comments (6)
.gitignore (1)

289-291: Ignore rule for generated stubs is consistent with packaging strategy

Ignoring src/lfx/src/lfx/**/*.pyi while including them in the wheel via pyproject.toml is a good balance between clean VCS and distributable typing assets. No issues here.

src/lfx/src/lfx/stubs/__init__.py (1)

1-5: Public stubs API is minimal and well-scoped

Re-exporting generate_stubs and generate_stubs_for_component from lfx.stubs with an explicit __all__ is a clean, discoverable surface for tooling and scripts. Looks good.

src/lfx/tests/unit/custom/component/test_component_dx.py (1)

1-181: DX tests give solid coverage for __dir__, set signature, and describe

This suite does a good job validating the new developer-experience features:

  • __dir__ exposes input names, output methods, and standard helpers on both a simple component and core ChatInput/ChatOutput.
  • inspect.signature(..set) is verified to include input names, preserve defaults, and use keyword-only parameters.
  • describe() is checked for basic structure and meaningful content (class/display names, inputs, outputs, and types).

The tests are pytest-idiomatic and live in an appropriate location under tests/unit/custom/component/. No changes needed.

src/lfx/src/lfx/stubs/generator.py (3)

14-66: Input type mapping and _get_python_type_for_input look solid overall

The mapping and override logic via IGNORE_INPUT_TYPES_FOR plus input_types introspection cover the common cases and allow Handle‑style inputs to express richer unions. Behavior is reasonable as long as input_types is consistently a list of strings, which seems to be the intended contract.

Please double‑check that all existing Input implementations set input_types to strings (not classes) so unions like ' | '.join(types) always yield valid annotations in stubs.


91-161: Output type resolution and _type_to_str are generally robust

The combination of preferring output.types and then falling back to method return annotations (with _type_to_str) is a good balance between explicit configuration and introspection. Handling of Union, Optional, list[T], and dict[K, V] via __origin__/__args__ should cover most annotations used in components.

Given from __future__ import annotations, the early isinstance(type_hint, str) path is also important and looks correct.

If you have components using PEP 604 unions (T | None) without stringized annotations, it may be worth adding a small test to confirm _type_to_str produces the expected string form for those as well.


68-89: > Likely an incorrect or invalid review comment.

Comment on lines +258 to +305
def generate_stubs_for_module(module_path: str) -> dict[str, str]:
"""Generate stubs for all components in a module.

Args:
module_path: The import path to the module (e.g., 'lfx.components.input_output').

Returns:
Dict mapping relative file paths to stub content.
"""
from lfx.custom.custom_component.component import Component

stubs: dict[str, str] = {}

try:
module = importlib.import_module(module_path)
except ImportError:
return stubs

# Find all Component subclasses in the module
component_classes: list[type[Component]] = []
for name in dir(module):
obj = getattr(module, name)
if isinstance(obj, type) and issubclass(obj, Component) and obj is not Component:
component_classes.append(obj)

if not component_classes:
return stubs

# Generate imports
imports = _collect_imports(component_classes)

# Generate stub content
lines = list(imports)
lines.append("")
lines.append("")

for component_class in sorted(component_classes, key=lambda c: c.__name__):
lines.append(generate_stubs_for_component(component_class))
lines.append("")
lines.append("")

# Determine output path
module_parts = module_path.split(".")
stub_path = "/".join(module_parts) + ".pyi"

stubs[stub_path] = "\n".join(lines)

return stubs
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

cd /tmp && find . -name "generator.py" -path "*/lfx/stubs/*" 2>/dev/null | head -5

Repository: langflow-ai/langflow

Length of output: 46


🏁 Script executed:

git ls-files | grep -E "generator\.py|stubs" | head -20

Repository: langflow-ai/langflow

Length of output: 396


🏁 Script executed:

find . -type f -name "generator.py" 2>/dev/null

Repository: langflow-ai/langflow

Length of output: 100


🏁 Script executed:

cat -n src/lfx/src/lfx/stubs/generator.py

Repository: langflow-ai/langflow

Length of output: 16289


Sort imports in generate_stubs_for_module for deterministic output

On line 290, imports are converted to a list without sorting:

lines = list(imports)

Since _collect_imports returns a set[str] (line 227), the import order is non-deterministic. However, the generate_stubs function (line 366) sorts imports explicitly:

lines = sorted(imports)

For reproducible builds and consistent stub file output, generate_stubs_for_module should do the same:

-    lines = list(imports)
+    lines = sorted(imports)
🤖 Prompt for AI Agents
In src/lfx/src/lfx/stubs/generator.py around lines 258 to 305, the code converts
the imports set to a list without sorting which produces non-deterministic
output; change the conversion to use a deterministic sorted order (e.g., replace
the unsorted list conversion with sorted(imports)) so the stub file imports are
written in a stable, reproducible order consistent with generate_stubs.

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

Labels

community Pull Request from an external contributor enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant