docs: contribute custom components refresh (#7971)

* rewrite-to-use-data-component

* code-font

* cleanup

* update-build-behavior

* comment-out-for-build

* icon-is-str

* repeat-deprecation-info

* code-review

* Apply suggestions from code review

Co-authored-by: KimberlyFields <46325568+KimberlyFields@users.noreply.github.com>

* add-anchor-link

---------

Co-authored-by: Edwin Jose <edwin.jose@datastax.com>
Co-authored-by: KimberlyFields <46325568+KimberlyFields@users.noreply.github.com>
This commit is contained in:
Mendon Kissling 2025-05-20 13:21:35 -04:00 committed by GitHub
commit e8f4dba133
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 166 additions and 14 deletions

View file

@ -23,7 +23,7 @@ For example, if the component being tested is `PromptComponent`, then the test c
## Imports, inheritance, and mandatory methods
To standardize comoponent tests, base test classes have been created and should be imported and inherited by all component test classes. These base classes are located in the file `src/backend/tests/unit/base.py`.
To standardize component tests, base test classes have been created and should be imported and inherited by all component test classes. These base classes are located in the file `src/backend/tests/unit/base.py`.
To import the base test classes:

View file

@ -4,20 +4,172 @@ slug: /contributing-components
---
New components are added as objects of the [CustomComponent](https://github.com/langflow-ai/langflow/blob/dev/src/backend/base/langflow/custom/custom_component/custom_component.py) class.
New components are added as objects of the [Component](https://github.com/langflow-ai/langflow/blob/main/src/backend/base/langflow/custom/custom_component/component.py) class.
Any dependencies are added to the [pyproject.toml](https://github.com/langflow-ai/langflow/blob/main/pyproject.toml#L148) file.
Dependencies are added to the [pyproject.toml](https://github.com/langflow-ai/langflow/blob/main/pyproject.toml#L148) file.
### Contribute an example component to Langflow
## Contribute an example component to Langflow
Anyone can contribute an example component. For example, if you created a new document loader called **MyCustomDocumentLoader**, you can follow these steps to contribute it to Langflow.
Anyone can contribute an example component. For example, to create a new **Data** component called **DataFrame processor**, follow these steps to contribute it to Langflow.
1. Write your loader as an object of the [CustomComponent](https://github.com/langflow-ai/langflow/blob/dev/src/backend/base/langflow/custom/custom_component/custom_component.py) class. You'll create a new class, `MyCustomDocumentLoader`, that will inherit from `CustomComponent` and override the base class's methods.
2. Define optional attributes like `display_name`, `description`, and `documentation` to provide information about your custom component.
3. Implement the `build_config` method to define the configuration options for your custom component.
4. Implement the `build` method to define the logic for taking input parameters specified in the `build_config` method and returning the desired output.
5. Add the code to the [/components/documentloaders](https://github.com/langflow-ai/langflow/tree/dev/src/backend/base/langflow/components) folder.
6. Add the dependency to [/documentloaders/__init__.py](https://github.com/langflow-ai/langflow/blob/dev/src/backend/base/langflow/components/documentloaders/__init__.py) as `from .MyCustomDocumentLoader import MyCustomDocumentLoader`.
7. Add any new dependencies to the [pyproject.toml](https://github.com/langflow-ai/langflow/blob/main/pyproject.toml#L148) file.
8. Submit documentation for your component. For this example, you'd submit documentation to the [loaders page](https://github.com/langflow-ai/langflow/blob/main/docs/docs/Components/components-loaders.md).
9. Submit your changes as a pull request. The Langflow team will have a look, suggest changes, and add your component to Langflow.
1. Create a Python file called `dataframe_processor.py`.
2. Write your processor as an object of the [Component](https://github.com/langflow-ai/langflow/blob/main/src/backend/base/langflow/custom/custom_component/component.py) class. You'll create a new class, `DataFrameProcessor`, that will inherit from `Component` and override the base class's methods.
```python
from typing import Any, Dict, Optional
import pandas as pd
from langflow.custom import Component
class DataFrameProcessor(Component):
"""A component that processes pandas DataFrames with various operations."""
```
3. Define class attributes to provide information about your custom component:
```python
from typing import Any, Dict, Optional
import pandas as pd
from langflow.custom import Component
class DataFrameProcessor(Component):
"""A component that processes pandas DataFrames with various operations."""
display_name: str = "DataFrame Processor"
description: str = "Process and transform pandas DataFrames with various operations like filtering, sorting, and aggregation."
documentation: str = "https://docs.langflow.org/components-dataframe-processor"
icon: str = "DataframeIcon"
priority: int = 100
name: str = "dataframe_processor"
```
* `display_name`: A user-friendly name shown in the UI.
* `description`: A brief description of what your component does.
* `documentation`: A link to detailed documentation.
* `icon`: An emoji or icon identifier for visual representation.
For more information, see [Contributing bundles](/contributing-bundles#add-the-bundle-to-the-frontend-folder).
* `priority`: An optional integer to control display order. Lower numbers appear first.
* `name`: An optional internal identifier that defaults to class name.
4. Define the component's interface by specifying its inputs, outputs, and the method that will process them. The method name must match the `method` field in your outputs list, as this is how Langflow knows which method to call to generate each output.
This example creates a minimal custom component skeleton.
For more information on creating your custom component, see [Create custom Python components](/components-custom-components).
```python
from typing import Any, Dict, Optional
import pandas as pd
from langflow.custom import Component
class DataFrameProcessor(Component):
"""A component that processes pandas DataFrames with various operations."""
display_name: str = "DataFrame Processor"
description: str = "Process and transform pandas DataFrames with various operations like filtering, sorting, and aggregation."
documentation: str = "https://docs.langflow.org/components-dataframe-processor"
icon: str = "DataframeIcon"
priority: int = 100
name: str = "dataframe_processor"
# input and output lists
inputs = []
outputs = []
# method
def some_output_method(self):
return ...
```
5. Save the `dataframe_processor.py` to the `src > backend > base > langflow > components` directory.
This example adds a **Data** component, so add it to the `/data` directory.
6. Add the component dependency to `src > backend > base > langflow > components > data > __init__.py` as `from .DataFrameProcessor import DataFrameProcessor`.
You can view the [/data/__init__.py](https://github.com/langflow-ai/langflow/blob/dev/src/backend/base/langflow/components/data/__init__.py) in the Langflow repository.
7. Add any new dependencies to the [pyproject.toml](https://github.com/langflow-ai/langflow/blob/main/pyproject.toml#L20) file.
8. Submit documentation for your component. For this example component, you would submit documentation to the [Data components page](https://github.com/langflow-ai/langflow/blob/main/docs/docs/Components/components-data.md).
9. Submit your changes as a pull request. The Langflow team will review, suggest changes, and add your component to Langflow.
## Best practices for modifying components
When creating or updating components, follow these best practices to maintain backward compatibility and ensure a smooth experience for users.
### Don't rename the class or `name` attribute
Changing the class name or the `name` attribute breaks the component for all existing users. This happens because the frontend tests the `type` attribute, which is set to the class' name or the `name` attribute. If these names change, the component effectively becomes a new component, and the old component disappears.
Instead, do the following:
* Change only the display name if the old name is unclear.
* Change only the display name if functionality changes but remains related.
* If a new internal name is necessary, mark the old component as `legacy=true` and create a new component.
For example:
```python
class MyCustomComponent(BaseComponent):
name = "my_custom_component_internal"
legacy = True
```
### Don't remove fields and outputs
Removing fields or outputs can cause edges to disconnect and change the behavior of components.
Instead, mark fields as `deprecated` and keep them in the same location. If removal is absolutely necessary, you must define and document a migration plan. Always clearly communicate any changes in the field's information to users.
### Maintain outdated components as legacy
When updating components, create them as completely separate entities while maintaining the old component as a legacy version. Always ensure backward compatibility and never remove methods and attributes from base classes, such as `LCModelComponent`.
### Favor asynchronous methods
Always favor asynchronous methods and functions in your components. When interacting with files, use `aiofile` and `anyio.Path` for better performance and compatibility.
### Include tests with your component
Include tests for your changes using `ComponentTestBase` classes. For more information, see [Contribute component tests](/contributing-component-tests).
### Documentation
When documenting changes in pull requests, clearly explain *what* changed, such as display name updates or new fields, *why* it changed, such as improvements or bug fixes, and the *impact* on existing users.
For example:
<details>
<summary>Example PR</summary>
```markdown
# Pull request with changes to Notify component
This pull request updates the Notify component.
## What changed
- Added new `timeout` field to control how long the component waits for a response.
- Renamed `message` field to `notification_text` for clarity.
- Added support for async operations.
- Deprecated the `retry_count` field in favor of `max_retries`.
## Why it changed
- `timeout` field addresses user requests for better control over wait times.
- `message` to `notification_text` change makes the field's purpose clearer.
- Async support improves performance in complex flows.
- `retry_count` to `max_retries` aligns with common retry pattern terminology.
## Impact on users
- New `timeout` field is optional (defaults to 30 seconds).
- Users will see a deprecation warning for `retry_count`.
- Migration: Replace `retry_count` with `max_retries` in existing flows.
- Both fields will work until version 2.0.
- No action needed for async support - it's backward compatible.
```
</details>
## Example pull request flow
1. Create or update a component.
Maintain the class name and `name` attribute if the purpose remains the same.
Otherwise, create a new component and move the old component to `legacy`.
2. Add tests.
Create tests using one of the `ComponentTestBase` classes.
For more information, see [Contribute component tests](/contributing-component-tests).
3. Flag outdated fields and outputs as `deprecated` and keep them in the same location to ensure backward compatibility.
4. Document your changes.
Include migration instructions if breaking changes occur.