Skip to content
3 changes: 3 additions & 0 deletions openedx_filters/management/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"""
Package where filters related to management command execution are implemented.
"""
53 changes: 53 additions & 0 deletions openedx_filters/management/filters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
"""
Package where filters related to management command execution are implemented.
"""

from collections.abc import Callable
from typing import Any

from openedx_filters.tooling import OpenEdxPublicFilter


class ManagementCommandExecutionRequested(OpenEdxPublicFilter):
"""
Filter used to modify the execution of Django management commands.

Purpose:
This filter is triggered in ``manage.py`` before a management command is
executed, allowing pipeline steps to wrap or replace the command runner.

Filter Type:
org.openedx.platform.management.command.execute.requested.v1

Trigger:
- Repository: edx/edx-platform

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.

Suggested change
- Repository: edx/edx-platform
- Repository: openedx/openedx-platform

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.

+1

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Updated

- Path: manage.py
- Function or Method: __main__
"""

filter_type = "org.openedx.platform.management.command.execute.requested.v1"

@classmethod
def run_filter(
cls,
command_name: str,
service_variant: str,
command_runner: Callable[..., Any],
) -> dict[str, Any]:

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.

This signature is non-conventional. The input args (excluding cls) should map to an output tuple with identical parts:

Suggested change
@classmethod
def run_filter(
cls,
command_name: str,
service_variant: str,
command_runner: Callable[..., Any],
) -> dict[str, Any]:
@classmethod
def run_filter(
cls,
command_name: str,
service_variant: str,
command_runner: Callable[..., Any],
) -> tuple[str, str, Callable[..., Any]]:

But also, see my comment on your platform PR: edx/edx-platform#200 (comment)

The revised signature would look like this instead:

Suggested change
@classmethod
def run_filter(
cls,
command_name: str,
service_variant: str,
command_runner: Callable[..., Any],
) -> dict[str, Any]:
@classmethod
def run_filter(
cls,
command_contextmanager: AbstractContextManager[None]
command_name: str,
service_variant: str,
) -> tuple[AbstractContextManager[None], str, str]:

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I updated this filter to the context-manager pattern so inputs and outputs map positionally as a tuple. The signature is now command_contextmanager, command_name, service_variant -> (command_contextmanager, command_name, service_variant), and the test was updated to assert tuple unpacking accordingly. This also aligns with the platform-side change where manage.py remains the only execution callsite and the filter only wraps execution via a context manager.

"""
Process management command execution arguments through the pipeline.

Arguments:
command_name (str): name of the management command being executed.
service_variant (str): service variant, such as lms or cms.
command_runner (Callable): callable that executes the command.

Returns:
dict[str, Any]: accumulated pipeline output, including possibly
modified command metadata and command runner.
"""
return super().run_pipeline(
command_name=command_name,
service_variant=service_variant,
command_runner=command_runner,
)
35 changes: 35 additions & 0 deletions openedx_filters/management/tests/test_filters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
"""
Tests for management subdomain filters.
"""
from unittest.mock import Mock

from django.test import TestCase

from openedx_filters.management.filters import ManagementCommandExecutionRequested


class TestManagementFilters(TestCase):
"""
Test class to verify standard behavior of management filters.
"""

def test_management_command_execution_requested(self):
"""
Test ManagementCommandExecutionRequested filter behavior.

Expected behavior:
- The filter should return management command metadata and runner.
"""
command_name = "migrate"
service_variant = "lms"
command_runner = Mock()

result = ManagementCommandExecutionRequested.run_filter(
command_name=command_name,
service_variant=service_variant,
command_runner=command_runner,
)

self.assertEqual(command_name, result.get("command_name"))
self.assertEqual(service_variant, result.get("service_variant"))
self.assertEqual(command_runner, result.get("command_runner"))