Skip to content

Commit

Permalink
feat!: Drop support for python 3.5
Browse files Browse the repository at this point in the history
Closes: SDK-1889
  • Loading branch information
lukaszsocha2 committed Jan 3, 2022
1 parent e010bcd commit 2ac1ff1
Show file tree
Hide file tree
Showing 78 changed files with 368 additions and 468 deletions.
8 changes: 3 additions & 5 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,10 @@ before_cache:

matrix:
include:
- python: 3.5
- python: 3.6
env: TOX_ENV=pycodestyle
- python: 3.5
- python: 3.6
env: TOX_ENV=pylint
- python: 3.5
env: TOX_ENV=py35
- python: 3.6
env: TOX_ENV=py36
- python: 3.7
Expand All @@ -30,7 +28,7 @@ matrix:
sudo: true
- python: pypy
env: TOX_ENV=pypy PYPY_VERSION='3.6-7.3.0'
- python: 3.5
- python: 3.6
env: TOX_ENV=coverage

# commands to install dependencies
Expand Down
4 changes: 0 additions & 4 deletions .travis/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,6 @@ if [[ "$(uname -s)" == 'Darwin' ]]; then
fi

case "${TOX_ENV}" in
py35)
pyenv install 3.5.0
pyenv global 3.5.0
;;
py36)
pyenv install 3.6.0
pyenv global 3.6.0
Expand Down
15 changes: 7 additions & 8 deletions boxsdk/auth/jwt_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ def _normalize_user_id(cls, user: Any) -> Optional[str]:
return user.object_id
if isinstance(user, str):
return str(user)
raise TypeError("Got unsupported type {0!r} for user.".format(user.__class__.__name__))
raise TypeError(f"Got unsupported type {user.__class__.__name__!r} for user.")

def authenticate_instance(self, enterprise: Optional[str] = None) -> str:
"""
Expand All @@ -340,8 +340,8 @@ def authenticate_instance(self, enterprise: Optional[str] = None) -> str:
raise ValueError("authenticate_instance: Requires the enterprise ID, but it was not provided.")
if all(enterprises) and (enterprise != self._enterprise_id):
raise ValueError(
"authenticate_instance: Given enterprise ID {given_enterprise!r}, but {auth} already has ID {existing_enterprise!r}"
.format(auth=self, given_enterprise=enterprise, existing_enterprise=self._enterprise_id)
f"authenticate_instance: Given enterprise ID {enterprise!r}, "
f"but {self} already has ID {self._enterprise_id!r}"
)
if not self._enterprise_id:
self._enterprise_id = enterprise
Expand Down Expand Up @@ -396,8 +396,7 @@ def _normalize_rsa_private_key(
'rsa_private_key_data must be binary data (bytes/str), '
'a file-like object with a read() method, '
'or an instance of RSAPrivateKey, '
'but got {0!r}'
.format(data.__class__.__name__)
f'but got {data.__class__.__name__!r}'
)

@staticmethod
Expand All @@ -412,8 +411,8 @@ def _normalize_rsa_private_key_passphrase(passphrase: Any):

if not isinstance(passphrase, (bytes, type(None))):
raise TypeError(
"rsa_private_key_passphrase must contain binary data (bytes/str), got {0!r}"
.format(passphrase.__class__.__name__)
f"rsa_private_key_passphrase must contain binary data (bytes/str), "
f"got {passphrase.__class__.__name__!r}"
)
return passphrase

Expand Down Expand Up @@ -448,6 +447,6 @@ def from_settings_file(cls, settings_file_sys_path: str, **kwargs: Any) -> 'JWTA
:param settings_file_sys_path: Path to the JSON file containing the configuration.
:return: Auth instance configured as specified by the JSON file.
"""
with open(settings_file_sys_path) as config_file:
with open(settings_file_sys_path, encoding='utf-8') as config_file:
config_dictionary = json.load(config_file)
return cls.from_settings_dictionary(config_dictionary, **kwargs)
9 changes: 5 additions & 4 deletions boxsdk/auth/oauth2.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import random
import string # pylint:disable=deprecated-module
from threading import Lock
from typing import Optional, Callable, ContextManager, Tuple, TYPE_CHECKING, Any
from typing import Optional, Callable, ContextManager, Tuple, TYPE_CHECKING, Any, Union
from urllib.parse import urlunsplit, urlencode

from ..config import API
Expand All @@ -17,6 +17,7 @@

if TYPE_CHECKING:
from boxsdk.session.box_response import BoxResponse
from boxsdk import NetworkResponse


