diff --git a/.travis.yml b/.travis.yml index 074fe3b..a6a88fe 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,9 +4,9 @@ arch: sudo: false language: python python: -- '3.7' - '3.8' - '3.9' - '3.10' +- '3.11' install: pip install tox-travis script: tox diff --git a/azure-pipeline.yml b/azure-pipeline.yml index 48505d8..fae48b0 100644 --- a/azure-pipeline.yml +++ b/azure-pipeline.yml @@ -20,9 +20,6 @@ jobs: name: 'pool-ubuntu-2004' strategy: matrix: - Python37: - python.version: '3.7' - tox_env: 'py37' Python38: python.version: '3.8' tox_env: 'py38' @@ -32,6 +29,9 @@ jobs: Python310: python.version: '3.10' tox_env: 'py310' + Python311: + python.version: '3.11' + tox_env: 'py311' steps: - task: UsePythonVersion@0 displayName: 'Use Python $(python.version)' @@ -53,9 +53,8 @@ jobs: name: 'pool-ubuntu-2004' steps: - task: UsePythonVersion@0 - displayName: Use Python 3.10 inputs: - versionSpec: 3.10 + versionSpec: 3.11 - bash: | set -ev diff --git a/knack/cli.py b/knack/cli.py index 8178be7..0562865 100644 --- a/knack/cli.py +++ b/knack/cli.py @@ -104,7 +104,7 @@ def __init__(self, def _should_show_version(args): return args and (args[0] == '--version' or args[0] == '-v') - def get_cli_version(self): # pylint: disable=no-self-use + def get_cli_version(self): """ Get the CLI Version. Override this to define how to get the CLI version :return: The CLI version @@ -112,7 +112,7 @@ def get_cli_version(self): # pylint: disable=no-self-use """ return '' - def get_runtime_version(self): # pylint: disable=no-self-use + def get_runtime_version(self): """ Get the runtime information. :return: Runtime information @@ -169,7 +169,7 @@ def raise_event(self, event_name, **kwargs): for func in handlers: func(self, **kwargs) - def exception_handler(self, ex): # pylint: disable=no-self-use + def exception_handler(self, ex): """ The default exception handler """ if isinstance(ex, CLIError): logger.error(ex) diff --git a/knack/completion.py b/knack/completion.py index 3d4ecb1..b5b27c1 100644 --- a/knack/completion.py +++ b/knack/completion.py @@ -34,7 +34,7 @@ def __init__(self, cli_ctx=None): self.cli_ctx = cli_ctx self.cli_ctx.data['completer_active'] = ARGCOMPLETE_ENV_NAME in os.environ - def get_completion_args(self, is_completion=False, comp_line=None): # pylint: disable=no-self-use + def get_completion_args(self, is_completion=False, comp_line=None): """ Get the args that will be used to tab completion if completion is active. """ is_completion = is_completion or os.environ.get(ARGCOMPLETE_ENV_NAME) comp_line = comp_line or os.environ.get('COMP_LINE') diff --git a/knack/deprecation.py b/knack/deprecation.py index bb183a9..ffaa429 100644 --- a/knack/deprecation.py +++ b/knack/deprecation.py @@ -94,12 +94,10 @@ def _default_get_message(self): message_func=message_func or _default_get_message ) - # pylint: disable=no-self-use def _version_less_than_or_equal_to(self, v1, v2): """ Returns true if v1 <= v2. """ - # pylint: disable=no-name-in-module, import-error - from distutils.version import LooseVersion - return LooseVersion(v1) <= LooseVersion(v2) + from packaging.version import parse + return parse(v1) <= parse(v2) def expired(self): if self.expiration: diff --git a/knack/introspection.py b/knack/introspection.py index 65e045c..e8412ea 100644 --- a/knack/introspection.py +++ b/knack/introspection.py @@ -67,45 +67,23 @@ def extract_args_from_signature(operation, excluded_params=None): """ Extracts basic argument data from an operation's signature and docstring excluded_params: List of params to ignore and not extract. By default we ignore ['self', 'kwargs']. """ - args = [] - try: - # only supported in python3 - falling back to argspec if not available - sig = inspect.signature(operation) - args = sig.parameters - except AttributeError: - sig = inspect.getargspec(operation) # pylint: disable=deprecated-method, useless-suppression - args = sig.args + sig = inspect.signature(operation) + args = sig.parameters arg_docstring_help = option_descriptions(operation) excluded_params = excluded_params or ['self', 'kwargs'] for arg_name in [a for a in args if a not in excluded_params]: - try: - # this works in python3 - default = args[arg_name].default - required = default == inspect.Parameter.empty # pylint: disable=no-member, useless-suppression - except TypeError: - arg_defaults = (dict(zip(sig.args[-len(sig.defaults):], sig.defaults)) - if sig.defaults - else {}) - default = arg_defaults.get(arg_name) - required = arg_name not in arg_defaults - + default = args[arg_name].default + required = default == inspect.Parameter.empty action = 'store_' + str(not default).lower() if isinstance(default, bool) else None - - try: - default = (default - if default != inspect._empty # pylint: disable=protected-access - else None) - except AttributeError: - pass - + command_argument_default = default if default != inspect.Parameter.empty else None options_list = ['--' + arg_name.replace('_', '-')] help_str = arg_docstring_help.get(arg_name) yield (arg_name, CLICommandArgument(arg_name, options_list=options_list, required=required, - default=default, + default=command_argument_default, help=help_str, action=action)) diff --git a/knack/invocation.py b/knack/invocation.py index 46420b5..b9011bc 100644 --- a/knack/invocation.py +++ b/knack/invocation.py @@ -54,7 +54,7 @@ def __init__(self, prog=self.cli_ctx.name, parents=[self._global_parser]) self.commands_loader = commands_loader_cls(cli_ctx=self.cli_ctx) - def _filter_params(self, args): # pylint: disable=no-self-use + def _filter_params(self, args): # Consider - we are using any args that start with an underscore (_) as 'private' # arguments and remove them from the arguments that we pass to the actual function. params = {key: value @@ -88,7 +88,7 @@ def _find_args(args): return ' '.join(nouns) - def _validate_cmd_level(self, ns, cmd_validator): # pylint: disable=no-self-use + def _validate_cmd_level(self, ns, cmd_validator): if cmd_validator: cmd_validator(ns) try: @@ -96,7 +96,7 @@ def _validate_cmd_level(self, ns, cmd_validator): # pylint: disable=no-self-use except AttributeError: pass - def _validate_arg_level(self, ns, **_): # pylint: disable=no-self-use + def _validate_arg_level(self, ns, **_): for validator in getattr(ns, '_argument_validators', []): validator(ns) try: diff --git a/knack/log.py b/knack/log.py index 5c0aec9..7baa46a 100644 --- a/knack/log.py +++ b/knack/log.py @@ -180,7 +180,7 @@ def _is_file_log_enabled(cli_ctx): @staticmethod def _get_log_dir(cli_ctx): - default_dir = (os.path.join(cli_ctx.config.config_dir, 'logs')) + default_dir = os.path.join(cli_ctx.config.config_dir, 'logs') return os.path.expanduser(cli_ctx.config.get('logging', 'log_dir', fallback=default_dir)) def _get_console_log_levels(self): diff --git a/knack/output.py b/knack/output.py index cb71eff..ed3bf2a 100644 --- a/knack/output.py +++ b/knack/output.py @@ -129,7 +129,7 @@ def __init__(self, cli_ctx=None): self.cli_ctx.register_event(EVENT_PARSER_GLOBAL_CREATE, OutputProducer.on_global_arguments) self.cli_ctx.register_event(EVENT_INVOKER_POST_PARSE_ARGS, OutputProducer.handle_output_argument) - def out(self, obj, formatter=None, out_file=None): # pylint: disable=no-self-use + def out(self, obj, formatter=None, out_file=None): """ Produces the output using the command result. The method does not return a result as the output is written straight to the output file. @@ -157,7 +157,7 @@ def out(self, obj, formatter=None, out_file=None): # pylint: disable=no-self-us print(output.encode('ascii', 'ignore').decode('utf-8', 'ignore'), file=out_file, end='') - def get_formatter(self, format_type): # pylint: disable=no-self-use + def get_formatter(self, format_type): # remove color if stdout is not a tty if not self.cli_ctx.enable_color and format_type == 'jsonc': return OutputProducer._FORMAT_DICT['json'] diff --git a/knack/testsdk/base.py b/knack/testsdk/base.py index 0b522c8..e6a07ef 100644 --- a/knack/testsdk/base.py +++ b/knack/testsdk/base.py @@ -33,7 +33,7 @@ def __init__(self, cli, method_name): def cmd(self, command, checks=None, expect_failure=False): return ExecutionResult(self.cli, command, expect_failure=expect_failure).assert_with_checks(checks) - def create_random_name(self, prefix, length): # pylint: disable=no-self-use + def create_random_name(self, prefix, length): return create_random_name(prefix=prefix, length=length) def create_temp_file(self, size_kb, full_random=False): @@ -117,7 +117,7 @@ def setUp(self): # set up cassette cm = self.vcr.use_cassette(self.recording_file) - self.cassette = cm.__enter__() + self.cassette = cm.__enter__() # pylint: disable=unnecessary-dunder-call self.addCleanup(cm.__exit__) if not self.in_recording: diff --git a/knack/testsdk/patches.py b/knack/testsdk/patches.py index 080b1b0..2e31302 100644 --- a/knack/testsdk/patches.py +++ b/knack/testsdk/patches.py @@ -18,5 +18,5 @@ def _mock_in_unit_test(unit_test, target, replacement): if not isinstance(unit_test, unittest.TestCase): raise CliTestError('The patch can be only used in unit test') mp = mock.patch(target, replacement) - mp.__enter__() + mp.__enter__() # pylint: disable=unnecessary-dunder-call unit_test.addCleanup(mp.__exit__) diff --git a/knack/testsdk/recording_processors.py b/knack/testsdk/recording_processors.py index 92b3f69..0f0e120 100644 --- a/knack/testsdk/recording_processors.py +++ b/knack/testsdk/recording_processors.py @@ -5,10 +5,10 @@ class RecordingProcessor(object): - def process_request(self, request): # pylint: disable=no-self-use + def process_request(self, request): return request - def process_response(self, response): # pylint: disable=no-self-use + def process_response(self, response): return response @classmethod diff --git a/knack/util.py b/knack/util.py index 45a1c21..68e5076 100644 --- a/knack/util.py +++ b/knack/util.py @@ -86,7 +86,6 @@ def __init__(self, cli_ctx, object_type, target, tag_func, message_func, color, self._get_tag = tag_func self._get_message = message_func - # pylint: disable=no-self-use def hidden(self): return False diff --git a/requirements.txt b/requirements.txt index 2a9ddfe..8861184 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,9 +1,10 @@ -argcomplete==1.12.2 -flake8==4.0.1 -jmespath==0.10.0 -Pygments==2.8.1 -pylint==2.11.1 -pytest==6.2.5 +argcomplete==3.1.1 +flake8==6.0.0 +jmespath==1.0.1 +packaging==23.1 +Pygments==2.15.1 +pylint==2.17.4 +pytest==7.4.0 PyYAML -tabulate==0.8.9 -vcrpy==4.1.1 +tabulate==0.9.0 +vcrpy==5.0.0 diff --git a/setup.py b/setup.py index 43bdece..f92956e 100644 --- a/setup.py +++ b/setup.py @@ -13,6 +13,7 @@ DEPENDENCIES = [ 'argcomplete', 'jmespath', + 'packaging', 'pygments', 'pyyaml', 'tabulate' @@ -37,10 +38,10 @@ 'Intended Audience :: System Administrators', 'Programming Language :: Python', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: 3.11', 'License :: OSI Approved :: MIT License', ], packages=['knack', 'knack.testsdk'], diff --git a/tests/test_query.py b/tests/test_query.py index b45ef32..c6c1975 100644 --- a/tests/test_query.py +++ b/tests/test_query.py @@ -38,12 +38,12 @@ class TestQuery(unittest.TestCase): (We are not testing JMESPath itself here) ''' - def test_query_valid_1(self): # pylint: disable=no-self-use + def test_query_valid_1(self): query = 'length(@)' # Should not raise any exception as it is valid CLIQuery.jmespath_type(query) - def test_query_valid_2(self): # pylint: disable=no-self-use + def test_query_valid_2(self): query = "[?propertyX.propertyY.propertyZ=='AValue'].[col1,col2]" # Should not raise any exception as it is valid CLIQuery.jmespath_type(query) diff --git a/tox.ini b/tox.ini index d2f0040..d4153bd 100644 --- a/tox.ini +++ b/tox.ini @@ -1,10 +1,10 @@ [tox] -envlist = py36,py37,py38,py39,py310 +envlist = py38,py39,py310,py311 [testenv] deps = -rrequirements.txt commands= python ./scripts/license_verify.py flake8 --statistics --append-config=.flake8 knack - pylint knack --rcfile=.pylintrc -r n -d I0013 + pylint knack --rcfile=.pylintrc --reports n --disable I0013 pytest python ./examples/test_exapp