From ec28703dc304a50ef09671595104fc82ec81666d Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Wed, 7 May 2025 12:24:37 +0100 Subject: [PATCH] Bump Python version used for linters to 3.9 We should have done this ages ago. Do it now. The main change is that this lets us use the newly subscriptable 'type' [1], 'list' [2], and 'frozenset' [3] introduced in this version. [1] https://docs.python.org/3/library/typing.html#typing.Type [2] https://docs.python.org/3/library/typing.html#typing.List [3] https://docs.python.org/3/library/typing.html#typing.FrozenSet Signed-off-by: Stephen Finucane Change-Id: Idf13dd34c54534a6572beaa4675498d7e9a3be52 --- keystoneauth1/_fair_semaphore.py | 2 +- keystoneauth1/access/access.py | 2 +- keystoneauth1/extras/_saml2/_loading.py | 5 ++-- keystoneauth1/extras/kerberos/_loading.py | 4 +-- keystoneauth1/extras/oauth1/_loading.py | 3 +-- keystoneauth1/identity/v3/base.py | 4 +-- keystoneauth1/loading/_plugins/admin_token.py | 3 +-- keystoneauth1/loading/_plugins/http_basic.py | 3 +-- .../loading/_plugins/identity/generic.py | 5 ++-- keystoneauth1/loading/_plugins/identity/v2.py | 5 ++-- keystoneauth1/loading/_plugins/identity/v3.py | 26 +++++++++---------- keystoneauth1/loading/_plugins/noauth.py | 3 +-- keystoneauth1/loading/adapter.py | 2 +- keystoneauth1/loading/base.py | 4 +-- keystoneauth1/loading/opts.py | 4 +-- keystoneauth1/loading/session.py | 2 +- keystoneauth1/plugin.py | 2 +- keystoneauth1/session.py | 2 +- pyproject.toml | 2 +- 19 files changed, 38 insertions(+), 45 deletions(-) diff --git a/keystoneauth1/_fair_semaphore.py b/keystoneauth1/_fair_semaphore.py index c7b1ffac..b828d506 100644 --- a/keystoneauth1/_fair_semaphore.py +++ b/keystoneauth1/_fair_semaphore.py @@ -93,7 +93,7 @@ class FairSemaphore: def __exit__( self, - exc_type: ty.Optional[ty.Type[BaseException]], + exc_type: ty.Optional[type[BaseException]], exc_value: ty.Optional[BaseException], traceback: ty.Optional[types.TracebackType], ) -> None: diff --git a/keystoneauth1/access/access.py b/keystoneauth1/access/access.py index ceadba74..45d0d639 100644 --- a/keystoneauth1/access/access.py +++ b/keystoneauth1/access/access.py @@ -57,7 +57,7 @@ class AccessInfo: Provides helper methods for extracting useful values from that token. """ - _service_catalog_class: ty.Type[service_catalog.ServiceCatalog] + _service_catalog_class: type[service_catalog.ServiceCatalog] _data: ty.Any def __init__( diff --git a/keystoneauth1/extras/_saml2/_loading.py b/keystoneauth1/extras/_saml2/_loading.py index 5f8c4738..7e374bf7 100644 --- a/keystoneauth1/extras/_saml2/_loading.py +++ b/keystoneauth1/extras/_saml2/_loading.py @@ -10,7 +10,6 @@ # License for the specific language governing permissions and limitations # under the License. -import typing as ty from keystoneauth1.extras import _saml2 from keystoneauth1 import loading @@ -19,7 +18,7 @@ from keystoneauth1.loading import opts class Saml2Password(loading.BaseFederationLoader[_saml2.V3Saml2Password]): @property - def plugin_class(self) -> ty.Type[_saml2.V3Saml2Password]: + def plugin_class(self) -> type[_saml2.V3Saml2Password]: return _saml2.V3Saml2Password @property @@ -51,7 +50,7 @@ class Saml2Password(loading.BaseFederationLoader[_saml2.V3Saml2Password]): class ADFSPassword(loading.BaseFederationLoader[_saml2.V3ADFSPassword]): @property - def plugin_class(self) -> ty.Type[_saml2.V3ADFSPassword]: + def plugin_class(self) -> type[_saml2.V3ADFSPassword]: return _saml2.V3ADFSPassword @property diff --git a/keystoneauth1/extras/kerberos/_loading.py b/keystoneauth1/extras/kerberos/_loading.py index 34b4f54c..cf7dba79 100644 --- a/keystoneauth1/extras/kerberos/_loading.py +++ b/keystoneauth1/extras/kerberos/_loading.py @@ -20,7 +20,7 @@ from keystoneauth1.loading import opts class Kerberos(loading.BaseV3Loader[kerberos.Kerberos]): @property - def plugin_class(self) -> ty.Type[kerberos.Kerberos]: + def plugin_class(self) -> type[kerberos.Kerberos]: return kerberos.Kerberos @property @@ -59,7 +59,7 @@ class Kerberos(loading.BaseV3Loader[kerberos.Kerberos]): class MappedKerberos(loading.BaseFederationLoader[kerberos.MappedKerberos]): @property - def plugin_class(self) -> ty.Type[kerberos.MappedKerberos]: + def plugin_class(self) -> type[kerberos.MappedKerberos]: return kerberos.MappedKerberos @property diff --git a/keystoneauth1/extras/oauth1/_loading.py b/keystoneauth1/extras/oauth1/_loading.py index dfe56f5d..baeca4dd 100644 --- a/keystoneauth1/extras/oauth1/_loading.py +++ b/keystoneauth1/extras/oauth1/_loading.py @@ -10,7 +10,6 @@ # License for the specific language governing permissions and limitations # under the License. -import typing as ty from keystoneauth1.extras.oauth1 import v3 from keystoneauth1 import loading @@ -21,7 +20,7 @@ from keystoneauth1.loading import opts # include the scoping options like project-id in the option list class V3OAuth1(loading.BaseIdentityLoader[v3.OAuth1]): @property - def plugin_class(self) -> ty.Type[v3.OAuth1]: + def plugin_class(self) -> type[v3.OAuth1]: return v3.OAuth1 @property diff --git a/keystoneauth1/identity/v3/base.py b/keystoneauth1/identity/v3/base.py index 5ccb53c9..79118e87 100644 --- a/keystoneauth1/identity/v3/base.py +++ b/keystoneauth1/identity/v3/base.py @@ -362,7 +362,7 @@ class AuthMethod(metaclass=abc.ABCMeta): @ty.runtime_checkable class SupportsMultiFactor(ty.Protocol): - _auth_method_class: ty.ClassVar[ty.Type[AuthMethod]] + _auth_method_class: ty.ClassVar[type[AuthMethod]] class AuthConstructor(Auth, metaclass=abc.ABCMeta): @@ -376,7 +376,7 @@ class AuthConstructor(Auth, metaclass=abc.ABCMeta): creates the auth plugin with only that authentication method. """ - _auth_method_class: ty.ClassVar[ty.Type[AuthMethod]] + _auth_method_class: ty.ClassVar[type[AuthMethod]] def __init__( self, diff --git a/keystoneauth1/loading/_plugins/admin_token.py b/keystoneauth1/loading/_plugins/admin_token.py index 68a52014..328e059b 100644 --- a/keystoneauth1/loading/_plugins/admin_token.py +++ b/keystoneauth1/loading/_plugins/admin_token.py @@ -10,7 +10,6 @@ # License for the specific language governing permissions and limitations # under the License. -import typing as ty from keystoneauth1 import loading from keystoneauth1.loading import opts @@ -31,7 +30,7 @@ class AdminToken(loading.BaseLoader[token_endpoint.Token]): """ @property - def plugin_class(self) -> ty.Type[token_endpoint.Token]: + def plugin_class(self) -> type[token_endpoint.Token]: return token_endpoint.Token def get_options(self) -> list[opts.Opt]: diff --git a/keystoneauth1/loading/_plugins/http_basic.py b/keystoneauth1/loading/_plugins/http_basic.py index 6842ba83..8331593c 100644 --- a/keystoneauth1/loading/_plugins/http_basic.py +++ b/keystoneauth1/loading/_plugins/http_basic.py @@ -10,7 +10,6 @@ # License for the specific language governing permissions and limitations # under the License. -import typing as ty from keystoneauth1 import http_basic from keystoneauth1 import loading @@ -30,7 +29,7 @@ class HTTPBasicAuth(loading.BaseLoader[http_basic.HTTPBasicAuth]): """ @property - def plugin_class(self) -> ty.Type[http_basic.HTTPBasicAuth]: + def plugin_class(self) -> type[http_basic.HTTPBasicAuth]: return http_basic.HTTPBasicAuth def get_options(self) -> list[opts.Opt]: diff --git a/keystoneauth1/loading/_plugins/identity/generic.py b/keystoneauth1/loading/_plugins/identity/generic.py index d83587a6..1710f7af 100644 --- a/keystoneauth1/loading/_plugins/identity/generic.py +++ b/keystoneauth1/loading/_plugins/identity/generic.py @@ -10,7 +10,6 @@ # License for the specific language governing permissions and limitations # under the License. -import typing as ty from keystoneauth1 import identity from keystoneauth1 import loading @@ -31,7 +30,7 @@ class Token(loading.BaseGenericLoader[identity.Token]): """ @property - def plugin_class(self) -> ty.Type[identity.Token]: + def plugin_class(self) -> type[identity.Token]: return identity.Token def get_options(self) -> list[opts.Opt]: @@ -60,7 +59,7 @@ class Password(loading.BaseGenericLoader[identity.Password]): """ @property - def plugin_class(self) -> ty.Type[identity.Password]: + def plugin_class(self) -> type[identity.Password]: return identity.Password def get_options(self) -> list[opts.Opt]: diff --git a/keystoneauth1/loading/_plugins/identity/v2.py b/keystoneauth1/loading/_plugins/identity/v2.py index fdeef9dc..28da3ac9 100644 --- a/keystoneauth1/loading/_plugins/identity/v2.py +++ b/keystoneauth1/loading/_plugins/identity/v2.py @@ -10,7 +10,6 @@ # License for the specific language governing permissions and limitations # under the License. -import typing as ty from keystoneauth1 import identity from keystoneauth1 import loading @@ -27,7 +26,7 @@ class Token(loading.BaseV2Loader[identity.V2Token]): """ @property - def plugin_class(self) -> ty.Type[identity.V2Token]: + def plugin_class(self) -> type[identity.V2Token]: return identity.V2Token def get_options(self) -> list[opts.Opt]: @@ -46,7 +45,7 @@ class Password(loading.BaseV2Loader[identity.V2Password]): """ @property - def plugin_class(self) -> ty.Type[identity.V2Password]: + def plugin_class(self) -> type[identity.V2Password]: return identity.V2Password def get_options(self) -> list[opts.Opt]: diff --git a/keystoneauth1/loading/_plugins/identity/v3.py b/keystoneauth1/loading/_plugins/identity/v3.py index bcf32c80..ba2557af 100644 --- a/keystoneauth1/loading/_plugins/identity/v3.py +++ b/keystoneauth1/loading/_plugins/identity/v3.py @@ -54,7 +54,7 @@ class Password(loading.BaseV3Loader[identity.V3Password]): """ @property - def plugin_class(self) -> ty.Type[identity.V3Password]: + def plugin_class(self) -> type[identity.V3Password]: return identity.V3Password def get_options(self) -> list[opts.Opt]: @@ -90,7 +90,7 @@ class Token(loading.BaseV3Loader[identity.V3Token]): """ @property - def plugin_class(self) -> ty.Type[identity.V3Token]: + def plugin_class(self) -> type[identity.V3Token]: return identity.V3Token def get_options(self) -> list[opts.Opt]: @@ -177,7 +177,7 @@ class OpenIDConnectClientCredentials( """Authenticate with the OIDC Client Credentials flow.""" @property - def plugin_class(self) -> ty.Type[identity.V3OidcClientCredentials]: + def plugin_class(self) -> type[identity.V3OidcClientCredentials]: return identity.V3OidcClientCredentials def get_options(self) -> list[opts.Opt]: @@ -190,7 +190,7 @@ class OpenIDConnectPassword(_OpenIDConnectBase[identity.V3OidcPassword]): """Authenticate with the OIDC Resource Owner Password Credentials flow.""" @property - def plugin_class(self) -> ty.Type[identity.V3OidcPassword]: + def plugin_class(self) -> type[identity.V3OidcPassword]: return identity.V3OidcPassword def get_options(self) -> list[opts.Opt]: @@ -220,7 +220,7 @@ class OpenIDConnectAuthorizationCode( """Authenticate with the OIDC Authorization Code flow.""" @property - def plugin_class(self) -> ty.Type[identity.V3OidcAuthorizationCode]: + def plugin_class(self) -> type[identity.V3OidcAuthorizationCode]: return identity.V3OidcAuthorizationCode def get_options(self) -> list[opts.Opt]: @@ -250,7 +250,7 @@ class OpenIDConnectAccessToken( """Authenticate with the OIDC Access Token flow.""" @property - def plugin_class(self) -> ty.Type[identity.V3OidcAccessToken]: + def plugin_class(self) -> type[identity.V3OidcAccessToken]: return identity.V3OidcAccessToken def get_options(self) -> list[opts.Opt]: @@ -275,7 +275,7 @@ class OpenIDConnectDeviceAuthorization( """Authenticate with the OAuth 2.0 Device Authorization flow.""" @property - def plugin_class(self) -> ty.Type[identity.V3OidcDeviceAuthorization]: + def plugin_class(self) -> type[identity.V3OidcDeviceAuthorization]: return identity.V3OidcDeviceAuthorization def get_options(self) -> list[opts.Opt]: @@ -312,7 +312,7 @@ class TOTP(loading.BaseV3Loader[identity.V3TOTP]): """ @property - def plugin_class(self) -> ty.Type[identity.V3TOTP]: + def plugin_class(self) -> type[identity.V3TOTP]: return identity.V3TOTP def get_options(self) -> list[opts.Opt]: @@ -342,7 +342,7 @@ class TokenlessAuth(loading.BaseLoader[identity.V3TokenlessAuth]): """Authenticate without a token, using an X.509 certificate.""" @property - def plugin_class(self) -> ty.Type[identity.V3TokenlessAuth]: + def plugin_class(self) -> type[identity.V3TokenlessAuth]: return identity.V3TokenlessAuth def get_options(self) -> list[opts.Opt]: @@ -407,7 +407,7 @@ class ApplicationCredential( """ @property - def plugin_class(self) -> ty.Type[identity.V3ApplicationCredential]: + def plugin_class(self) -> type[identity.V3ApplicationCredential]: return identity.V3ApplicationCredential def get_options(self) -> list[opts.Opt]: @@ -466,7 +466,7 @@ class MultiFactor(loading.BaseV3Loader[identity.V3MultiFactor]): self._methods = None @property - def plugin_class(self) -> ty.Type[identity.V3MultiFactor]: + def plugin_class(self) -> type[identity.V3MultiFactor]: return identity.V3MultiFactor def get_options(self) -> list[opts.Opt]: @@ -508,7 +508,7 @@ class OAuth2ClientCredential( """Authenticate with an OAuth2.0 client credential.""" @property - def plugin_class(self) -> ty.Type[identity.V3OAuth2ClientCredential]: + def plugin_class(self) -> type[identity.V3OAuth2ClientCredential]: return identity.V3OAuth2ClientCredential def get_options(self) -> list[opts.Opt]: @@ -558,7 +558,7 @@ class OAuth2mTlsClientCredential( """Authenticate with an OAuth2.0 mTLS client credential.""" @property - def plugin_class(self) -> ty.Type[identity.V3OAuth2mTlsClientCredential]: + def plugin_class(self) -> type[identity.V3OAuth2mTlsClientCredential]: return identity.V3OAuth2mTlsClientCredential def get_options(self) -> list[opts.Opt]: diff --git a/keystoneauth1/loading/_plugins/noauth.py b/keystoneauth1/loading/_plugins/noauth.py index d354e21d..79e3e681 100644 --- a/keystoneauth1/loading/_plugins/noauth.py +++ b/keystoneauth1/loading/_plugins/noauth.py @@ -10,7 +10,6 @@ # License for the specific language governing permissions and limitations # under the License. -import typing as ty from keystoneauth1 import loading from keystoneauth1.loading import opts @@ -30,7 +29,7 @@ class NoAuth(loading.BaseLoader[noauth.NoAuth]): """ @property - def plugin_class(self) -> ty.Type[noauth.NoAuth]: + def plugin_class(self) -> type[noauth.NoAuth]: return noauth.NoAuth def get_options(self) -> list[opts.Opt]: diff --git a/keystoneauth1/loading/adapter.py b/keystoneauth1/loading/adapter.py index 4c0c5c5c..baa1ba64 100644 --- a/keystoneauth1/loading/adapter.py +++ b/keystoneauth1/loading/adapter.py @@ -34,7 +34,7 @@ __all__ = ( class Adapter(base._BaseLoader[adapter.Adapter]): @property - def plugin_class(self) -> ty.Type[adapter.Adapter]: + def plugin_class(self) -> type[adapter.Adapter]: return adapter.Adapter def get_options(self) -> list['opts.Opt']: diff --git a/keystoneauth1/loading/base.py b/keystoneauth1/loading/base.py index 85d0c2d4..af88eb6b 100644 --- a/keystoneauth1/loading/base.py +++ b/keystoneauth1/loading/base.py @@ -42,7 +42,7 @@ def _auth_plugin_available(ext: extension.Extension) -> bool: return ty.cast(bool, ext.obj.available) -def get_available_plugin_names() -> ty.FrozenSet[str]: +def get_available_plugin_names() -> frozenset[str]: """Get the names of all the plugins that are available on the system. This is particularly useful for help and error text to prompt a user for @@ -116,7 +116,7 @@ def get_plugin_options(name: str) -> list['opts.Opt']: class _BaseLoader(ty.Generic[T], metaclass=abc.ABCMeta): @property - def plugin_class(self) -> ty.Type[T]: + def plugin_class(self) -> type[T]: raise NotImplementedError() def create_plugin(self, **kwargs: ty.Any) -> T: diff --git a/keystoneauth1/loading/opts.py b/keystoneauth1/loading/opts.py index 98e67f31..492de101 100644 --- a/keystoneauth1/loading/opts.py +++ b/keystoneauth1/loading/opts.py @@ -66,7 +66,7 @@ class Opt: def __init__( self, name: str, - type: ty.Type[ty.Any] = str, + type: type[ty.Any] = str, help: ty.Optional[str] = None, secret: bool = False, dest: ty.Optional[str] = None, @@ -141,7 +141,7 @@ class Opt: return [f'--os-{o.name}' for o in self._all_opts] @property - def argparse_envvars(self) -> ty.List[str]: + def argparse_envvars(self) -> list[str]: return [ 'OS_{}'.format(o.name.replace('-', '_').upper()) for o in self._all_opts diff --git a/keystoneauth1/loading/session.py b/keystoneauth1/loading/session.py index e60a7b77..fd711e2b 100644 --- a/keystoneauth1/loading/session.py +++ b/keystoneauth1/loading/session.py @@ -51,7 +51,7 @@ def _positive_non_zero_float( class Session(base._BaseLoader[session.Session]): @property - def plugin_class(self) -> ty.Type[session.Session]: + def plugin_class(self) -> type[session.Session]: return session.Session def get_options(self) -> list['opts.Opt']: diff --git a/keystoneauth1/plugin.py b/keystoneauth1/plugin.py index 357119e9..ab458870 100644 --- a/keystoneauth1/plugin.py +++ b/keystoneauth1/plugin.py @@ -35,7 +35,7 @@ BaseAuthPluginT = ty.TypeVar( class ConnectionParams(ty.TypedDict): # https://github.com/python/typeshed/blob/24c78b9e0/stubs/requests/requests/sessions.pyi#L82 - cert: ty_ext.NotRequired[ty.Union[str, ty.Tuple[str, str], None]] + cert: ty_ext.NotRequired[ty.Union[str, tuple[str, str], None]] # https://github.com/python/typeshed/blob/24c78b9e0/stubs/requests/requests/sessions.pyi#L108 verify: ty_ext.NotRequired[ty.Union[bool, str, None]] diff --git a/keystoneauth1/session.py b/keystoneauth1/session.py index 293a59b6..3167d596 100644 --- a/keystoneauth1/session.py +++ b/keystoneauth1/session.py @@ -118,7 +118,7 @@ class NoOpSemaphore: def __exit__( self, - exc_type: ty.Optional[ty.Type[BaseException]], + exc_type: ty.Optional[type[BaseException]], exc_value: ty.Optional[BaseException], traceback: ty.Optional[types.TracebackType], ) -> None: diff --git a/pyproject.toml b/pyproject.toml index 95375810..243e9bd7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -42,7 +42,7 @@ disallow_untyped_calls = false [tool.ruff] line-length = 79 -target-version = "py38" +target-version = "py39" [tool.ruff.lint] # enable the following rule classes: