Skip to content

Commit 08e1de9

Browse files
committed
drop support for python < 3.6
1 parent 135cc84 commit 08e1de9

26 files changed

+63
-67
lines changed

.travis.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
language: python
22
python:
3-
- 2.7
4-
- 3.5
53
- 3.6
4+
- 3.7
65
install:
76
- pip install -U pip setuptools
87
- pip install -e .[testing]

backslash/api.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,10 @@
4444
_MAX_PARAMS_UNCOMPRESSED_SIZE = 10 * 1024 * 1024 # 10Mb
4545

4646

47-
class API(object):
47+
class API():
4848

4949
def __init__(self, client, url, runtoken, timeout_seconds=60, headers=None):
50-
super(API, self).__init__()
50+
super().__init__()
5151
self.client = client
5252
self.url = URL(url)
5353
self.runtoken = runtoken
@@ -177,10 +177,10 @@ def _compress(self, data):
177177
return s.getvalue()
178178

179179

180-
class CallProxy(object):
180+
class CallProxy():
181181

182182
def __init__(self, api):
183-
super(CallProxy, self).__init__()
183+
super().__init__()
184184
self._api = api
185185

186186
def __getattr__(self, attr):

backslash/api_object.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11

2-
class APIObject(object):
2+
class APIObject():
33

44
def __init__(self, client, json_data):
5-
super(APIObject, self).__init__()
5+
super().__init__()
66
self.client = client
77
self._data = json_data
88

@@ -38,7 +38,7 @@ def _fetch(self):
3838
return self.client.api.get(self.api_path, raw=True)[self._data['type']]
3939

4040
def __repr__(self):
41-
return '<API:{data[type]}:{data[id]}>'.format(data=self._data)
41+
return f'<API:{self._data[type]}:{self._data[id]}>'
4242

