Skip to content

Commit e6e5ef2

Browse files
hugovkBeyondEvil
authored andcommitted
Drop support for legacy Python 2.7 (#230)
* Drop support for legacy Python 2.7 * Upgrade Python syntax with pyupgrade --py36-plus * Require pytest 5+, supports only Python 3 * Format with Black
1 parent 1abfe5d commit e6e5ef2

File tree

7 files changed

+127
-226
lines changed

7 files changed

+127
-226
lines changed

.travis.yml

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,6 @@ jobs:
1717
directories:
1818
- $HOME/.cache/pre-commit
1919

20-
-
21-
python: 2.7
22-
env: TOXENV=py27
23-
24-
-
25-
python: 2.7
26-
env: TOXENV=py27-ansi2html
27-
28-
-
2920
python: 3.6
3021
env: TOXENV=py36
3122

@@ -45,14 +36,6 @@ jobs:
4536
sudo: required
4637
env: TOXENV=py37-ansi2html
4738

48-
-
49-
python: pypy
50-
env: TOXENV=pypy
51-
52-
-
53-
python: pypy
54-
env: TOXENV=pypy-ansi2html
55-
5639
-
5740
python: pypy3
5841
env: TOXENV=pypy3

README.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ Requirements
2828

2929
You will need the following prerequisites in order to use pytest-html:
3030

31-
- Python 2.7, 3.6, PyPy, or PyPy3
31+
- Python 3.6+ or PyPy3
3232

3333
Installation
3434
------------

appveyor.yml

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,7 @@ environment:
99
- TOXENV: py36-pytest29
1010
PYTHON_HOME: C:\Python36
1111
- TOXENV: flake8
12-
PYTHON_HOME: C:\Python27
13-
- TOXENV: py27-pytest30
14-
PYTHON_HOME: C:\Python27
15-
- TOXENV: py27-pytest29
16-
PYTHON_HOME: C:\Python27
12+
PYTHON_HOME: C:\Python37
1713
install:
1814
- '%PYTHON_HOME%\Scripts\pip --version'
1915
- '%PYTHON_HOME%\Scripts\pip install tox'

pytest_html/plugin.py

Lines changed: 27 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,20 @@
22
# License, v. 2.0. If a copy of the MPL was not distributed with this
33
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
44

5-
from __future__ import absolute_import
6-
75
from base64 import b64encode, b64decode
86
from collections import OrderedDict
97
from os.path import isfile
108
import datetime
119
import json
1210
import os
1311
import pkg_resources
14-
import sys
1512
import time
1613
import bisect
1714
import warnings
1815
import re
1916

17+
from html import escape
18+
2019
try:
2120
from ansi2html import Ansi2HTMLConverter, style
2221

@@ -30,16 +29,6 @@
3029
from . import extras
3130
from . import __version__, __pypi_url__
3231

33-
PY3 = sys.version_info[0] == 3
34-
35-
# Python 2.X and 3.X compatibility
36-
if PY3:
37-
basestring = str
38-
from html import escape
39-
else:
40-
from codecs import open
41-
from cgi import escape
42-
4332

4433
def pytest_addhooks(pluginmanager):
4534
from . import hooks
@@ -95,10 +84,10 @@ def pytest_unconfigure(config):
9584

9685
def data_uri(content, mime_type="text/plain", charset="utf-8"):
9786
data = b64encode(content.encode(charset)).decode("ascii")
98-
return "data:{0};charset={1};base64,{2}".format(mime_type, charset, data)
87+
return f"data:{mime_type};charset={charset};base64,{data}"
9988

10089

101-
class HTMLReport(object):
90+
class HTMLReport:
10291
def __init__(self, logfile, config):
10392
logfile = os.path.expanduser(os.path.expandvars(logfile))
10493
self.logfile = os.path.abspath(logfile)
@@ -136,7 +125,7 @@ def __init__(self, outcome, report, logfile, config):
136125
cells = [
137126
html.td(self.outcome, class_="col-result"),
138127
html.td(self.test_id, class_="col-name"),
139-
html.td("{0:.2f}".format(self.time), class_="col-duration"),
128+
html.td(f"{self.time:.2f}", class_="col-duration"),
140129
html.td(self.links_html, class_="col-links"),
141130
]
142131

@@ -181,7 +170,7 @@ def create_asset(
181170
if not os.path.exists(os.path.dirname(asset_path)):
182171
os.makedirs(os.path.dirname(asset_path))
183172

184-
relative_path = "{0}/{1}".format("assets", asset_file_name)
173+
relative_path = f"assets/{asset_file_name}"
185174

186175
kwargs = {"encoding": "utf-8"} if "b" not in mode else {}
187176
with open(asset_path, mode, **kwargs) as f:
@@ -209,13 +198,10 @@ def append_extra_html(self, extra, extra_index, test_index):
209198
)
210199
html_div = html.a(html.img(src=content), href=content)
211200
elif self.self_contained:
212-
src = "data:{0};base64,{1}".format(extra.get("mime_type"), content)
201+
src = "data:{};base64,{}".format(extra.get("mime_type"), content)
213202
html_div = html.img(src=src)
214203
else:
215-
if PY3:
216-
content = content.encode("utf-8")
217-
218-
content = b64decode(content)
204+
content = b64decode(content.encode("utf-8"))
219205
href = src = self.create_asset(
220206
content, extra_index, test_index, extra.get("extension"), "wb"
221207
)
@@ -276,7 +262,7 @@ def append_log_html(self, report, additional_html):
276262

277263
for section in report.sections:
278264
header, content = map(escape, section)
279-
log.append(" {0} ".format(header).center(80, "-"))
265+
log.append(f" {header:-^80} ")
280266
log.append(html.br())
281267
if ANSI:
282268
converter = Ansi2HTMLConverter(inline=False, escaped=False)
@@ -296,7 +282,7 @@ def _appendrow(self, outcome, report):
296282
self.results.insert(index, result)
297283
tbody = html.tbody(
298284
result.row_table,
299-
class_="{0} results-table-row".format(result.outcome.lower()),
285+
class_="{} results-table-row".format(result.outcome.lower()),
300286
)
301287
if result.row_extra is not None:
302288
tbody.append(result.row_extra)
@@ -345,9 +331,7 @@ def _generate_report(self, session):
345331

346332
self.style_css = pkg_resources.resource_string(
347333
__name__, os.path.join("resources", "style.css")
348-
)
349-
if PY3:
350-
self.style_css = self.style_css.decode("utf-8")
334+
).decode("utf-8")
351335