class TokenScope(TextEnum):
Expand Down Expand Up @@ -281,7 +282,7 @@ def _execute_token_request(
The response for the token request.
"""
self._check_closed()
url = '{base_auth_url}/token'.format(base_auth_url=self._api_config.OAUTH2_API_URL)
url = f'{self._api_config.OAUTH2_API_URL}/token'
headers = {'content-type': 'application/x-www-form-urlencoded'}
try:
network_response = self._session.request(
Expand All @@ -307,7 +308,7 @@ def _execute_token_request(
return token_response

@staticmethod
def _oauth_exception(network_response: 'BoxResponse', url: str) -> BoxOAuthException:
def _oauth_exception(network_response: Union['NetworkResponse', 'BoxResponse'], url: str) -> BoxOAuthException:
"""
Create a BoxOAuthException instance to raise. If the error response is JSON, parse it and include the
code and message in the exception.
Expand Down Expand Up @@ -361,7 +362,7 @@ def revoke(self) -> None:
token_to_revoke = access_token or refresh_token
if token_to_revoke is None:
return
url = '{base_auth_url}/revoke'.format(base_auth_url=self._api_config.OAUTH2_API_URL)
url = f'{self._api_config.OAUTH2_API_URL}/revoke'
try:
network_response = self._session.request(
'POST',
Expand Down
2 changes: 1 addition & 1 deletion boxsdk/auth/redis_managed_oauth2.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def __init__(self, unique_id: str = uuid4(), redis_server: Redis = None, *args:
# pylint:disable=keyword-arg-before-vararg
self._unique_id = unique_id
self._redis_server = redis_server or StrictRedis()
refresh_lock = Lock(redis=self._redis_server, name='{0}_lock'.format(self._unique_id))
refresh_lock = Lock(redis=self._redis_server, name=f'{self._unique_id}_lock')
super().__init__(*args, refresh_lock=refresh_lock, **kwargs)
if self._access_token is None:
self._get_and_update_current_tokens()
Expand Down
2 changes: 1 addition & 1 deletion boxsdk/client/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -1195,7 +1195,7 @@ def downscope_token(
:return:
The response for the downscope token request.
"""
url = '{base_auth_url}/token'.format(base_auth_url=self._session.api_config.OAUTH2_API_URL)
url = f'{self._session.api_config.OAUTH2_API_URL}/token'
access_token = self.auth.access_token or self.auth.refresh(None)
data = {
'subject_token': access_token,
Expand Down
10 changes: 3 additions & 7 deletions boxsdk/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,9 @@ class API:
class Client:
"""Configuration object containing the user agent string."""
VERSION = version.__version__
USER_AGENT_STRING = 'box-python-sdk-{0}'.format(VERSION)
BOX_UA_STRING = 'agent=box-python-sdk/{0}; env=python/{1}.{2}.{3}'.format(
VERSION,
py_version.major,
py_version.minor,
py_version.micro,
)
USER_AGENT_STRING = f'box-python-sdk-{VERSION}'
BOX_UA_STRING = f'agent=box-python-sdk/{VERSION}; ' \
f'env=python/{py_version.major}.{py_version.minor}.{py_version.micro}'


class Proxy:
Expand Down
74 changes: 20 additions & 54 deletions boxsdk/exception.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# coding: utf-8
from typing import Optional

import attr

Expand All @@ -11,10 +12,10 @@ class BoxException(Exception):
Base class exception for all errors raised from the SDK.
"""
def __str__(self):
return '{}'.format(self.__class__.__name__)
return self.__class__.__name__

def __repr__(self):
return '<{}>'.format(self.__class__.__name__)
return f'<{self.__class__.__name__}>'


class BoxValueError(ValueError):
Expand All @@ -36,50 +37,32 @@ class BoxAPIException(BoxException):
:param status:
HTTP status code of the failed response
:type status:
`int`
:param code:
The 'code' field of the failed response
:type code:
`unicode` or None
:param message:
A message to associate with the exception, e.g. 'message' field of the json in the failed response
:type message:
`unicode` or None
:param request_id:
The 'request_id' field of the json in the failed response
:type request_id:
`unicode` or None
:param headers:
The HTTP headers in the failed response
:type headers:
`dict`
:param url:
The url which raised the exception
:type url:
`unicode`
:param method:
The HTTP verb used to make the request.
:type method:
`unicode`
:param context_info:
The context_info returned in the failed response.
:type context_info:
`dict` or None
:param network_response:
The failed response
:type network_response:
Requests `Response`
"""
status = attr.ib()
code = attr.ib(default=None)
message = attr.ib(default=None)
request_id = attr.ib(default=None)
headers = attr.ib(default=None, hash=False)
url = attr.ib(default=None)
method = attr.ib(default=None)
context_info = attr.ib(default=None)
network_response = attr.ib(default=None, repr=False)
status: int = attr.ib()
code: Optional[str] = attr.ib(default=None)
message: Optional[str] = attr.ib(default=None)
request_id: Optional[str] = attr.ib(default=None)
headers: dict = attr.ib(default=None, hash=False)
url: str = attr.ib(default=None)
method: str = attr.ib(default=None)
context_info: Optional[dict] = attr.ib(default=None)
network_response: 'NetworkResponse' = attr.ib(default=None, repr=False)

def __str__(self):
return '\n'.join((
Expand All @@ -101,35 +84,23 @@ class BoxOAuthException(BoxException):
:param status:
HTTP status code of the auth response
:type status:
`int`
:param message:
A message to associate with the exception, e.g. HTTP content of the auth response
:type message:
`unicode`
:param url:
The url which raised the exception
:type url:
`unicode`
:param method:
The HTTP verb used to make the request.
:type method:
`unicode`
:param network_response:
The network response for the request.
:type network_response:
:class:`NetworkResponse`
:param code:
The 'code' field of the failed response
:type code:
`unicode` or None
"""
status = attr.ib()
message = attr.ib(default=None)
url = attr.ib(default=None)
method = attr.ib(default=None)
network_response = attr.ib(default=None, repr=False, type=NetworkResponse)
code = attr.ib(default=None)
status: int = attr.ib()
message: str = attr.ib(default=None)
url: str = attr.ib(default=None)
method: str = attr.ib(default=None)
network_response: NetworkResponse = attr.ib(default=None, repr=False)
code: Optional[str] = attr.ib(default=None)

def __str__(self):
# pylint:disable=no-member
Expand All @@ -138,13 +109,8 @@ def __str__(self):
# pylint:enable=no-member
else:
headers = 'N/A'
return '\nMessage: {0}\nStatus: {1}\nURL: {2}\nMethod: {3}\nHeaders: {4}'.format(
self.message,
self.status,
self.url,
self.method,
headers,
)
return f'\nMessage: {self.message}\nStatus: {self.status}\nURL: {self.url}\nMethod: {self.method}' \
f'\nHeaders: {headers}'


__all__ = list(map(str, ['BoxException', 'BoxAPIException', 'BoxOAuthException', 'BoxNetworkException']))
11 changes: 4 additions & 7 deletions boxsdk/network/default_network.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,8 @@ class DefaultNetworkResponse(NetworkResponse):
"""

_COMMON_RESPONSE_FORMAT = '"%(method)s %(url)s" %(status_code)s %(content_length)s\n%(headers)s\n%(content)s\n'
SUCCESSFUL_RESPONSE_FORMAT = '\x1b[32m{0}\x1b[0m'.format(_COMMON_RESPONSE_FORMAT)
ERROR_RESPONSE_FORMAT = '\x1b[31m{0}\x1b[0m'.format(_COMMON_RESPONSE_FORMAT)
SUCCESSFUL_RESPONSE_FORMAT = f'\x1b[32m{_COMMON_RESPONSE_FORMAT}\x1b[0m'
ERROR_RESPONSE_FORMAT = f'\x1b[31m{_COMMON_RESPONSE_FORMAT}\x1b[0m'
STREAM_CONTENT_NOT_LOGGED = '<File download contents unavailable for logging>'

def __init__(self, request_response: 'Response', access_token_used: str):
Expand Down Expand Up @@ -258,8 +258,5 @@ def log(self, can_safely_log_content: bool = False) -> None:
)

def __repr__(self) -> str:
return '<Box Network Response ({method} {url} {status_code})>'.format(
method=self._request_response.request.method,
url=self._request_response.request.url,
status_code=self.status_code,
)
return f'<Box Network Response ({self._request_response.request.method} {self._request_response.request.url} ' \
f'{self.status_code})>'
4 changes: 2 additions & 2 deletions boxsdk/object/base_api_json_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,8 @@ def __iter__(self) -> Iterator:

def __repr__(self) -> str:
"""Base class override. Return a human-readable representation using the Box ID or name of the object."""
extra_description = ' - {0}'.format(self._description) if self._description else ''
description = '<Box {0}{1}>'.format(self.__class__.__name__, extra_description)
extra_description = f' - {self._description}' if self._description else ''
description = f'<Box {self.__class__.__name__}{extra_description}>'
return description

@property
Expand Down
8 changes: 4 additions & 4 deletions boxsdk/object/base_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,22 +32,22 @@ def _description(self) -> str:
Base class override. Return a description for the object.
"""
if 'name' in self._response_object:
return '{0} ({1})'.format(self._object_id, self.name) # pylint:disable=no-member
return '{0}'.format(self._object_id)
return f'{self._object_id} ({self.name})' # pylint:disable=no-member
return self._object_id

def get_url(self, *args: Any) -> str:
"""
Base class override.
Return the given object's URL, appending any optional parts as specified by args.
"""
# pylint:disable=arguments-differ
return super().get_url('{0}s'.format(self._item_type), self._object_id, *args)
return super().get_url(f'{self._item_type}s', self._object_id, *args)

def get_type_url(self) -> str:
"""
Return the URL for type of the given resource.
"""
return super().get_url('{0}s'.format(self._item_type))
return super().get_url(f'{self._item_type}s')

@property
def object_id(self) -> str:
Expand Down
Loading

0 comments on commit 2ac1ff1

Please sign in to comment.