4343
def without_fields(self, field_names):
4444
new_data = dict((field_name, field_value)

backslash/archiveable.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
class Archiveable(object):
1+
class Archiveable():
22

33
def toggle_archived(self):
44
self.client.api.call_function('toggle_archived', {self._get_id_key(): self.id})

backslash/client.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@
1212
_logger = logbook.Logger(__name__)
1313

1414

15-
class Backslash(object):
15+
class Backslash():
1616

1717
def __init__(self, url, runtoken, headers=None):
18-
super(Backslash, self).__init__()
18+
super().__init__()
1919
if not url.startswith('http'):
20-
url = 'http://{0}'.format(url)
20+
url = f'http://{url}'
2121
self._url = URL(url)
2222
self.api = API(self, url, runtoken, headers=headers)
2323

@@ -33,7 +33,7 @@ def get_ui_url(self, fragment=None):
3333
fragment = '/'
3434
elif not fragment.startswith('/'):
3535
fragment = '/' + fragment
36-
returned += '#{}'.format(fragment)
36+
returned += f'#{fragment}'
3737
return returned
3838

3939

backslash/commentable.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
from .lazy_query import LazyQuery
22

33

4-
class Commentable(object):
4+
class Commentable():
55

66
def post_comment(self, comment):
77
return self.client.api.call_function('post_comment', {
88
'comment': comment,
9-
'{}_id'.format(self.type): self.id
9+
f'{self.type}_id': self.id
1010
})
1111

1212
def get_comments(self):
13-
return LazyQuery(self.client, '/rest/comments', query_params={'{}_id'.format(self.type): self.id})
13+
return LazyQuery(self.client, '/rest/comments', query_params={f'{self.type}_id': self.id})

backslash/compatibility.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
class Compatibility(object):
1+
class Compatibility():
22

33
def __init__(self, client):
4-
super(Compatibility, self).__init__()
4+
super().__init__()
55
self.client = client

backslash/contrib/keepalive_thread.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
class KeepaliveThread(threading.Thread):
99

1010
def __init__(self, client, session, interval, error_callback=None):
11-
super(KeepaliveThread, self).__init__()
11+
super().__init__()
1212
self._client = client
1313
self._session = session
1414
self._interval = interval / 2.0

backslash/contrib/slash_plugin.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ class BackslashPlugin(PluginInterface):
6868

6969
def __init__(self, url=None, keepalive_interval=None, runtoken=None,
7070
propagate_exceptions=False, config_filename=_DEFAULT_CONFIG_FILENAME):
71-
super(BackslashPlugin, self).__init__()
71+
super().__init__()
7272
self._url = url
7373
self._repo_cache = {}
7474
self._config_filename = config_filename
@@ -98,7 +98,7 @@ def session_webapp_url(self):
9898
session = slash.context.session
9999
if session is None or self.client is None:
100100
return None
101-
return self.client.get_ui_url('sessions/{}'.format(session.id))
101+
return self.client.get_ui_url(f'sessions/{session.id}')
102102

103103
def _handle_exception(self, exc_info):
104104
pass
@@ -144,7 +144,7 @@ def _get_default_headers(self):
144144
def deactivate(self):
145145
if self._keepalive_thread is not None:
146146
self._keepalive_thread.stop()
147-
super(BackslashPlugin, self).deactivate()
147+
super().deactivate()
148148

149149
def _notify_session_start(self):
150150
metadata = self._get_initial_session_metadata()
@@ -298,7 +298,7 @@ def test_skip(self, reason=None):
298298
@slash.plugins.registers_on(None)
299299
def is_session_exist(self, session_id):
300300
try:
301-
self.client.api.get('/rest/sessions/{0}'.format(session_id))
301+
self.client.api.get(f'/rest/sessions/{session_id}')
302302
return True
303303
except HTTPError as e:
304304
if e.response.status_code == 404:
@@ -392,10 +392,10 @@ def _calculate_file_hash(self, filename):
392392
data = f.read()
393393
h = hashlib.sha1()
394394
h.update('blob '.encode('utf-8'))
395-
h.update('{0}\0'.format(len(data)).encode('utf-8'))
395+
h.update(f'{len(data)}\0'.encode('utf-8'))
396396
h.update(data)
397397
except IOError as e:
398-
_logger.debug('Ignoring IOError {0!r} when calculating file hash for {1}', e, filename)
398+
_logger.debug(f'Ignoring IOError {e!r} when calculating file hash for {filename}')
399399
returned = None
400400
else:
401401
returned = h.hexdigest()
@@ -452,7 +452,7 @@ def _session_report_end(self, hook_name):
452452
self.session.report_end(**kwargs)
453453
self._started = False
454454
except Exception: # pylint: disable=broad-except
455-
_logger.error('Exception ignored in {}'.format(hook_name), exc_info=True)
455+
_logger.error(f'Exception ignored in {hook_name}', exc_info=True)
456456

457457
@handle_exceptions
458458
def error_added(self, result, error):
@@ -588,7 +588,7 @@ def fetch_token(self, username, password):
588588
headers={'Content-type': 'application/json'})\
589589
.raise_for_status()
590590

591-
s.post(URL(self._get_backslash_url()).add_path('/runtoken/request/{}/complete'.format(request_id)))\
591+
s.post(URL(self._get_backslash_url()).add_path(f'/runtoken/request/{request_id}/complete'))\
592592
.raise_for_status()
593593

594594
resp = s.get(response_url)

backslash/contrib/utils.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ def _unwrap_object_variable(var_name, var_value):
103103
return
104104

105105
for attr, value in _iter_distilled_object_attributes(var_value):
106-
yield 'self.{}'.format(attr), value
106+
yield f'self.{attr}', value
107107

108108
def _iter_distilled_object_attributes(obj):
109109
try:
@@ -162,12 +162,12 @@ def _nested_assign(dictionary, key, value):
162162

163163
def _safe_repr(value, repr_blacklisted_types, truncate=True):
164164
if isinstance(value, repr_blacklisted_types):
165-
returned = "<{!r} object {:x}>".format(type(value).__name__, id(value))
165+
returned = f"<{type(value).__name__!r} object {id(value):x}>"
166166

167167
try:
168168
returned = repr(value)
169169
except Exception: # pylint: disable=broad-except
170-
return "[Unprintable {0!r} object]".format(type(value).__name__)
170+
return f"[Unprintable {type(value).__name__!r} object]"
171171

172172
if truncate and len(returned) > _MAX_VARIABLE_VALUE_LENGTH:
173173
returned = returned[:_MAX_VARIABLE_VALUE_LENGTH - 3] + '...'

backslash/error_container.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
_logger = logbook.Logger(__name__)
1212

1313

14-
class ErrorContainer(object):
14+
class ErrorContainer():
1515

1616
def add_error(self, message, exception_type=NOTHING, traceback=NOTHING,
1717
timestamp=NOTHING, is_failure=NOTHING, exception_attrs=NOTHING, is_interruption=NOTHING, is_fatal=NOTHING):

backslash/field_filters.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,28 @@
1-
class FieldFilter(object):
1+
class FieldFilter():
22

33
def __init__(self, field_name):
4-
super(FieldFilter, self).__init__()
4+
super().__init__()
55
self.field_name = field_name
66
self._filters = []
77

88
def add_to_url(self, url):
99
for operator_name, value in self._filters:
10-
url = url.add_query_param(self.field_name, '{0}:{1}'.format(operator_name, value))
10+
url = url.add_query_param(self.field_name, f'{operator_name}:{value}')
1111
return url
1212

1313
def _add_field_proxy_operator_method(operator_name):
1414

1515
def method(self, other):
1616
self._filters.append((operator_name, other)) # pylint: disable=protected-access
1717
return self
18-
method_name = method.__name__ = '__{0}__'.format(operator_name)
18+
method_name = method.__name__ = f'__{operator_name}__'
1919
setattr(FieldFilter, method_name, method)
2020

2121
for _operator_name in ['eq', 'ne', 'lt', 'le', 'gt', 'ge']:
2222
_add_field_proxy_operator_method(_operator_name)
2323

2424

25-
class _Fields(object):
25+
class _Fields():
2626

2727
def __getattr__(self, name):
2828
return FieldFilter(name)

backslash/lazy_query.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@
77
from .utils import raise_for_status
88

99

10-
class LazyQuery(object):
10+
class LazyQuery():
1111

1212
def __init__(self, client, path=None, url=None, query_params=None, page_size=100):
13-
super(LazyQuery, self).__init__()
13+
super().__init__()
1414
self._client = client
1515
if url is None:
1616
url = client.api.url
@@ -37,7 +37,7 @@ def filter(self, *filter_objects, **fields):
3737
return LazyQuery(self._client, url=returned_url, page_size=self._page_size)
3838

3939
def __repr__(self):
40-
return '<Query {0!r}>'.format(str(self._url))
40+
return f'<Query {str(self._url)!r}>'
4141

4242
def __iter__(self):
4343
for i in itertools.count():
@@ -77,7 +77,7 @@ def _fetch_page(self, page_index):
7777
raise RuntimeError('Multiple keys returned')
7878
[obj_typename] = keys
7979
if self._typename is not None and obj_typename != self._typename:
80-
raise RuntimeError('Got different typename in query: {!r} != {!r}'.format(obj_typename, self._typename))
80+
raise RuntimeError(f'Got different typename in query: {obj_typename!r} != {self._typename!r}')
8181
self._typename = obj_typename
8282

8383
for index, json_obj in enumerate(response_data[self._typename]):

backslash/metadata_holder.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
class MetadataHolder(object):
1+
class MetadataHolder():
22

33
def set_metadata(self, key, value):
44
self.client.api.call_function('set_metadata', {

backslash/related_entity_container.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
class RelatedEntityContainer(object):
1+
class RelatedEntityContainer():
22

33
def add_related_entity(self, entity_type, entity_name):
44
# pylint: disable=no-member

backslash/session.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class Session(APIObject, MetadataHolder, ErrorContainer, WarningContainer, Archi
1717

1818
@property
1919
def ui_url(self):
20-
return self.client.get_ui_url('/sessions/{}'.format(self.logical_id or self.id))
20+
return self.client.get_ui_url(f'/sessions/{self.logical_id or self.id}')
2121

2222
def report_end(self, duration=NOTHING, has_fatal_errors=NOTHING):
2323

@@ -100,7 +100,7 @@ def query_tests(self, include_planned=False):
100100
params = None
101101
if include_planned:
102102
params = {'show_planned':'true'}
103-
return LazyQuery(self.client, '/rest/sessions/{0}/tests'.format(self.id), query_params=params)
103+
return LazyQuery(self.client, f'/rest/sessions/{self.id}/tests', query_params=params)
104104

105105
def query_errors(self):
106106
"""Queries tests of the current session

backslash/test.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ class Test(APIObject, MetadataHolder, ErrorContainer, WarningContainer, Commenta
1414

1515
@property
1616
def ui_url(self):
17-
return self.client.get_ui_url('sessions/{}/tests/{}'.format(self.session_display_id, self.logical_id or self.id))
17+
return self.client.get_ui_url(f'sessions/{self.session_display_id}/tests/{self.logical_id or self.id}')
1818

1919
def report_end(self, duration=NOTHING):
2020
self.client.api.call_function('report_test_end', {'id': self.id, 'duration': duration})
@@ -33,7 +33,7 @@ def query_errors(self):
3333
return LazyQuery(self.client, '/rest/errors', query_params={'test_id': self.id})
3434

3535
def get_session(self):
36-
return self.client.api.get('/rest/sessions/{0}'.format(self.session_id))
36+
return self.client.api.get(f'/rest/sessions/{self.session_id}')
3737

3838
def get_parent(self):
3939
return self.get_session()

backslash/timing_container.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
class TimingContainer(object):
1+
class TimingContainer():
22

33
def report_timing_start(self, name):
44
self._report('start', name)
@@ -9,7 +9,7 @@ def report_timing_end(self, name):
99
def _report(self, start_stop, name):
1010
kwargs = {'name': name}
1111
kwargs.update(self._get_identity_kwargs())
12-
self.client.api.call_function('report_timing_{}'.format(start_stop), kwargs) # pylint: disable=no-member
12+
self.client.api.call_function(f'report_timing_{start_stop}', kwargs) # pylint: disable=no-member
1313

1414
def _get_identity_kwargs(self):
1515
if self.type.lower() == 'session': # pylint: disable=no-member

backslash/utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,5 @@ def raise_for_status(resp):
3333
resp.raise_for_status()
3434
except HTTPError as e:
3535
raise HTTPError(
36-
'{0.request.method} {0.request.url}: {0.status_code}\n\n{0.content}'.format(e.response),
36+
f'{e.response.request.method} {e.response.request.url}: {e.response.status_code}\n\n{e.response.content}',
3737
response=resp, request=resp.request)

backslash/warning_container.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from .lazy_query import LazyQuery
55

66

7-
class WarningContainer(object):
7+
class WarningContainer():
88

99
def add_warning(self, message, filename=NOTHING, lineno=NOTHING, timestamp=NOTHING):
1010
return self.client.api.call_function('add_warning', {self._get_id_key(): self.id,

docs/changelog.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
Changelog
22
=========
33

4+
* :feature:`104` Drop support for python version < 3.6
45
* :release:`2.39.0 <03-07-2019>`
56
* :feature:`101` Report if error is fatal
67
* :feature:`91` Allow passing custom default headers to server

setup.cfg

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
[metadata]
22
name = backslash
33
classifiers =
4-
Programming Language :: Python :: 2.7
5-
Programming Language :: Python :: 3.5
64
Programming Language :: Python :: 3.6
5+
Programming Language :: Python :: 3.7
76
description = Client library for the Backslash test reporting service
87
license = BSD
98
author = Rotem Yaari
@@ -16,12 +15,9 @@ testing =
1615
slash>=1.5.0
1716
Flask
1817
Flask-Loopback
19-
pylint~=1.9.0; python_version<'3.0'
20-
pylint~=2.2.0; python_version>='3.0'
21-
pytest; python_version < '3.0'
22-
pytest>4.0; python_version >= '3.0'
23-
pytest-cov<2.6; python_version < '3.0'
24-
pytest-cov>=2.6; python_version >= '3.0'
18+
pylint~=2.2.0
19+
pytest>4.0
20+
pytest-cov>=2.6
2521
URLObject
2622
weber-utils
2723

0 commit comments

Comments
 (0)