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

remove optparse support #1739

Merged
merged 1 commit into from Nov 16, 2022
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
112 changes: 4 additions & 108 deletions src/flake8/options/manager.py
Expand Up @@ -7,7 +7,6 @@
import logging
from typing import Any
from typing import Callable
from typing import Mapping
from typing import Sequence

from flake8 import utils
Expand All @@ -20,55 +19,6 @@
_ARG = enum.Enum("_ARG", "NO")


_optparse_callable_map: dict[str, type[Any] | _ARG] = {
"int": int,
"long": int,
"string": str,
"float": float,
"complex": complex,
"choice": _ARG.NO,
# optparse allows this but does not document it
"str": str,
}


class _CallbackAction(argparse.Action):
"""Shim for optparse-style callback actions."""

def __init__(
self,
*args: Any,
callback: Callable[..., Any],
callback_args: Sequence[Any] = (),
callback_kwargs: dict[str, Any] | None = None,
**kwargs: Any,
) -> None:
self._callback = callback
self._callback_args = callback_args
self._callback_kwargs = callback_kwargs or {}
super().__init__(*args, **kwargs)

def __call__(
self,
parser: argparse.ArgumentParser,
namespace: argparse.Namespace,
values: Sequence[str] | str | None,
option_string: str | None = None,
) -> None:
if not values:
values = None
elif isinstance(values, list) and len(values) > 1:
values = tuple(values)
self._callback(
self,
option_string,
values,
parser,
*self._callback_args,
**self._callback_kwargs,
)


