diff --git a/azure-pipelines-full-tests.yml b/azure-pipelines-full-tests.yml index 33980164884..977cdb446ef 100644 --- a/azure-pipelines-full-tests.yml +++ b/azure-pipelines-full-tests.yml @@ -25,8 +25,8 @@ jobs: matrix: Python39: python.version: '3.9' - Python310: - python.version: '3.10' + Python311: + python.version: '3.11' steps: - template: .azure-pipelines/templates/automation_test.yml parameters: @@ -44,8 +44,8 @@ jobs: matrix: Python39: python.version: '3.9' - Python310: - python.version: '3.10' + Python311: + python.version: '3.11' steps: - template: .azure-pipelines/templates/automation_test.yml parameters: @@ -63,8 +63,8 @@ jobs: matrix: Python39: python.version: '3.9' - Python310: - python.version: '3.10' + Python311: + python.version: '3.11' steps: - template: .azure-pipelines/templates/automation_test.yml parameters: @@ -107,8 +107,8 @@ jobs: fullTest: true jobName: 'FullTest' -- job: AutomationFullTestPython310ProfileLatest - displayName: Automation Full Test Python310 Profile Latest +- job: AutomationFullTestPython311ProfileLatest + displayName: Automation Full Test Python311 Profile Latest timeoutInMinutes: 9999 strategy: maxParallel: 8 @@ -134,7 +134,7 @@ jobs: steps: - template: .azure-pipelines/templates/automation_test.yml parameters: - pythonVersion: '3.10' + pythonVersion: '3.11' profile: 'latest' instance_cnt: '8' instance_idx: '$(Instance_idx)' @@ -147,16 +147,16 @@ jobs: - AutomationTest20190301 - AutomationTest20180301 - AutomationFullTestPython39ProfileLatest - - AutomationFullTestPython310ProfileLatest + - AutomationFullTestPython311ProfileLatest condition: and(failed(), in(variables['Build.Reason'], 'BatchedCI')) displayName: Notify CI Errors pool: name: ${{ variables.ubuntu_pool }} steps: - task: UsePythonVersion@0 - displayName: 'Use Python 3.10' + displayName: 'Use Python 3.11' inputs: - versionSpec: 3.10 + versionSpec: 3.11 - task: AzureCLI@2 inputs: azureSubscription: 'Azure CLI' diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 7433df640cd..9c2a04b90d6 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -130,9 +130,9 @@ jobs: steps: - task: UsePythonVersion@0 - displayName: 'Use Python 3.10' + displayName: 'Use Python 3.11' inputs: - versionSpec: 3.10 + versionSpec: 3.11 - bash: ./scripts/ci/dependency_check.sh displayName: 'Verify src/azure-cli/requirements.py3.Linux.txt' @@ -145,9 +145,9 @@ jobs: steps: - task: UsePythonVersion@0 - displayName: 'Use Python 3.10' + displayName: 'Use Python 3.11' inputs: - versionSpec: 3.10 + versionSpec: 3.11 - bash: ./scripts/ci/dependency_check.sh displayName: 'Verify src/azure-cli/requirements.py3.Darwin.txt' @@ -160,9 +160,9 @@ jobs: steps: - task: UsePythonVersion@0 - displayName: 'Use Python 3.10' + displayName: 'Use Python 3.11' inputs: - versionSpec: 3.10 + versionSpec: 3.11 - task: BatchScript@1 inputs: @@ -177,9 +177,9 @@ jobs: name: ${{ variables.ubuntu_pool }} steps: - task: UsePythonVersion@0 - displayName: 'Use Python 3.10' + displayName: 'Use Python 3.11' inputs: - versionSpec: 3.10 + versionSpec: 3.11 - template: .azure-pipelines/templates/azdev_setup.yml - bash: | set -ev @@ -349,9 +349,9 @@ jobs: name: ${{ variables.ubuntu_pool }} steps: - task: UsePythonVersion@0 - displayName: 'Use Python 3.10' + displayName: 'Use Python 3.11' inputs: - versionSpec: 3.10 + versionSpec: 3.11 - script: | @@ -411,9 +411,9 @@ jobs: --rm -v $PYPI_FILES:/mnt/pypi python:3.9 \ /bin/bash -c "cd /mnt/pypi && ls && pip install --find-links ./ azure_cli-$CLI_VERSION*whl && az self-test && az --version && sleep 5" - echo "== Testing pip install on Python 3.10 ==" + echo "== Testing pip install on Python 3.11 ==" docker run \ - --rm -v $PYPI_FILES:/mnt/pypi python:3.10 \ + --rm -v $PYPI_FILES:/mnt/pypi python:3.11 \ /bin/bash -c "cd /mnt/pypi && ls && pip install --find-links ./ azure_cli-$CLI_VERSION*whl && az self-test && az --version && sleep 5" displayName: 'Test pip Install' @@ -427,8 +427,8 @@ jobs: matrix: Python39: python.version: '3.9' - Python310: - python.version: '3.10' + Python311: + python.version: '3.11' steps: - template: .azure-pipelines/templates/automation_test.yml parameters: @@ -444,8 +444,8 @@ jobs: matrix: Python39: python.version: '3.9' - Python310: - python.version: '3.10' + Python311: + python.version: '3.11' steps: - template: .azure-pipelines/templates/automation_test.yml parameters: @@ -464,8 +464,8 @@ jobs: matrix: Python39: python.version: '3.9' - Python310: - python.version: '3.10' + Python311: + python.version: '3.11' steps: - task: UsePythonVersion@0 displayName: 'Use Python $(python.version)' @@ -485,8 +485,8 @@ jobs: name: ${{ variables.ubuntu_pool }} strategy: matrix: - Python310: - python.version: '3.10' + Python311: + python.version: '3.11' steps: - task: UsePythonVersion@0 displayName: 'Use Python $(python.version)' @@ -530,7 +530,7 @@ jobs: -e CLI_VERSION=$CLI_VERSION \ -e HOMEBREW_UPSTREAM_URL=$HOMEBREW_UPSTREAM_URL \ --name azurecli \ - python:3.10 \ + python:3.11 \ /mnt/scripts/run.sh # clean up @@ -954,9 +954,9 @@ jobs: name: ${{ variables.ubuntu_pool }} steps: - task: UsePythonVersion@0 - displayName: 'Use Python 3.10' + displayName: 'Use Python 3.11' inputs: - versionSpec: 3.10 + versionSpec: 3.11 - template: .azure-pipelines/templates/azdev_setup.yml - bash: | set -ev @@ -970,9 +970,9 @@ jobs: name: ${{ variables.ubuntu_pool }} steps: - task: UsePythonVersion@0 - displayName: 'Use Python 3.10' + displayName: 'Use Python 3.11' inputs: - versionSpec: 3.10 + versionSpec: 3.11 - template: .azure-pipelines/templates/azdev_setup.yml - bash: | set -ev @@ -987,8 +987,8 @@ jobs: matrix: Python39: python.version: '3.9' - Python310: - python.version: '3.10' + Python311: + python.version: '3.11' pool: name: ${{ variables.ubuntu_pool }} steps: @@ -1016,9 +1016,9 @@ jobs: name: ${{ variables.ubuntu_pool }} steps: - task: UsePythonVersion@0 - displayName: 'Use Python 3.10' + displayName: 'Use Python 3.11' inputs: - versionSpec: 3.10 + versionSpec: 3.11 - template: .azure-pipelines/templates/azdev_setup.yml - bash: | set -ev @@ -1039,9 +1039,9 @@ jobs: name: ${{ variables.ubuntu_pool }} steps: - task: UsePythonVersion@0 - displayName: 'Use Python 3.10' + displayName: 'Use Python 3.11' inputs: - versionSpec: 3.10 + versionSpec: 3.11 - template: .azure-pipelines/templates/azdev_setup.yml - bash: | set -ev @@ -1126,9 +1126,9 @@ jobs: name: ${{ variables.ubuntu_pool }} steps: - task: UsePythonVersion@0 - displayName: 'Use Python 3.10' + displayName: 'Use Python 3.11' inputs: - versionSpec: 3.10 + versionSpec: 3.11 - task: AzureCLI@2 inputs: azureSubscription: 'Azure CLI' diff --git a/scripts/ci/build.sh b/scripts/ci/build.sh index 45efa04313c..671b5d62ec7 100755 --- a/scripts/ci/build.sh +++ b/scripts/ci/build.sh @@ -101,6 +101,7 @@ CLASSIFIERS = [ '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', ] diff --git a/src/azure-cli-core/azure/cli/core/telemetry.py b/src/azure-cli-core/azure/cli/core/telemetry.py index 9ecef53ebd5..380360f8d72 100644 --- a/src/azure-cli-core/azure/cli/core/telemetry.py +++ b/src/azure-cli-core/azure/cli/core/telemetry.py @@ -191,7 +191,7 @@ def _get_azure_cli_properties(self): lambda: _get_config().get('core', 'output', fallback='unknown')) set_custom_properties(result, 'EnvironmentVariables', _get_env_string) set_custom_properties(result, 'Locale', - lambda: '{},{}'.format(locale.getdefaultlocale()[0], locale.getdefaultlocale()[1])) + lambda: '{},{}'.format(locale.getlocale()[0], locale.getlocale()[1])) set_custom_properties(result, 'StartTime', str(self.start_time)) set_custom_properties(result, 'EndTime', str(self.end_time)) set_custom_properties(result, 'InitTimeElapsed', str(self.init_time_elapsed)) diff --git a/src/azure-cli-core/azure/cli/core/tests/test_command_registration.py b/src/azure-cli-core/azure/cli/core/tests/test_command_registration.py index 5bad0b2f311..6e96ef57f13 100644 --- a/src/azure-cli-core/azure/cli/core/tests/test_command_registration.py +++ b/src/azure-cli-core/azure/cli/core/tests/test_command_registration.py @@ -298,10 +298,10 @@ def _check_index(): loader.load_command_table(["hello", "mod-only"]) _check_index() - with mock.patch("azure.cli.core.__version__", "2.7.0"), mock.patch.object(cli.cloud, "profile", "2019-03-01-hybrid"): + with mock.patch.object(cli.cloud, "profile", "2019-03-01-hybrid"): def update_and_check_index(): loader.load_command_table(["hello", "mod-only"]) - self.assertEqual(INDEX[CommandIndex._COMMAND_INDEX_VERSION], "2.7.0") + self.assertEqual(INDEX[CommandIndex._COMMAND_INDEX_VERSION], __version__) self.assertEqual(INDEX[CommandIndex._COMMAND_INDEX_CLOUD_PROFILE], "2019-03-01-hybrid") self.assertDictEqual(INDEX[CommandIndex._COMMAND_INDEX], self.expected_command_index) @@ -395,6 +395,7 @@ def update_and_check_index(): @mock.patch('azure.cli.core.extension.get_extension_modname', _mock_get_extension_modname) @mock.patch('azure.cli.core.extension.get_extensions', _mock_get_extensions) def test_command_index_always_loaded_extensions(self): + import azure from azure.cli.core import CommandIndex cli = DummyCli() @@ -403,14 +404,14 @@ def test_command_index_always_loaded_extensions(self): index.invalidate() # Test azext_always_loaded is loaded when command index is rebuilt - with mock.patch('azure.cli.core.ALWAYS_LOADED_EXTENSIONS', ['azext_always_loaded']): + with mock.patch.object(azure.cli.core,'ALWAYS_LOADED_EXTENSIONS', ['azext_always_loaded']): loader.load_command_table(["hello", "mod-only"]) self.assertEqual(TestCommandRegistration.test_hook, "FAKE_HANDLER") TestCommandRegistration.test_hook = [] # Test azext_always_loaded is loaded when command index is used - with mock.patch('azure.cli.core.ALWAYS_LOADED_EXTENSIONS', ['azext_always_loaded']): + with mock.patch.object(azure.cli.core,'ALWAYS_LOADED_EXTENSIONS', ['azext_always_loaded']): loader.load_command_table(["hello", "mod-only"]) self.assertEqual(TestCommandRegistration.test_hook, "FAKE_HANDLER") diff --git a/src/azure-cli-core/azure/cli/core/tests/test_help.py b/src/azure-cli-core/azure/cli/core/tests/test_help.py index 990c94b79b6..17d8c9587cc 100644 --- a/src/azure-cli-core/azure/cli/core/tests/test_help.py +++ b/src/azure-cli-core/azure/cli/core/tests/test_help.py @@ -130,7 +130,6 @@ def test_help_loads(self): except SystemExit: pass cmd_tbl = cli.invocation.commands_loader.command_table - cli.invocation.parser.load_command_table(cli.invocation.commands_loader) for cmd in cmd_tbl: try: cmd_tbl[cmd].loader.command_name = cmd @@ -140,7 +139,6 @@ def test_help_loads(self): cli.register_event(events.EVENT_INVOKER_POST_CMD_TBL_CREATE, register_global_subscription_argument) cli.register_event(events.EVENT_INVOKER_POST_CMD_TBL_CREATE, register_ids_argument) cli.raise_event(events.EVENT_INVOKER_CMD_TBL_LOADED, command_table=cmd_tbl) - cli.invocation.parser.load_command_table(cli.invocation.commands_loader) _store_parsers(cli.invocation.parser, parser_dict) # TODO: do we want to update this as it doesn't actually load all help. diff --git a/src/azure-cli-core/azure/cli/core/tests/test_parser.py b/src/azure-cli-core/azure/cli/core/tests/test_parser.py index db37b2fc05a..36b1849f1ca 100644 --- a/src/azure-cli-core/azure/cli/core/tests/test_parser.py +++ b/src/azure-cli-core/azure/cli/core/tests/test_parser.py @@ -196,6 +196,8 @@ def load_command_table(self, args): @mock.patch('azure.cli.core.extension.get_extension_modname', _mock_extension_modname) @mock.patch('azure.cli.core.extension.get_extensions', _mock_get_extensions) def test_parser_error_spellchecker(self): + import logging + import azure cli = DummyCli() main_loader = MainCommandsLoader(cli) cli.loader = main_loader @@ -224,8 +226,8 @@ def mock_add_extension(*args, **kwargs): pass # run multiple faulty commands and save error logs, as well as close matches - with mock.patch('logging.Logger.error', mock_log_error), \ - mock.patch('difflib.get_close_matches', mock_get_close_matches): + with mock.patch.object(logging.Logger, 'error', mock_log_error), \ + mock.patch.object(difflib, 'get_close_matches', mock_get_close_matches): faulty_cmd_args = [ 'test module1 --opt enum_1', 'test extension1 --opt enum_1', @@ -256,11 +258,14 @@ def mock_add_extension(*args, **kwargs): self.assertIn(choice, choices) # test dynamic extension install - with mock.patch('logging.Logger.error', mock_log_error), \ - mock.patch('azure.cli.core.extension.operations.add_extension', mock_add_extension), \ - mock.patch('azure.cli.core.extension.dynamic_install._get_extension_command_tree', mock_ext_cmd_tree_load), \ - mock.patch('azure.cli.core.extension.dynamic_install._get_extension_use_dynamic_install_config', return_value='yes_without_prompt'), \ - mock.patch('azure.cli.core.extension.dynamic_install._get_extension_run_after_dynamic_install_config', return_value=False): + with mock.patch.object(logging.Logger, 'error', mock_log_error), \ + mock.patch.object(azure.cli.core.extension.operations, 'add_extension', mock_add_extension), \ + mock.patch.object(azure.cli.core.extension.dynamic_install, '_get_extension_command_tree', + mock_ext_cmd_tree_load), \ + mock.patch.object(azure.cli.core.extension.dynamic_install, '_get_extension_use_dynamic_install_config', + return_value='yes_without_prompt'), \ + mock.patch.object(azure.cli.core.extension.dynamic_install, + '_get_extension_run_after_dynamic_install_config', return_value=False): with self.assertRaises(SystemExit): parser.parse_args('test new-ext create --opt enum_2'.split()) self.assertIn("Extension new-ext-name installed. Please rerun your command.", logger_msgs[5]) diff --git a/src/azure-cli-core/azure/cli/core/util.py b/src/azure-cli-core/azure/cli/core/util.py index ee903887fc8..f54239ee2c2 100644 --- a/src/azure-cli-core/azure/cli/core/util.py +++ b/src/azure-cli-core/azure/cli/core/util.py @@ -655,14 +655,8 @@ def in_cloud_console(): def get_arg_list(op): import inspect - - try: - # only supported in python3 - falling back to argspec if not available - sig = inspect.signature(op) - return sig.parameters - except AttributeError: - sig = inspect.getargspec(op) # pylint: disable=deprecated-method - return sig.args + sig = inspect.signature(op) + return sig.parameters def is_track2(client_class): diff --git a/src/azure-cli-core/setup.py b/src/azure-cli-core/setup.py index cd818eb2576..66071713219 100644 --- a/src/azure-cli-core/setup.py +++ b/src/azure-cli-core/setup.py @@ -38,6 +38,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', ] diff --git a/src/azure-cli-telemetry/setup.py b/src/azure-cli-telemetry/setup.py index 9d72c9d7f73..55a52d35252 100755 --- a/src/azure-cli-telemetry/setup.py +++ b/src/azure-cli-telemetry/setup.py @@ -19,6 +19,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', ] diff --git a/src/azure-cli-testsdk/azure/cli/testsdk/scenario_tests/utilities.py b/src/azure-cli-testsdk/azure/cli/testsdk/scenario_tests/utilities.py index 98be0bccebc..af7b7680dba 100644 --- a/src/azure-cli-testsdk/azure/cli/testsdk/scenario_tests/utilities.py +++ b/src/azure-cli-testsdk/azure/cli/testsdk/scenario_tests/utilities.py @@ -70,7 +70,7 @@ def trim_kwargs_from_test_function(fn, kwargs): # the next function is the actual test function. the kwargs need to be trimmed so # that parameters which are not required will not be passed to it. if not is_preparer_func(fn): - args, _, kw, _ = inspect.getargspec(fn) # pylint: disable=deprecated-method + args, _, kw, *_ = inspect.getfullargspec(fn) if kw is None: args = set(args) for key in [k for k in kwargs if k not in args]: diff --git a/src/azure-cli-testsdk/setup.py b/src/azure-cli-testsdk/setup.py index 34d228b5de9..56ffeb6be42 100644 --- a/src/azure-cli-testsdk/setup.py +++ b/src/azure-cli-testsdk/setup.py @@ -18,6 +18,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', ] diff --git a/src/azure-cli/azure/cli/command_modules/cdn/tests/latest/test_afd_custom_domain_scenarios.py b/src/azure-cli/azure/cli/command_modules/cdn/tests/latest/test_afd_custom_domain_scenarios.py index 91c788db69e..b03ca332d8a 100644 --- a/src/azure-cli/azure/cli/command_modules/cdn/tests/latest/test_afd_custom_domain_scenarios.py +++ b/src/azure-cli/azure/cli/command_modules/cdn/tests/latest/test_afd_custom_domain_scenarios.py @@ -38,8 +38,8 @@ def test_afd_custom_domain_crud(self, resource_group): custom_domain_name = self.create_random_name(prefix='customdomain', length=24) host_name = f"{custom_domain_name}.localdev.cdn.azure.cn" - certificate_type = AfdCertificateType.customer_certificate - minimum_tls_version = AfdMinimumTlsVersion.tls12 + certificate_type = AfdCertificateType.customer_certificate.value + minimum_tls_version = AfdMinimumTlsVersion.tls12.value azure_dns_zone = None checks = [JMESPathCheck('domainValidationState', 'Pending')] diff --git a/src/azure-cli/azure/cli/command_modules/cdn/tests/latest/test_afd_route_scenarios.py b/src/azure-cli/azure/cli/command_modules/cdn/tests/latest/test_afd_route_scenarios.py index d0c8e0d6b8e..dd823dc4d4f 100644 --- a/src/azure-cli/azure/cli/command_modules/cdn/tests/latest/test_afd_route_scenarios.py +++ b/src/azure-cli/azure/cli/command_modules/cdn/tests/latest/test_afd_route_scenarios.py @@ -68,8 +68,8 @@ def test_afd_route_crud(self, resource_group): profile_name, custom_domain_name, host_name, - AfdCertificateType.managed_certificate, - AfdMinimumTlsVersion.tls12, + AfdCertificateType.managed_certificate.value, + AfdMinimumTlsVersion.tls12.value, None, None) diff --git a/src/azure-cli/azure/cli/command_modules/keyvault/vendored_sdks/azure_keyvault_t1/key_vault_authentication.py b/src/azure-cli/azure/cli/command_modules/keyvault/vendored_sdks/azure_keyvault_t1/key_vault_authentication.py index 99d563f21f3..be90ae86bdc 100644 --- a/src/azure-cli/azure/cli/command_modules/keyvault/vendored_sdks/azure_keyvault_t1/key_vault_authentication.py +++ b/src/azure-cli/azure/cli/command_modules/keyvault/vendored_sdks/azure_keyvault_t1/key_vault_authentication.py @@ -59,7 +59,7 @@ def __init__(self, authorization_callback): # for backwards compatibility we need to support callbacks which don't accept the scheme def _auth_callback_compat(self, server, resource, scope, scheme): return self._user_callback(server, resource, scope) \ - if len(inspect.getargspec(self._user_callback).args) == 3 \ + if len(inspect.getfullargspec(self._user_callback).args) == 3 \ else self._user_callback(server, resource, scope, scheme) def __call__(self, request): diff --git a/src/azure-cli/azure/cli/command_modules/sql/tests/latest/test_sql_commands.py b/src/azure-cli/azure/cli/command_modules/sql/tests/latest/test_sql_commands.py index 4ee72f80d3f..7e288645553 100644 --- a/src/azure-cli/azure/cli/command_modules/sql/tests/latest/test_sql_commands.py +++ b/src/azure-cli/azure/cli/command_modules/sql/tests/latest/test_sql_commands.py @@ -942,8 +942,8 @@ def test_sql_db_preferred_enclave_type(self, resource_group, resource_group_loca database_name_one = "cliautomationdb01" database_name_two = "cliautomationdb02" database_name_three = "cliautomationdb03" - preferred_enclave_type_default = AlwaysEncryptedEnclaveType.default - preferred_enclave_type_vbs = AlwaysEncryptedEnclaveType.vbs + preferred_enclave_type_default = AlwaysEncryptedEnclaveType.default.value + preferred_enclave_type_vbs = AlwaysEncryptedEnclaveType.vbs.value # test sql db is created with default enclave type @@ -1020,8 +1020,8 @@ class SqlServerServerlessDbMgmtScenarioTest(ScenarioTest): @AllowLargeResponse() def test_sql_db_serverless_mgmt(self, resource_group, resource_group_location, server): database_name = "cliautomationdb01" - compute_model_serverless = ComputeModelType.serverless - compute_model_provisioned = ComputeModelType.provisioned + compute_model_serverless = ComputeModelType.serverless.value + compute_model_provisioned = ComputeModelType.provisioned.value # Create database with vcore edition vcore_edition = 'GeneralPurpose' @@ -3543,8 +3543,8 @@ def test_sql_elastic_pools_preferred_enclave_type_mgmt(self, resource_group, res database_name_one = "cliautomationdb01" database_name_two = "cliautomationdb02" edition = 'GeneralPurpose' - preferred_enclave_type_default = AlwaysEncryptedEnclaveType.default - preferred_enclave_type_vbs = AlwaysEncryptedEnclaveType.vbs + preferred_enclave_type_default = AlwaysEncryptedEnclaveType.default.value + preferred_enclave_type_vbs = AlwaysEncryptedEnclaveType.vbs.value # Create general purpose pool with default enclave type self.cmd('sql elastic-pool create -g {} --server {} --name {} --edition {} --preferred-enclave-type {}' diff --git a/src/azure-cli/setup.py b/src/azure-cli/setup.py index 3800e8db45e..d9b98ffbf83 100644 --- a/src/azure-cli/setup.py +++ b/src/azure-cli/setup.py @@ -45,6 +45,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', ]