Files
superset2/superset/extensions/contributions.py

95 lines
3.1 KiB
Python

# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
"""
Unified Contribution Processing System
This module provides a centralized system for processing pending contributions
from decorators across all contribution types (extension APIs, MCP tools, tasks, etc.)
after extension loading when publisher/name context is available.
"""
import logging
from typing import Protocol
from superset_core.extensions.types import Manifest
logger = logging.getLogger(__name__)
class ContributionProcessor(Protocol):
"""Protocol for contribution processor functions."""
def __call__(self, manifest: Manifest) -> None:
"""Process pending contributions for an extension."""
...
class ContributionProcessorRegistry:
"""Registry for contribution processors from different decorator systems."""
def __init__(self) -> None:
self._processors: list[ContributionProcessor] = []
def register_processor(self, processor: ContributionProcessor) -> None:
"""Register a contribution processor function."""
self._processors.append(processor)
logger.debug(
"Registered contribution processor: %s",
getattr(processor, "__name__", repr(processor)),
)
def process_all_contributions(self, manifest: Manifest) -> None:
"""Process all pending contributions for an extension."""
logger.debug(
"Processing %d contribution processors for %s",
len(self._processors),
manifest.id,
)
for processor in self._processors:
try:
processor(manifest)
except Exception as e:
logger.error(
"Failed to process contributions with %s for %s: %s",
getattr(processor, "__name__", repr(processor)),
manifest.id,
e,
)
# Global registry instance
_contribution_registry = ContributionProcessorRegistry()
def register_contribution_processor(processor: ContributionProcessor) -> None:
"""Register a contribution processor function."""
_contribution_registry.register_processor(processor)
def process_extension_contributions(manifest: Manifest) -> None:
"""Process all pending contributions for an extension."""
_contribution_registry.process_all_contributions(manifest)
__all__ = [
"ContributionProcessor",
"register_contribution_processor",
"process_extension_contributions",
]