mirror of https://github.com/docker/docker-py.git
types: Add types to `auth`, `client`, `errors`, `tls`
Signed-off-by: Victorien Plot <65306057+Viicos@users.noreply.github.com> Signed-off-by: Viicos <65306057+Viicos@users.noreply.github.com>
This commit is contained in:
parent
c38656dc78
commit
6db8e694db
|
|
@ -1,9 +1,12 @@
|
||||||
|
from __future__ import annotations
|
||||||
import base64
|
import base64
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
|
from typing import Any, AnyStr, Tuple, Dict, Optional, Union
|
||||||
|
|
||||||
from . import credentials
|
from . import credentials
|
||||||
from . import errors
|
from . import errors
|
||||||
|
from .api.client import APIClient
|
||||||
from .utils import config
|
from .utils import config
|
||||||
|
|
||||||
INDEX_NAME = 'docker.io'
|
INDEX_NAME = 'docker.io'
|
||||||
|
|
@ -13,7 +16,7 @@ TOKEN_USERNAME = '<token>'
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def resolve_repository_name(repo_name):
|
def resolve_repository_name(repo_name: str) -> Tuple[str, str]:
|
||||||
if '://' in repo_name:
|
if '://' in repo_name:
|
||||||
raise errors.InvalidRepository(
|
raise errors.InvalidRepository(
|
||||||
f'Repository name cannot contain a scheme ({repo_name})'
|
f'Repository name cannot contain a scheme ({repo_name})'
|
||||||
|
|
@ -28,14 +31,14 @@ def resolve_repository_name(repo_name):
|
||||||
return resolve_index_name(index_name), remote_name
|
return resolve_index_name(index_name), remote_name
|
||||||
|
|
||||||
|
|
||||||
def resolve_index_name(index_name):
|
def resolve_index_name(index_name: str) -> str:
|
||||||
index_name = convert_to_hostname(index_name)
|
index_name = convert_to_hostname(index_name)
|
||||||
if index_name == f"index.{INDEX_NAME}":
|
if index_name == f"index.{INDEX_NAME}":
|
||||||
index_name = INDEX_NAME
|
index_name = INDEX_NAME
|
||||||
return index_name
|
return index_name
|
||||||
|
|
||||||
|
|
||||||
def get_config_header(client, registry):
|
def get_config_header(client: APIClient, registry: str) -> Optional[bytes]:
|
||||||
log.debug('Looking for auth config')
|
log.debug('Looking for auth config')
|
||||||
if not client._auth_configs or client._auth_configs.is_empty:
|
if not client._auth_configs or client._auth_configs.is_empty:
|
||||||
log.debug(
|
log.debug(
|
||||||
|
|
@ -57,7 +60,7 @@ def get_config_header(client, registry):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def split_repo_name(repo_name):
|
def split_repo_name(repo_name: str) -> Tuple[str, str]:
|
||||||
parts = repo_name.split('/', 1)
|
parts = repo_name.split('/', 1)
|
||||||
if len(parts) == 1 or (
|
if len(parts) == 1 or (
|
||||||
'.' not in parts[0] and ':' not in parts[0] and parts[0] != 'localhost'
|
'.' not in parts[0] and ':' not in parts[0] and parts[0] != 'localhost'
|
||||||
|
|
@ -74,7 +77,7 @@ def get_credential_store(authconfig, registry):
|
||||||
|
|
||||||
|
|
||||||
class AuthConfig(dict):
|
class AuthConfig(dict):
|
||||||
def __init__(self, dct, credstore_env=None):
|
def __init__(self, dct: Dict[str, Any], credstore_env: Optional[Dict[str, Any]] = None) -> None:
|
||||||
if 'auths' not in dct:
|
if 'auths' not in dct:
|
||||||
dct['auths'] = {}
|
dct['auths'] = {}
|
||||||
self.update(dct)
|
self.update(dct)
|
||||||
|
|
@ -82,7 +85,7 @@ class AuthConfig(dict):
|
||||||
self._stores = {}
|
self._stores = {}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def parse_auth(cls, entries, raise_on_error=False):
|
def parse_auth(cls, entries: Dict[str, Any], raise_on_error: bool = False) -> Dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
Parses authentication entries
|
Parses authentication entries
|
||||||
|
|
||||||
|
|
@ -142,7 +145,7 @@ class AuthConfig(dict):
|
||||||
return conf
|
return conf
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def load_config(cls, config_path, config_dict, credstore_env=None):
|
def load_config(cls, config_path: str, config_dict: Dict[str, Any], credstore_env: Optional[Dict[str, Any]] = None) -> AuthConfig:
|
||||||
"""
|
"""
|
||||||
Loads authentication data from a Docker configuration file in the given
|
Loads authentication data from a Docker configuration file in the given
|
||||||
root directory or if config_path is passed use given path.
|
root directory or if config_path is passed use given path.
|
||||||
|
|
@ -190,24 +193,24 @@ class AuthConfig(dict):
|
||||||
return cls({'auths': cls.parse_auth(config_dict)}, credstore_env)
|
return cls({'auths': cls.parse_auth(config_dict)}, credstore_env)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def auths(self):
|
def auths(self) -> Dict[str, Any]:
|
||||||
return self.get('auths', {})
|
return self.get('auths', {})
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def creds_store(self):
|
def creds_store(self) -> Optional[str]:
|
||||||
return self.get('credsStore', None)
|
return self.get('credsStore', None)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def cred_helpers(self):
|
def cred_helpers(self) -> Dict[str, Any]:
|
||||||
return self.get('credHelpers', {})
|
return self.get('credHelpers', {})
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_empty(self):
|
def is_empty(self) -> bool:
|
||||||
return (
|
return (
|
||||||
not self.auths and not self.creds_store and not self.cred_helpers
|
not self.auths and not self.creds_store and not self.cred_helpers
|
||||||
)
|
)
|
||||||
|
|
||||||
def resolve_authconfig(self, registry=None):
|
def resolve_authconfig(self, registry: Optional[str] = None) -> Optional[Dict[str, Any]]:
|
||||||
"""
|
"""
|
||||||
Returns the authentication data from the given auth configuration for a
|
Returns the authentication data from the given auth configuration for a
|
||||||
specific registry. As with the Docker client, legacy entries in the
|
specific registry. As with the Docker client, legacy entries in the
|
||||||
|
|
@ -242,7 +245,7 @@ class AuthConfig(dict):
|
||||||
log.debug("No entry found")
|
log.debug("No entry found")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def _resolve_authconfig_credstore(self, registry, credstore_name):
|
def _resolve_authconfig_credstore(self, registry: str, credstore_name: str) -> Optional[Dict[str, Any]]:
|
||||||
if not registry or registry == INDEX_NAME:
|
if not registry or registry == INDEX_NAME:
|
||||||
# The ecosystem is a little schizophrenic with index.docker.io VS
|
# The ecosystem is a little schizophrenic with index.docker.io VS
|
||||||
# docker.io - in that case, it seems the full URL is necessary.
|
# docker.io - in that case, it seems the full URL is necessary.
|
||||||
|
|
@ -270,20 +273,20 @@ class AuthConfig(dict):
|
||||||
f'Credentials store error: {repr(e)}'
|
f'Credentials store error: {repr(e)}'
|
||||||
) from e
|
) from e
|
||||||
|
|
||||||
def _get_store_instance(self, name):
|
def _get_store_instance(self, name: str) -> Dict[str, Any]:
|
||||||
if name not in self._stores:
|
if name not in self._stores:
|
||||||
self._stores[name] = credentials.Store(
|
self._stores[name] = credentials.Store(
|
||||||
name, environment=self._credstore_env
|
name, environment=self._credstore_env
|
||||||
)
|
)
|
||||||
return self._stores[name]
|
return self._stores[name]
|
||||||
|
|
||||||
def get_credential_store(self, registry):
|
def get_credential_store(self, registry: str) -> str:
|
||||||
if not registry or registry == INDEX_NAME:
|
if not registry or registry == INDEX_NAME:
|
||||||
registry = INDEX_URL
|
registry = INDEX_URL
|
||||||
|
|
||||||
return self.cred_helpers.get(registry) or self.creds_store
|
return self.cred_helpers.get(registry) or self.creds_store
|
||||||
|
|
||||||
def get_all_credentials(self):
|
def get_all_credentials(self) -> Dict[str, Any]:
|
||||||
auth_data = self.auths.copy()
|
auth_data = self.auths.copy()
|
||||||
if self.creds_store:
|
if self.creds_store:
|
||||||
# Retrieve all credentials from the default store
|
# Retrieve all credentials from the default store
|
||||||
|
|
@ -303,34 +306,36 @@ class AuthConfig(dict):
|
||||||
|
|
||||||
return auth_data
|
return auth_data
|
||||||
|
|
||||||
def add_auth(self, reg, data):
|
def add_auth(self, reg: str, data: Any) -> None:
|
||||||
self['auths'][reg] = data
|
self['auths'][reg] = data
|
||||||
|
|
||||||
|
|
||||||
def resolve_authconfig(authconfig, registry=None, credstore_env=None):
|
def resolve_authconfig(authconfig: Union[AuthConfig, Dict[str, Any]], registry: Optional[str] = None, credstore_env: Optional[Dict[str, Any]] = None) -> Optional[Dict[str, Any]]:
|
||||||
if not isinstance(authconfig, AuthConfig):
|
if not isinstance(authconfig, AuthConfig):
|
||||||
authconfig = AuthConfig(authconfig, credstore_env)
|
authconfig = AuthConfig(authconfig, credstore_env)
|
||||||
return authconfig.resolve_authconfig(registry)
|
return authconfig.resolve_authconfig(registry)
|
||||||
|
|
||||||
|
|
||||||
def convert_to_hostname(url):
|
def convert_to_hostname(url: str) -> str:
|
||||||
return url.replace('http://', '').replace('https://', '').split('/', 1)[0]
|
return url.replace('http://', '').replace('https://', '').split('/', 1)[0]
|
||||||
|
|
||||||
|
|
||||||
def decode_auth(auth):
|
def decode_auth(auth: AnyStr) -> Tuple[str, str]:
|
||||||
if isinstance(auth, str):
|
if isinstance(auth, str):
|
||||||
auth = auth.encode('ascii')
|
auth_bytes = auth.encode('ascii')
|
||||||
s = base64.b64decode(auth)
|
else:
|
||||||
|
auth_bytes = auth
|
||||||
|
s = base64.b64decode(auth_bytes)
|
||||||
login, pwd = s.split(b':', 1)
|
login, pwd = s.split(b':', 1)
|
||||||
return login.decode('utf8'), pwd.decode('utf8')
|
return login.decode('utf8'), pwd.decode('utf8')
|
||||||
|
|
||||||
|
|
||||||
def encode_header(auth):
|
def encode_header(auth: Dict[str, Any]) -> bytes:
|
||||||
auth_json = json.dumps(auth).encode('ascii')
|
auth_json = json.dumps(auth).encode('ascii')
|
||||||
return base64.urlsafe_b64encode(auth_json)
|
return base64.urlsafe_b64encode(auth_json)
|
||||||
|
|
||||||
|
|
||||||
def parse_auth(entries, raise_on_error=False):
|
def parse_auth(entries: Dict[str, Any], raise_on_error: bool = False) -> Dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
Parses authentication entries
|
Parses authentication entries
|
||||||
|
|
||||||
|
|
@ -346,11 +351,11 @@ def parse_auth(entries, raise_on_error=False):
|
||||||
return AuthConfig.parse_auth(entries, raise_on_error)
|
return AuthConfig.parse_auth(entries, raise_on_error)
|
||||||
|
|
||||||
|
|
||||||
def load_config(config_path=None, config_dict=None, credstore_env=None):
|
def load_config(config_path: Optional[str] = None, config_dict: Optional[Dict[str, Any]] = None, credstore_env: Optional[Dict[str, Any]] = None) -> AuthConfig:
|
||||||
return AuthConfig.load_config(config_path, config_dict, credstore_env)
|
return AuthConfig.load_config(config_path, config_dict, credstore_env)
|
||||||
|
|
||||||
|
|
||||||
def _load_legacy_config(config_file):
|
def _load_legacy_config(config_file: str) -> Dict[str, Any]:
|
||||||
log.debug("Attempting to parse legacy auth file format")
|
log.debug("Attempting to parse legacy auth file format")
|
||||||
try:
|
try:
|
||||||
data = []
|
data = []
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,7 @@
|
||||||
|
from __future__ import annotations
|
||||||
|
from typing import Any, Dict, NoReturn
|
||||||
|
|
||||||
|
from .types.daemon import CancellableStream
|
||||||
from .api.client import APIClient
|
from .api.client import APIClient
|
||||||
from .constants import (DEFAULT_TIMEOUT_SECONDS, DEFAULT_MAX_POOL_SIZE)
|
from .constants import (DEFAULT_TIMEOUT_SECONDS, DEFAULT_MAX_POOL_SIZE)
|
||||||
from .models.configs import ConfigCollection
|
from .models.configs import ConfigCollection
|
||||||
|
|
@ -41,11 +45,11 @@ class DockerClient:
|
||||||
max_pool_size (int): The maximum number of connections
|
max_pool_size (int): The maximum number of connections
|
||||||
to save in the pool.
|
to save in the pool.
|
||||||
"""
|
"""
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
||||||
self.api = APIClient(*args, **kwargs)
|
self.api = APIClient(*args, **kwargs)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_env(cls, **kwargs):
|
def from_env(cls, **kwargs: Any) -> DockerClient:
|
||||||
"""
|
"""
|
||||||
Return a client configured from environment variables.
|
Return a client configured from environment variables.
|
||||||
|
|
||||||
|
|
@ -103,7 +107,7 @@ class DockerClient:
|
||||||
|
|
||||||
# Resources
|
# Resources
|
||||||
@property
|
@property
|
||||||
def configs(self):
|
def configs(self) -> ConfigCollection:
|
||||||
"""
|
"""
|
||||||
An object for managing configs on the server. See the
|
An object for managing configs on the server. See the
|
||||||
:doc:`configs documentation <configs>` for full details.
|
:doc:`configs documentation <configs>` for full details.
|
||||||
|
|
@ -111,7 +115,7 @@ class DockerClient:
|
||||||
return ConfigCollection(client=self)
|
return ConfigCollection(client=self)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def containers(self):
|
def containers(self) -> ContainerCollection:
|
||||||
"""
|
"""
|
||||||
An object for managing containers on the server. See the
|
An object for managing containers on the server. See the
|
||||||
:doc:`containers documentation <containers>` for full details.
|
:doc:`containers documentation <containers>` for full details.
|
||||||
|
|
@ -119,7 +123,7 @@ class DockerClient:
|
||||||
return ContainerCollection(client=self)
|
return ContainerCollection(client=self)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def images(self):
|
def images(self) -> ImageCollection:
|
||||||
"""
|
"""
|
||||||
An object for managing images on the server. See the
|
An object for managing images on the server. See the
|
||||||
:doc:`images documentation <images>` for full details.
|
:doc:`images documentation <images>` for full details.
|
||||||
|
|
@ -127,7 +131,7 @@ class DockerClient:
|
||||||
return ImageCollection(client=self)
|
return ImageCollection(client=self)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def networks(self):
|
def networks(self) -> NetworkCollection:
|
||||||
"""
|
"""
|
||||||
An object for managing networks on the server. See the
|
An object for managing networks on the server. See the
|
||||||
:doc:`networks documentation <networks>` for full details.
|
:doc:`networks documentation <networks>` for full details.
|
||||||
|
|
@ -135,7 +139,7 @@ class DockerClient:
|
||||||
return NetworkCollection(client=self)
|
return NetworkCollection(client=self)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def nodes(self):
|
def nodes(self) -> NodeCollection:
|
||||||
"""
|
"""
|
||||||
An object for managing nodes on the server. See the
|
An object for managing nodes on the server. See the
|
||||||
:doc:`nodes documentation <nodes>` for full details.
|
:doc:`nodes documentation <nodes>` for full details.
|
||||||
|
|
@ -143,7 +147,7 @@ class DockerClient:
|
||||||
return NodeCollection(client=self)
|
return NodeCollection(client=self)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def plugins(self):
|
def plugins(self) -> PluginCollection:
|
||||||
"""
|
"""
|
||||||
An object for managing plugins on the server. See the
|
An object for managing plugins on the server. See the
|
||||||
:doc:`plugins documentation <plugins>` for full details.
|
:doc:`plugins documentation <plugins>` for full details.
|
||||||
|
|
@ -151,7 +155,7 @@ class DockerClient:
|
||||||
return PluginCollection(client=self)
|
return PluginCollection(client=self)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def secrets(self):
|
def secrets(self) -> SecretCollection:
|
||||||
"""
|
"""
|
||||||
An object for managing secrets on the server. See the
|
An object for managing secrets on the server. See the
|
||||||
:doc:`secrets documentation <secrets>` for full details.
|
:doc:`secrets documentation <secrets>` for full details.
|
||||||
|
|
@ -159,7 +163,7 @@ class DockerClient:
|
||||||
return SecretCollection(client=self)
|
return SecretCollection(client=self)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def services(self):
|
def services(self) -> ServiceCollection:
|
||||||
"""
|
"""
|
||||||
An object for managing services on the server. See the
|
An object for managing services on the server. See the
|
||||||
:doc:`services documentation <services>` for full details.
|
:doc:`services documentation <services>` for full details.
|
||||||
|
|
@ -167,7 +171,7 @@ class DockerClient:
|
||||||
return ServiceCollection(client=self)
|
return ServiceCollection(client=self)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def swarm(self):
|
def swarm(self) -> Swarm:
|
||||||
"""
|
"""
|
||||||
An object for managing a swarm on the server. See the
|
An object for managing a swarm on the server. See the
|
||||||
:doc:`swarm documentation <swarm>` for full details.
|
:doc:`swarm documentation <swarm>` for full details.
|
||||||
|
|
@ -175,7 +179,7 @@ class DockerClient:
|
||||||
return Swarm(client=self)
|
return Swarm(client=self)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def volumes(self):
|
def volumes(self) -> VolumeCollection:
|
||||||
"""
|
"""
|
||||||
An object for managing volumes on the server. See the
|
An object for managing volumes on the server. See the
|
||||||
:doc:`volumes documentation <volumes>` for full details.
|
:doc:`volumes documentation <volumes>` for full details.
|
||||||
|
|
@ -183,35 +187,35 @@ class DockerClient:
|
||||||
return VolumeCollection(client=self)
|
return VolumeCollection(client=self)
|
||||||
|
|
||||||
# Top-level methods
|
# Top-level methods
|
||||||
def events(self, *args, **kwargs):
|
def events(self, *args: Any, **kwargs: Any) -> CancellableStream:
|
||||||
return self.api.events(*args, **kwargs)
|
return self.api.events(*args, **kwargs)
|
||||||
events.__doc__ = APIClient.events.__doc__
|
events.__doc__ = APIClient.events.__doc__
|
||||||
|
|
||||||
def df(self):
|
def df(self) -> Dict[str, Any]:
|
||||||
return self.api.df()
|
return self.api.df()
|
||||||
df.__doc__ = APIClient.df.__doc__
|
df.__doc__ = APIClient.df.__doc__
|
||||||
|
|
||||||
def info(self, *args, **kwargs):
|
def info(self, *args: Any, **kwargs: Any) -> Dict[str, Any]:
|
||||||
return self.api.info(*args, **kwargs)
|
return self.api.info(*args, **kwargs)
|
||||||
info.__doc__ = APIClient.info.__doc__
|
info.__doc__ = APIClient.info.__doc__
|
||||||
|
|
||||||
def login(self, *args, **kwargs):
|
def login(self, *args: Any, **kwargs: Any) -> Dict[str, Any]:
|
||||||
return self.api.login(*args, **kwargs)
|
return self.api.login(*args, **kwargs)
|
||||||
login.__doc__ = APIClient.login.__doc__
|
login.__doc__ = APIClient.login.__doc__
|
||||||
|
|
||||||
def ping(self, *args, **kwargs):
|
def ping(self, *args: Any, **kwargs: Any) -> bool:
|
||||||
return self.api.ping(*args, **kwargs)
|
return self.api.ping(*args, **kwargs)
|
||||||
ping.__doc__ = APIClient.ping.__doc__
|
ping.__doc__ = APIClient.ping.__doc__
|
||||||
|
|
||||||
def version(self, *args, **kwargs):
|
def version(self, *args: Any, **kwargs: Any) -> Dict[str, Any]:
|
||||||
return self.api.version(*args, **kwargs)
|
return self.api.version(*args, **kwargs)
|
||||||
version.__doc__ = APIClient.version.__doc__
|
version.__doc__ = APIClient.version.__doc__
|
||||||
|
|
||||||
def close(self):
|
def close(self) -> None:
|
||||||
return self.api.close()
|
return self.api.close()
|
||||||
close.__doc__ = APIClient.close.__doc__
|
close.__doc__ = APIClient.close.__doc__
|
||||||
|
|
||||||
def __getattr__(self, name):
|
def __getattr__(self, name: str) -> NoReturn:
|
||||||
s = [f"'DockerClient' object has no attribute '{name}'"]
|
s = [f"'DockerClient' object has no attribute '{name}'"]
|
||||||
# If a user calls a method on APIClient, they
|
# If a user calls a method on APIClient, they
|
||||||
if hasattr(APIClient, name):
|
if hasattr(APIClient, name):
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,9 @@
|
||||||
|
from typing import Any, Optional, List, Union
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
|
from .models.containers import Container
|
||||||
|
|
||||||
_image_not_found_explanation_fragments = frozenset(
|
_image_not_found_explanation_fragments = frozenset(
|
||||||
fragment.lower() for fragment in [
|
fragment.lower() for fragment in [
|
||||||
'no such image',
|
'no such image',
|
||||||
|
|
@ -19,11 +23,11 @@ class DockerException(Exception):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
def create_api_error_from_http_exception(e):
|
def create_api_error_from_http_exception(e: requests.HTTPError) -> Union["APIError", "ImageNotFound", "NotFound"]:
|
||||||
"""
|
"""
|
||||||
Create a suitable APIError from requests.exceptions.HTTPError.
|
Create a suitable APIError from requests.exceptions.HTTPError.
|
||||||
"""
|
"""
|
||||||
response = e.response
|
response: requests.Response = e.response
|
||||||
try:
|
try:
|
||||||
explanation = response.json()['message']
|
explanation = response.json()['message']
|
||||||
except ValueError:
|
except ValueError:
|
||||||
|
|
@ -43,14 +47,14 @@ class APIError(requests.exceptions.HTTPError, DockerException):
|
||||||
"""
|
"""
|
||||||
An HTTP error from the API.
|
An HTTP error from the API.
|
||||||
"""
|
"""
|
||||||
def __init__(self, message, response=None, explanation=None):
|
def __init__(self, message: str, response: Optional[requests.Response] = None, explanation: Optional[str] = None) -> None:
|
||||||
# requests 1.2 supports response as a keyword argument, but
|
# requests 1.2 supports response as a keyword argument, but
|
||||||
# requests 1.1 doesn't
|
# requests 1.1 doesn't
|
||||||
super().__init__(message)
|
super().__init__(message)
|
||||||
self.response = response
|
self.response = response
|
||||||
self.explanation = explanation
|
self.explanation = explanation
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self) -> str:
|
||||||
message = super().__str__()
|
message = super().__str__()
|
||||||
|
|
||||||
if self.is_client_error():
|
if self.is_client_error():
|
||||||
|
|
@ -71,19 +75,19 @@ class APIError(requests.exceptions.HTTPError, DockerException):
|
||||||
return message
|
return message
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def status_code(self):
|
def status_code(self) -> Optional[int]:
|
||||||
if self.response is not None:
|
if self.response is not None:
|
||||||
return self.response.status_code
|
return self.response.status_code
|
||||||
|
|
||||||
def is_error(self):
|
def is_error(self) -> bool:
|
||||||
return self.is_client_error() or self.is_server_error()
|
return self.is_client_error() or self.is_server_error()
|
||||||
|
|
||||||
def is_client_error(self):
|
def is_client_error(self) -> bool:
|
||||||
if self.status_code is None:
|
if self.status_code is None:
|
||||||
return False
|
return False
|
||||||
return 400 <= self.status_code < 500
|
return 400 <= self.status_code < 500
|
||||||
|
|
||||||
def is_server_error(self):
|
def is_server_error(self) -> bool:
|
||||||
if self.status_code is None:
|
if self.status_code is None:
|
||||||
return False
|
return False
|
||||||
return 500 <= self.status_code < 600
|
return 500 <= self.status_code < 600
|
||||||
|
|
@ -118,10 +122,10 @@ class DeprecatedMethod(DockerException):
|
||||||
|
|
||||||
|
|
||||||
class TLSParameterError(DockerException):
|
class TLSParameterError(DockerException):
|
||||||
def __init__(self, msg):
|
def __init__(self, msg: str) -> None:
|
||||||
self.msg = msg
|
self.msg = msg
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self) -> str:
|
||||||
return self.msg + (". TLS configurations should map the Docker CLI "
|
return self.msg + (". TLS configurations should map the Docker CLI "
|
||||||
"client configurations. See "
|
"client configurations. See "
|
||||||
"https://docs.docker.com/engine/articles/https/ "
|
"https://docs.docker.com/engine/articles/https/ "
|
||||||
|
|
@ -136,7 +140,7 @@ class ContainerError(DockerException):
|
||||||
"""
|
"""
|
||||||
Represents a container that has exited with a non-zero exit code.
|
Represents a container that has exited with a non-zero exit code.
|
||||||
"""
|
"""
|
||||||
def __init__(self, container, exit_status, command, image, stderr):
|
def __init__(self, container: Container, exit_status: int, command: Union[str, List[str]], image: str, stderr: Optional[str]) -> None:
|
||||||
self.container = container
|
self.container = container
|
||||||
self.exit_status = exit_status
|
self.exit_status = exit_status
|
||||||
self.command = command
|
self.command = command
|
||||||
|
|
@ -151,7 +155,7 @@ class ContainerError(DockerException):
|
||||||
|
|
||||||
|
|
||||||
class StreamParseError(RuntimeError):
|
class StreamParseError(RuntimeError):
|
||||||
def __init__(self, reason):
|
def __init__(self, reason: Any) -> None:
|
||||||
self.msg = reason
|
self.msg = reason
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -178,32 +182,32 @@ def create_unexpected_kwargs_error(name, kwargs):
|
||||||
|
|
||||||
|
|
||||||
class MissingContextParameter(DockerException):
|
class MissingContextParameter(DockerException):
|
||||||
def __init__(self, param):
|
def __init__(self, param: str) -> None:
|
||||||
self.param = param
|
self.param = param
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self) -> str:
|
||||||
return (f"missing parameter: {self.param}")
|
return (f"missing parameter: {self.param}")
|
||||||
|
|
||||||
|
|
||||||
class ContextAlreadyExists(DockerException):
|
class ContextAlreadyExists(DockerException):
|
||||||
def __init__(self, name):
|
def __init__(self, name: str) -> None:
|
||||||
self.name = name
|
self.name = name
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self) -> str:
|
||||||
return (f"context {self.name} already exists")
|
return (f"context {self.name} already exists")
|
||||||
|
|
||||||
|
|
||||||
class ContextException(DockerException):
|
class ContextException(DockerException):
|
||||||
def __init__(self, msg):
|
def __init__(self, msg: str) -> None:
|
||||||
self.msg = msg
|
self.msg = msg
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self) -> str:
|
||||||
return (self.msg)
|
return (self.msg)
|
||||||
|
|
||||||
|
|
||||||
class ContextNotFound(DockerException):
|
class ContextNotFound(DockerException):
|
||||||
def __init__(self, name):
|
def __init__(self, name: str) -> None:
|
||||||
self.name = name
|
self.name = name
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self) -> str:
|
||||||
return (f"context '{self.name}' not found")
|
return (f"context '{self.name}' not found")
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
import os
|
import os
|
||||||
import ssl
|
import ssl
|
||||||
|
from typing import Tuple, Optional, Union
|
||||||
|
|
||||||
from . import errors
|
from . import errors
|
||||||
|
from .api.client import APIClient
|
||||||
from .transport import SSLHTTPAdapter
|
from .transport import SSLHTTPAdapter
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -26,9 +28,9 @@ class TLSConfig:
|
||||||
verify = None
|
verify = None
|
||||||
ssl_version = None
|
ssl_version = None
|
||||||
|
|
||||||
def __init__(self, client_cert=None, ca_cert=None, verify=None,
|
def __init__(self, client_cert: Optional[Tuple[str, str]] = None, ca_cert: Optional[str] = None, verify: Optional[Union[bool, str]] = None,
|
||||||
ssl_version=None, assert_hostname=None,
|
ssl_version: Optional[int] = None, assert_hostname: Optional[bool] = None,
|
||||||
assert_fingerprint=None):
|
assert_fingerprint: Optional[bool] = None) -> None:
|
||||||
# Argument compatibility/mapping with
|
# Argument compatibility/mapping with
|
||||||
# https://docs.docker.com/engine/articles/https/
|
# https://docs.docker.com/engine/articles/https/
|
||||||
# This diverges from the Docker CLI in that users can specify 'tls'
|
# This diverges from the Docker CLI in that users can specify 'tls'
|
||||||
|
|
@ -73,7 +75,7 @@ class TLSConfig:
|
||||||
'Invalid CA certificate provided for `ca_cert`.'
|
'Invalid CA certificate provided for `ca_cert`.'
|
||||||
)
|
)
|
||||||
|
|
||||||
def configure_client(self, client):
|
def configure_client(self, client: APIClient) -> None:
|
||||||
"""
|
"""
|
||||||
Configure a client with these TLS options.
|
Configure a client with these TLS options.
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue