Skip to content
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

Refactor builtin plugins #5261

Merged
merged 11 commits into from
Dec 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions app/packages/plugins/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ class PluginDefinition {
serverPath: string;
hasPy: boolean;
hasJS: boolean;
builtin: boolean;

constructor(json: any) {
const serverPathPrefix = fou.getFetchPathPrefix();
Expand All @@ -102,6 +103,7 @@ class PluginDefinition {
this.hasPy = json.has_py;
this.hasJS = json.has_js;
this.serverPath = `${serverPathPrefix}${json.server_path}`;
this.builtin = json.builtin;
}
}

Expand Down
2 changes: 1 addition & 1 deletion docs/source/plugins/developing_plugins.rst
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ configurable backend. Operators can even be composed of other operators or be
used to add functionality to custom panels.

FiftyOne comes with a number of builtin
:mod:`Python <fiftyone.operators.builtin>` and
:mod:`Python <fiftyone.operators.builtin.operations>` and
`JavaScript <https://github.com/voxel51/fiftyone/blob/develop/app/packages/operators/src/built-in-operators.ts>`_
operators for common tasks that are intended for either user-facing or internal
plugin use.
Expand Down
30 changes: 21 additions & 9 deletions fiftyone/operators/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@
from fiftyone.operators.panel import Panel
import fiftyone.plugins.context as fopc

from .builtin import BUILTIN_OPERATORS, BUILTIN_PANELS


def get_operator(operator_uri, enabled=True):
"""Gets the operator with the given URI.
Expand All @@ -34,20 +32,25 @@ def get_operator(operator_uri, enabled=True):
return operator


def list_operators(enabled=True, type=None):
def list_operators(enabled=True, type=None, builtins_only=False):
"""Returns all available operators.

Args:
enabled (True): whether to include only enabled operators (True) or
only disabled operators (False) or all operators ("all")
type (None): whether to include only ``"panel"`` or ``"operator"`` type
operators
builtins_only (False): whether to include only builtin operators

Returns:
a list of :class:`fiftyone.operators.Operator` instances
"""
registry = OperatorRegistry(enabled=enabled)
return registry.list_operators(include_builtin=enabled != False, type=type)
return registry.list_operators(
include_builtin=enabled != False,
ritch marked this conversation as resolved.
Show resolved Hide resolved
type=type,
builtins_only=builtins_only,
)


def operator_exists(operator_uri, enabled=True):
Expand All @@ -65,6 +68,9 @@ def operator_exists(operator_uri, enabled=True):
return registry.operator_exists(operator_uri)


_EXTRA_OPERATORS = []


class OperatorRegistry(object):
"""Operator registry.

Expand All @@ -75,24 +81,30 @@ class OperatorRegistry(object):
def __init__(self, enabled=True):
self.plugin_contexts = fopc.build_plugin_contexts(enabled=enabled)

def list_operators(self, include_builtin=True, type=None):
def list_operators(
self, include_builtin=True, type=None, builtins_only=False
):
"""Lists the available FiftyOne operators.

Args:
include_builtin (True): whether to include builtin operators
type (None): whether to include only ``"panel"`` or ``"operator"``
type operators
builtins_only (False): whether to include only builtin operators

Returns:
a list of :class:`fiftyone.operators.Operator` instances
"""
operators = []
operators.extend(_EXTRA_OPERATORS)
for pctx in self.plugin_contexts:
operators.extend(pctx.instances)

if include_builtin:
operators.extend(BUILTIN_OPERATORS)
operators.extend(BUILTIN_PANELS)
if not include_builtin:
operators = [op for op in operators if op._builtin is False]
ritch marked this conversation as resolved.
Show resolved Hide resolved

if builtins_only:
operators = [op for op in operators if op._builtin is True]

if type == "panel":
operators = [op for op in operators if isinstance(op, Panel)]
Expand Down Expand Up @@ -126,7 +138,7 @@ def operator_exists(self, operator_uri):
Returns:
True/False
"""
for operator in self.list_operators():
for operator in self.list_operators(include_builtin=True):
if operator_uri == operator.uri:
return True

Expand Down
4 changes: 2 additions & 2 deletions fiftyone/operators/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@


def get_operators(registry: PermissionedOperatorRegistry):
operators = registry.list_operators(True, "operator")
panels = registry.list_operators(True, "panel")
operators = registry.list_operators(include_builtin=True, type="operator")
panels = registry.list_operators(include_builtin=True, type="panel")
return operators + panels


Expand Down
12 changes: 12 additions & 0 deletions fiftyone/plugins/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
"""
FiftyOne plugins constants.

| Copyright 2017-2024, Voxel51, Inc.
| `voxel51.com <https://voxel51.com/>`_
|
"""
import os

BUILTIN_PLUGINS_DIR = os.path.join(
os.path.dirname(__file__), "..", "..", "plugins"
)
6 changes: 3 additions & 3 deletions fiftyone/plugins/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def build_plugin_contexts(enabled=True):
a list of :class:`PluginContext` instances
"""
plugin_contexts = []
for pd in fop.list_plugins(enabled=enabled):
for pd in fop.list_plugins(enabled=enabled, include_builtin=True):
pctx = PluginContext(pd)
pctx.register_all()
plugin_contexts.append(pctx)
Expand Down Expand Up @@ -96,10 +96,10 @@ def register(self, cls):
Any errors are logged rather than being raised.

Args:
cls: an :class:`fiftyone.operators.operator.Operator` class
cls: an :class:`fiftyone.operators.operator.Operator` or :class:`fiftyone.operators.panel.Panel` class
"""
try:
instance = cls()
instance = cls(_builtin=self.plugin_definition.builtin)
if self.can_register(instance):
instance.plugin_name = self.name
if self.secrets:
Expand Down
22 changes: 16 additions & 6 deletions fiftyone/plugins/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
import fiftyone.core.utils as fou
from fiftyone.plugins.definitions import PluginDefinition
from fiftyone.utils.github import GitHubRepository

import fiftyone.plugins.constants as constants

PLUGIN_METADATA_FILENAMES = ("fiftyone.yml", "fiftyone.yaml")

Expand All @@ -48,12 +48,13 @@ def __repr__(self):
return f"Plugin(name={self.name}, path={self.path})"


def list_plugins(enabled=True):
"""Returns the definitions of downloaded plugins.
def list_plugins(enabled=True, include_builtin=False):
"""Returns the definitions of available plugins.

Args:
enabled (True): whether to include only enabled plugins (True) or only
disabled plugins (False) or all plugins ("all")
include_builtin (False): whether to include built-in plugins

Returns:
a list of :class:`PluginDefinition` instances
Expand All @@ -62,7 +63,7 @@ def list_plugins(enabled=True):
enabled = None

plugins = []
for p in _list_plugins(enabled=enabled):
for p in _list_plugins(enabled=enabled, include_builtin=include_builtin):
try:
plugins.append(_load_plugin_definition(p))
except:
Expand Down Expand Up @@ -488,9 +489,18 @@ def _parse_plugin_metadata(metadata_path):
return PluginPackage(plugin_name, plugin_path)


def _list_plugins(enabled=None):
def _list_plugins(enabled=None, include_builtin=False):
plugins = []
for metadata_path in _iter_plugin_metadata_files():
external_plugin_paths = list(_iter_plugin_metadata_files())
builtin_plugin_paths = list(
_iter_plugin_metadata_files(constants.BUILTIN_PLUGINS_DIR)
)
ritch marked this conversation as resolved.
Show resolved Hide resolved
all_plugin_paths = (
(external_plugin_paths + builtin_plugin_paths)
if include_builtin
else external_plugin_paths
)
for metadata_path in all_plugin_paths:
try:
plugin = _parse_plugin_metadata(metadata_path)
plugins.append(plugin)
Expand Down
7 changes: 7 additions & 0 deletions fiftyone/plugins/definitions.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import eta.core.serial as etas

import fiftyone as fo
import fiftyone.plugins.constants as constants


class PluginDefinition(object):
Expand Down Expand Up @@ -40,6 +41,11 @@ def directory(self):
"""The directory containing the plugin."""
return self._directory

@property
def builtin(self):
"""Whether the plugin is a builtin plugin."""
self.directory.startswith(constants.BUILTIN_PLUGINS_DIR)

@property
def author(self):
"""The author of the plugin."""
Expand Down Expand Up @@ -205,6 +211,7 @@ def to_dict(self):
"has_js": self.has_js,
"server_path": self.server_path,
"secrets": self.secrets,
"builtin": self.builtin,
}

@classmethod
Expand Down
7 changes: 7 additions & 0 deletions plugins/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
"""
FiftyOne builtin plugins.

| Copyright 2017-2024, Voxel51, Inc.
| `voxel51.com <https://voxel51.com/>`_
|
"""
72 changes: 33 additions & 39 deletions fiftyone/operators/builtin.py → plugins/operators/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,6 @@
import fiftyone.operators.types as types
from fiftyone.core.odm.workspace import default_workspace_factory

# pylint: disable=no-name-in-module
from fiftyone.operators.builtins.panels.model_evaluation import EvaluationPanel


class EditFieldInfo(foo.Operator):
@property
Expand Down Expand Up @@ -2373,39 +2370,36 @@ def _parse_spaces(ctx, spaces):
return fo.Space.from_dict(spaces)


BUILTIN_OPERATORS = [
EditFieldInfo(_builtin=True),
CloneSelectedSamples(_builtin=True),
CloneSampleField(_builtin=True),
CloneFrameField(_builtin=True),
RenameSampleField(_builtin=True),
RenameFrameField(_builtin=True),
ClearSampleField(_builtin=True),
ClearFrameField(_builtin=True),
DeleteSelectedSamples(_builtin=True),
DeleteSelectedLabels(_builtin=True),
DeleteSampleField(_builtin=True),
DeleteFrameField(_builtin=True),
CreateIndex(_builtin=True),
DropIndex(_builtin=True),
CreateSummaryField(_builtin=True),
UpdateSummaryField(_builtin=True),
DeleteSummaryField(_builtin=True),
AddGroupSlice(_builtin=True),
RenameGroupSlice(_builtin=True),
DeleteGroupSlice(_builtin=True),
ListSavedViews(_builtin=True),
LoadSavedView(_builtin=True),
SaveView(_builtin=True),
EditSavedViewInfo(_builtin=True),
DeleteSavedView(_builtin=True),
ListWorkspaces(_builtin=True),
LoadWorkspace(_builtin=True),
SaveWorkspace(_builtin=True),
EditWorkspaceInfo(_builtin=True),
DeleteWorkspace(_builtin=True),
SyncLastModifiedAt(_builtin=True),
ListFiles(_builtin=True),
]

BUILTIN_PANELS = [EvaluationPanel(_builtin=True)]
def register(p):
p.register(EditFieldInfo)
p.register(CloneSelectedSamples)
p.register(CloneSampleField)
p.register(CloneFrameField)
p.register(RenameSampleField)
p.register(RenameFrameField)
p.register(ClearSampleField)
p.register(ClearFrameField)
p.register(DeleteSelectedSamples)
p.register(DeleteSelectedLabels)
p.register(DeleteSampleField)
p.register(DeleteFrameField)
p.register(CreateIndex)
p.register(DropIndex)
p.register(CreateSummaryField)
p.register(UpdateSummaryField)
p.register(DeleteSummaryField)
p.register(AddGroupSlice)
p.register(RenameGroupSlice)
p.register(DeleteGroupSlice)
p.register(ListSavedViews)
p.register(LoadSavedView)
p.register(SaveView)
p.register(EditSavedViewInfo)
p.register(DeleteSavedView)
p.register(ListWorkspaces)
p.register(LoadWorkspace)
p.register(SaveWorkspace)
p.register(EditWorkspaceInfo)
p.register(DeleteWorkspace)
p.register(SyncLastModifiedAt)
p.register(ListFiles)
39 changes: 39 additions & 0 deletions plugins/operators/fiftyone.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: "@voxel51/operators"
description: Core FiftyOne operators
version: 1.0.0
fiftyone:
version: "*"
url: https://github.com/voxel51/fiftyone/fiftyone/builtins/operators
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Correct the plugin URL

The URL in the plugin definition appears to have a duplicate 'fiftyone' in the path. Update the URL to point to the correct location.

Apply this diff to fix the URL:

- url: https://github.com/voxel51/fiftyone/fiftyone/builtins/operators
+ url: https://github.com/voxel51/fiftyone/tree/main/fiftyone/builtins/operators
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
url: https://github.com/voxel51/fiftyone/fiftyone/builtins/operators
url: https://github.com/voxel51/fiftyone/tree/main/fiftyone/builtins/operators

operators:
- edit_field_info
- clone_selected_samples
- clone_sample_field
- clone_frame_field
- rename_sample_field
- rename_frame_field
- clear_sample_field
- clear_frame_field
- delete_selected_samples
- delete_selected_labels
- delete_sample_field
- delete_frame_field
- create_index
- drop_index
- create_summary_field
- update_summary_field
- delete_summary_field
- add_group_slice
- rename_group_slice
- delete_group_slice
- list_saved_views
- load_saved_view
- save_view
- edit_saved_view_info
- delete_saved_view
- list_workspaces
- load_workspace
- save_workspace
- edit_workspace_info
- delete_workspace
- sync_last_modified_at
Copy link
Contributor

Choose a reason for hiding this comment

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

We already have the list pretty much here so it wouldn’t be much of a change to reference the list instead of the operator itself but would prevent people from saving their own as builtin

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is only part of this list this needs to support...in teams we have the other built-ins.

- list_files
13 changes: 13 additions & 0 deletions plugins/panels/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
"""
Builtin panels.

| Copyright 2017-2024, Voxel51, Inc.
| `voxel51.com <https://voxel51.com/>`_
|
"""

from .model_evaluation import EvaluationPanel


def register(p):
p.register(EvaluationPanel)
8 changes: 8 additions & 0 deletions plugins/panels/fiftyone.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
name: "@voxel51/panel"
description: Core FiftyOne panels
version: 1.0.0
fiftyone:
version: "*"
url: https://github.com/voxel51/fiftyone/plugins/panels
panels:
- model_evaluation_panel_builtin
Loading
Loading