352336
if ANSI:
353337
ansi_css = [
@@ -362,12 +346,12 @@ def _generate_report(self, session):
362346
for path in self.config.getoption("css"):
363347
self.style_css += "\n/******************************"
364348
self.style_css += "\n * CUSTOM CSS"
365-
self.style_css += "\n * {}".format(path)
349+
self.style_css += f"\n * {path}"
366350
self.style_css += "\n ******************************/\n\n"
367351
with open(path, "r") as f:
368352
self.style_css += f.read()
369353

370-
css_href = "{0}/{1}".format("assets", "style.css")
354+
css_href = "assets/style.css"
371355
html_css = html.link(href=css_href, rel="stylesheet", type="text/css")
372356
if self.self_contained:
373357
html_css = html.style(raw(self.style_css))
@@ -401,12 +385,12 @@ def generate_checkbox(self):
401385
name="filter_checkbox",
402386
class_="filter",
403387
hidden="true",
404-
**checkbox_kwargs
388+
**checkbox_kwargs,
405389
)
406390

407391
def generate_summary_item(self):
408392
self.summary_item = html.span(
409-
"{0} {1}".format(self.total, self.label), class_=self.class_html
393+
f"{self.total} {self.label}", class_=self.class_html
410394
)
411395

412396
outcomes = [
@@ -422,9 +406,7 @@ def generate_summary_item(self):
422406
outcomes.append(Outcome("rerun", self.rerun))
423407

424408
summary = [
425-
html.p(
426-
"{0} tests ran in {1:.2f} seconds. ".format(numtests, suite_time_delta)
427-
),
409+
html.p(f"{numtests} tests ran in {suite_time_delta:.2f} seconds. "),
428410
html.p(
429411
"(Un)check the boxes to filter the results.",
430412
class_="filter",
@@ -472,19 +454,17 @@ def generate_summary_item(self):
472454

473455
main_js = pkg_resources.resource_string(
474456
__name__, os.path.join("resources", "main.js")
475-
)
476-
if PY3:
477-
main_js = main_js.decode("utf-8")
457+
).decode("utf-8")
478458

479459
body = html.body(
480460
html.script(raw(main_js)),
481461
html.h1(os.path.basename(self.logfile)),
482462
html.p(
483-
"Report generated on {0} at {1} by ".format(
463+
"Report generated on {} at {} by ".format(
484464
generated.strftime("%d-%b-%Y"), generated.strftime("%H:%M:%S")
485465
),
486466
html.a("pytest-html", href=__pypi_url__),
487-
" v{0}".format(__version__),
467+
f" v{__version__}",
488468
),
489469
onLoad="init()",
490470
)
@@ -501,12 +481,11 @@ def generate_summary_item(self):
501481

502482
doc = html.html(head, body)
503483

504-
unicode_doc = u"<!DOCTYPE html>\n{0}".format(doc.unicode(indent=2))
505-
if PY3:
506-
# Fix encoding issues, e.g. with surrogates
507-
unicode_doc = unicode_doc.encode("utf-8", errors="xmlcharrefreplace")
508-
unicode_doc = unicode_doc.decode("utf-8")
509-
return unicode_doc
484+
unicode_doc = "<!DOCTYPE html>\n{}".format(doc.unicode(indent=2))
485+
486+
# Fix encoding issues, e.g. with surrogates
487+
unicode_doc = unicode_doc.encode("utf-8", errors="xmlcharrefreplace")
488+
return unicode_doc.decode("utf-8")
510489

511490
def _generate_environment(self, config):
512491
if not hasattr(config, "_metadata") or config._metadata is None:
@@ -522,10 +501,10 @@ def _generate_environment(self, config):
522501

523502
for key in keys:
524503
value = metadata[key]
525-
if isinstance(value, basestring) and value.startswith("http"):
504+
if isinstance(value, str) and value.startswith("http"):
526505
value = html.a(value, href=value, target="_blank")
527506
elif isinstance(value, (list, tuple, set)):
528-
value = ", ".join((str(i) for i in value))
507+
value = ", ".join(str(i) for i in value)
529508
rows.append(html.tr(html.td(key), html.td(value)))
530509

531510
environment.append(html.table(rows, id="environment"))
@@ -569,6 +548,4 @@ def pytest_sessionfinish(self, session):
569548
self._save_report(report_content)
570549

571550
def pytest_terminal_summary(self, terminalreporter):
572-
terminalreporter.write_sep(
573-
"-", "generated html file: file://{0}".format(self.logfile)
574-
)
551+
terminalreporter.write_sep("-", f"generated html file: file://{self.logfile}")

setup.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,10 @@
1212
package_data={"pytest_html": ["resources/*"]},
1313
entry_points={"pytest11": ["html = pytest_html.plugin"]},
1414
setup_requires=["setuptools_scm"],
15-
install_requires=["pytest>=3.0", "pytest-metadata"],
15+
install_requires=["pytest>=5.0", "pytest-metadata"],
1616
license="Mozilla Public License 2.0 (MPL 2.0)",
1717
keywords="py.test pytest html report",
18+
python_requires=">=3.6",
1819
classifiers=[
1920
"Development Status :: 5 - Production/Stable",
2021
"Framework :: Pytest",
@@ -27,8 +28,9 @@
2728
"Topic :: Software Development :: Testing",
2829
"Topic :: Utilities",
2930
"Programming Language :: Python",
30-
"Programming Language :: Python :: 2.7",
31+
"Programming Language :: Python :: 3",
3132
"Programming Language :: Python :: 3.6",
3233
"Programming Language :: Python :: 3.7",
34+
"Programming Language :: Python :: 3 :: Only",
3335
],
3436
)

0 commit comments

Comments
 (0)