def _flake8_normalize(
value: str,
*args: str,
Expand All @@ -95,21 +45,16 @@ def __init__(
self,
short_option_name: str | _ARG = _ARG.NO,
long_option_name: str | _ARG = _ARG.NO,
# Options below here are taken from the optparse.Option class
# Options below are taken from argparse.ArgumentParser.add_argument
action: str | type[argparse.Action] | _ARG = _ARG.NO,
default: Any | _ARG = _ARG.NO,
type: str | Callable[..., Any] | _ARG = _ARG.NO,
type: Callable[..., Any] | _ARG = _ARG.NO,
dest: str | _ARG = _ARG.NO,
nargs: int | str | _ARG = _ARG.NO,
const: Any | _ARG = _ARG.NO,
choices: Sequence[Any] | _ARG = _ARG.NO,
help: str | _ARG = _ARG.NO,
metavar: str | _ARG = _ARG.NO,
# deprecated optparse-only options
callback: Callable[..., Any] | _ARG = _ARG.NO,
callback_args: Sequence[Any] | _ARG = _ARG.NO,
callback_kwargs: Mapping[str, Any] | _ARG = _ARG.NO,
# Options below are taken from argparse.ArgumentParser.add_argument
required: bool | _ARG = _ARG.NO,
# Options below here are specific to Flake8
parse_from_config: bool = False,
Expand Down Expand Up @@ -150,21 +95,9 @@ def __init__(

:param type:
A callable to normalize the type (as is the case in
:mod:`argparse`). Deprecated: you can also pass through type
strings such as ``'int'`` which are handled by :mod:`optparse`.
:mod:`argparse`).
:param action:
Any action allowed by :mod:`argparse`. Deprecated: this also
understands the ``action='callback'`` action from :mod:`optparse`.
:param callback:
Callback used if the action is ``"callback"``. Deprecated: please
use ``action=`` instead.
:param callback_args:
Additional positional arguments to the callback callable.
Deprecated: please use ``action=`` instead (probably with
``functools.partial``).
:param callback_kwargs:
Keyword arguments to the callback callable. Deprecated: please
use ``action=`` instead (probably with ``functools.partial``).
Any action allowed by :mod:`argparse`.

The following parameters are for Flake8's option handling alone.

Expand All @@ -184,37 +117,6 @@ def __init__(
):
short_option_name, long_option_name = _ARG.NO, short_option_name

# optparse -> argparse `%default` => `%(default)s`
if help is not _ARG.NO and "%default" in help:
LOG.warning(
"option %s: please update `help=` text to use %%(default)s "
"instead of %%default -- this will be an error in the future",
long_option_name,
)
help = help.replace("%default", "%(default)s")

# optparse -> argparse for `callback`
if action == "callback":
LOG.warning(
"option %s: please update from optparse `action='callback'` "
"to argparse action classes -- this will be an error in the "
"future",
long_option_name,
)
action = _CallbackAction
if type is _ARG.NO:
nargs = 0

# optparse -> argparse for `type`
if isinstance(type, str):
LOG.warning(
"option %s: please update from optparse string `type=` to "
"argparse callable `type=` -- this will be an error in the "
"future",
long_option_name,
)
type = _optparse_callable_map[type]

# flake8 special type normalization
if comma_separated_list or normalize_paths:
type = functools.partial(
Expand All @@ -237,9 +139,6 @@ def __init__(
self.nargs = nargs
self.const = const
self.choices = choices
self.callback = callback
self.callback_args = callback_args
self.callback_kwargs = callback_kwargs
self.help = help
self.metavar = metavar
self.required = required
Expand All @@ -251,9 +150,6 @@ def __init__(
"nargs": self.nargs,
"const": self.const,
"choices": self.choices,
"callback": self.callback,
"callback_args": self.callback_args,
"callback_kwargs": self.callback_kwargs,
"help": self.help,
"metavar": self.metavar,
"required": self.required,
Expand Down
91 changes: 0 additions & 91 deletions tests/unit/test_option_manager.py
Expand Up @@ -3,7 +3,6 @@

import argparse
import os
from unittest import mock

import pytest

Expand Down Expand Up @@ -170,96 +169,6 @@ def test_extend_default_ignore(optmanager):
assert optmanager.extended_default_ignore == ["T100", "T101", "T102"]


def test_optparse_normalize_callback_option_legacy(optmanager):
"""Test the optparse shim for `callback=`."""
callback_foo = mock.Mock()
optmanager.add_option(
"--foo",
action="callback",
callback=callback_foo,
callback_args=(1, 2),
callback_kwargs={"a": "b"},
)
callback_bar = mock.Mock()
optmanager.add_option(
"--bar",
action="callback",
type="string",
callback=callback_bar,
)
callback_baz = mock.Mock()
optmanager.add_option(
"--baz",
action="callback",
type="string",
nargs=2,
callback=callback_baz,
)

optmanager.parse_args(["--foo", "--bar", "bararg", "--baz", "1", "2"])

callback_foo.assert_called_once_with(
mock.ANY, # the option / action instance
"--foo",
None,
mock.ANY, # the OptionParser / ArgumentParser
1,
2,
a="b",
)
callback_bar.assert_called_once_with(
mock.ANY, # the option / action instance
"--bar",
"bararg",
mock.ANY, # the OptionParser / ArgumentParser
)
callback_baz.assert_called_once_with(
mock.ANY, # the option / action instance
"--baz",
("1", "2"),
mock.ANY, # the OptionParser / ArgumentParser
)


@pytest.mark.parametrize(
("type_s", "input_val", "expected"),
(
("int", "5", 5),
("long", "6", 6),
("string", "foo", "foo"),
("float", "1.5", 1.5),
("complex", "1+5j", 1 + 5j),
# optparse allows this but does not document it
("str", "foo", "foo"),
),
)
def test_optparse_normalize_types(optmanager, type_s, input_val, expected):
"""Test the optparse shim for type="typename"."""
optmanager.add_option("--foo", type=type_s)
opts = optmanager.parse_args(["--foo", input_val])
assert opts.foo == expected


def test_optparse_normalize_choice_type(optmanager):
"""Test the optparse shim for type="choice"."""
optmanager.add_option("--foo", type="choice", choices=("1", "2", "3"))
opts = optmanager.parse_args(["--foo", "1"])
assert opts.foo == "1"
# fails to parse
with pytest.raises(SystemExit):
optmanager.parse_args(["--foo", "4"])


def test_optparse_normalize_help(optmanager, capsys):
"""Test the optparse shim for %default in help text."""
optmanager.add_option("--foo", default="bar", help="default: %default")
with pytest.raises(SystemExit):
optmanager.parse_args(["--help"])
out, err = capsys.readouterr()
output = out + err
assert "default: bar" in output


@pytest.mark.parametrize(
("s", "is_auto", "n_jobs"),
(
Expand Down