Skip to content

BUG: pd.show_versions: json.decoder.JSONDecodeError #39766

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Feb 22, 2021
Merged
1 change: 1 addition & 0 deletions doc/source/whatsnew/v1.3.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,7 @@ Other
- Bug in :class:`Styler` where ``subset`` arg in methods raised an error for some valid multiindex slices (:issue:`33562`)
- :class:`Styler` rendered HTML output minor alterations to support w3 good code standard (:issue:`39626`)
- Bug in :meth:`DataFrame.equals`, :meth:`Series.equals`, :meth:`Index.equals` with object-dtype containing ``np.datetime64("NaT")`` or ``np.timedelta64("NaT")`` (:issue:`39650`)
- Bug in :func:`pandas.util.show_versions` where console JSON output was not proper JSON (:issue:`39701`)


.. ---------------------------------------------------------------------------
Expand Down
70 changes: 59 additions & 11 deletions pandas/tests/util/test_show_versions.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import json
import os
import re

import pytest

from pandas.util._print_versions import _get_dependency_info, _get_sys_info

import pandas as pd


Expand All @@ -26,21 +30,65 @@
"ignore:Distutils:UserWarning"
)
@pytest.mark.filterwarnings("ignore:Setuptools is replacing distutils:UserWarning")
def test_show_versions(capsys):
@pytest.mark.parametrize("as_json", [True, False, "test_output.json"])
def test_show_versions(capsys, as_json, tmpdir):
# gh-32041
pd.show_versions()
if isinstance(as_json, str):
as_json = os.path.join(tmpdir, as_json)

pd.show_versions(as_json=as_json)
captured = capsys.readouterr()
result = captured.out

# check header
assert "INSTALLED VERSIONS" in result
# check header for non-JSON console output
if as_json is False:
assert "INSTALLED VERSIONS" in result

# check full commit hash
assert re.search(r"commit\s*:\s[0-9a-f]{40}\n", result)

# check required dependency
# 2020-12-09 npdev has "dirty" in the tag
assert re.search(r"numpy\s*:\s([0-9\.\+a-g\_]|dev)+(dirty)?\n", result)

# check optional dependency
assert re.search(r"pyarrow\s*:\s([0-9\.]+|None)\n", result)

# Dictionary-based asserts
else:
# check valid json is printed to the console if as_json is True
if as_json is True:
dict_check = json.loads(result)
elif isinstance(as_json, str):
# make sure that the file was created
assert os.path.exists(as_json)

with open(as_json) as fd:
contents = fd.readlines()
str_contents = "".join(contents)

# make sure that there was output to the file
assert str_contents

# check if file output is valid JSON
dict_check = json.loads(str_contents)

# Basic check that each version element is found in output
version_elements = {
"system": _get_sys_info(),
"dependencies": _get_dependency_info(),
}

assert version_elements == dict_check


# check full commit hash
assert re.search(r"commit\s*:\s[0-9a-f]{40}\n", result)
def test_json_output_match(capsys, tmpdir):
pd.show_versions(as_json=True)
result_console = capsys.readouterr().out

# check required dependency
# 2020-12-09 npdev has "dirty" in the tag
assert re.search(r"numpy\s*:\s([0-9\.\+a-g\_]|dev)+(dirty)?\n", result)
out_path = os.path.join(tmpdir, "test_json.json")
pd.show_versions(as_json=out_path)
with open(out_path) as out_fd:
result_file = "".join(out_fd.readlines())

# check optional dependency
assert re.search(r"pyarrow\s*:\s([0-9\.]+|None)\n", result)
assert result_console == result_file
2 changes: 1 addition & 1 deletion pandas/util/_print_versions.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ def show_versions(as_json: Union[str, bool] = False) -> None:
j = {"system": sys_info, "dependencies": deps}

if as_json is True:
print(j)
sys.stdout.writelines(json.dumps(j, indent=2))
else:
assert isinstance(as_json, str) # needed for mypy
with codecs.open(as_json, "wb", encoding="utf8") as f:
Expand Down