Skip to content

Conversation

@ephraimbuddy
Copy link
Contributor

Closes: #10109


^ Add meaningful description above

Read the Pull Request Guidelines for more information.
In case of fundamental code change, Airflow Improvement Proposal (AIP) is needed.
In case of a new dependency, check compliance with the ASF 3rd Party License Policy.
In case of backwards incompatible changes please leave a note in UPDATING.md.

Comment on lines 21 to 28
Copy link
Member

@turbaszek turbaszek Aug 2, 2020

Choose a reason for hiding this comment

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

How about

def check_value(action, value):
    cmd_map = {
        "worker": "celery worker",  # old: new
        ...
    }
    try:
        msg = "{} command, has been removed, please use `airflow {}`.format(value, cmd_map[value])
        raise ArgumentError(action, msg)
    except KeyError:
        pass 

We can consider making this map a global constant as it may be useful in the future. WDYT?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I like this!

Copy link
Member

Choose a reason for hiding this comment

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

Yeah!

Copy link
Contributor Author

@ephraimbuddy ephraimbuddy Aug 2, 2020

Choose a reason for hiding this comment

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

How do you suggest to write a test for this? @turbaszek

Copy link
Member

Choose a reason for hiding this comment

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

I would mock COMMAND_MAP with {"old_cmd": "new_cmd"} and then:

action = MagicMock()
with self.assertrises(ArgumentError):
    check_value(action, "old_cmd")

plus some regex check that the error msg is valid one.

Copy link
Member

Choose a reason for hiding this comment

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

class TestCliDeprecatedCommandsValue(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        cls.parser = cli_parser.get_parser()

    def test_should_display_value(self):
        with self.assertRaises(SystemExit) as cm_exception, \
                contextlib.redirect_stderr(io.StringIO()) as temp_stderr:
            config_command.get_value(self.parser.parse_args(['worker']))

        self.assertEqual(2, cm_exception.exception.code)
        self.assertIn(
            "`airflow worker` command, has been removed, "
            "please use `airflow celery worker`, see help above.",
            temp_stderr.getvalue().strip()
        )

I propose to test this by testing the CLI parser. We overwrite private methods, so I wouldn't trust unit tests only.

Copy link
Member

@kaxil kaxil left a comment

Choose a reason for hiding this comment

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

Thanks @ephraimbuddy for this PR.

How much effort might be required to make it backwards-compatible with deprecation warning, I definitely not saying we should do it --- but would like to hear your opinions @ephraimbuddy @turbaszek @potiuk .

@kaxil
Copy link
Member

kaxil commented Aug 2, 2020

CI is failing:


self = DefaultHelpParser(prog='airflow celery', usage=None, description='Start celery components. Works only when using Celer...xecutor/celery.html', formatter_class=<class 'argparse.RawTextHelpFormatter'>, conflict_handler='error', add_help=True)
action = _SubParsersAction(option_strings=[], dest='subcommand', nargs='A...', const=None, default=None, type=None, choices={'f...class=<class 'argparse.RawTextHelpFormatter'>, conflict_handler='error', add_help=True)}, help=None, metavar='COMMAND')
value = 'worker'

    def _check_value(self, action, value):
        """Override _check_value and check conditionally added command"""
        executor = conf.get('core', 'EXECUTOR')
        if value == 'celery' and executor != ExecutorLoader.CELERY_EXECUTOR:
            message = f'celery subcommand works only with CeleryExecutor, your current executor: {executor}'
            raise ArgumentError(action, message)
>       check_value(action, value)

airflow/cli/cli_parser.py:69: 

@potiuk
Copy link
Member

potiuk commented Aug 2, 2020

I

How much effort might be required to make it backwards-compatible with deprecation warning, I definitely not saying we should do it --- but would like to hear your opinions @ephraimbuddy @turbaszek @potiuk .

I think it's totally not worth it. There are very few issues where people use the CLI to automate stuff for Airflow and for most of them migration to 2.0 will be quite some change anyway (at least running upgrade check). I think we are talking about a handful of users here - far less than people who are writing DAGs and they use CLI either very rarely (db init, db reset etc) so they don't remember the commands by heart, or very frequently use one command ("backfill") but then it will be very easy to adapt to that single command.

@kaxil
Copy link
Member

kaxil commented Aug 2, 2020

I

How much effort might be required to make it backwards-compatible with deprecation warning, I definitely not saying we should do it --- but would like to hear your opinions @ephraimbuddy @turbaszek @potiuk .

I think it's totally not worth it. There are very few issues where people use the CLI to automate stuff for Airflow and for most of them migration to 2.0 will be quite some change (at least running upgrade check). I think we are talking about a handful of users here - far less than people who are writing DAGs and they use CLI either very rarely (db init, db reset etc) so they don't remember the commands by heart, or very frequently use one command ("backfill") but then it will be very easy to adapt to that single command.

Agree 👍

@ephraimbuddy
Copy link
Contributor Author

CI is failing:


self = DefaultHelpParser(prog='airflow celery', usage=None, description='Start celery components. Works only when using Celer...xecutor/celery.html', formatter_class=<class 'argparse.RawTextHelpFormatter'>, conflict_handler='error', add_help=True)
action = _SubParsersAction(option_strings=[], dest='subcommand', nargs='A...', const=None, default=None, type=None, choices={'f...class=<class 'argparse.RawTextHelpFormatter'>, conflict_handler='error', add_help=True)}, help=None, metavar='COMMAND')
value = 'worker'

    def _check_value(self, action, value):
        """Override _check_value and check conditionally added command"""
        executor = conf.get('core', 'EXECUTOR')
        if value == 'celery' and executor != ExecutorLoader.CELERY_EXECUTOR:
            message = f'celery subcommand works only with CeleryExecutor, your current executor: {executor}'
            raise ArgumentError(action, message)
>       check_value(action, value)

airflow/cli/cli_parser.py:69: 

It is like the worker command is still in use in the CI instead of celery worker?

@turbaszek
Copy link
Member

It is like the worker command is still in use in the CI instead of celery worker?

Probably the problem is related to subparsers. The command celery worker is first parsed as celery then as worker with respectible parser.

@ephraimbuddy
Copy link
Contributor Author

It is like the worker command is still in use in the CI instead of celery worker?

Probably the problem is related to subparsers. The command celery worker is first parsed as celery then as worker with respectible parser.

Seen, It also affects backfill, I understand now.

Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
msg = "{} command, has been removed, please use `airflow {}`".format(value, COMMAND_MAP[value])
new_command = COMMAND_MAP[value]
msg = f"`airflow {value}` command, has been removed, please use `airflow {new_command}`"

Copy link
Member

Choose a reason for hiding this comment

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

Can you give a more descriptive name e.g. check_legacy_commands?

Comment on lines 53 to 54
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
if COMMAND_MAP.get(value) is not None:
new_command = COMMAND_MAP[value]
new_command = COMMAND_MAP.get(value)
if new_command is not None:

Copy link
Member

Choose a reason for hiding this comment

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

If we are using existing command there's no reason to mock I think

Copy link
Member

Choose a reason for hiding this comment

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

Agree!

@potiuk potiuk merged commit 201823b into apache:master Aug 3, 2020
@ephraimbuddy ephraimbuddy deleted the legacy-commands branch August 3, 2020 18:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add Legacy command displaying new CLI counterparts.

5 participants