diff --git a/doc/source/whatsnew/v1.3.0.rst b/doc/source/whatsnew/v1.3.0.rst index 388c5dbf6a7ee..11ee3e2717612 100644 --- a/doc/source/whatsnew/v1.3.0.rst +++ b/doc/source/whatsnew/v1.3.0.rst @@ -478,6 +478,7 @@ Other - :class:`Styler` rendered HTML output minor alterations to support w3 good code standard (:issue:`39626`) - Bug in :class:`Styler` where rendered HTML was missing a column class identifier for certain header cells (:issue:`39716`) - 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`) .. --------------------------------------------------------------------------- diff --git a/pandas/tests/util/test_show_versions.py b/pandas/tests/util/test_show_versions.py index b6a16d027db77..57cd2e1a144b6 100644 --- a/pandas/tests/util/test_show_versions.py +++ b/pandas/tests/util/test_show_versions.py @@ -1,7 +1,14 @@ +import json +import os import re import pytest +from pandas.util._print_versions import ( + _get_dependency_info, + _get_sys_info, +) + import pandas as pd @@ -26,11 +33,47 @@ "ignore:Distutils:UserWarning" ) @pytest.mark.filterwarnings("ignore:Setuptools is replacing distutils:UserWarning") -def test_show_versions(capsys): +def test_show_versions(tmpdir): + # GH39701 + as_json = os.path.join(tmpdir, "test_output.json") + + pd.show_versions(as_json=as_json) + + with open(as_json) as fd: + # check if file output is valid JSON, will raise an exception if not + result = json.load(fd) + + # Basic check that each version element is found in output + expected = { + "system": _get_sys_info(), + "dependencies": _get_dependency_info(), + } + + assert result == expected + + +def test_show_versions_console_json(capsys): + # GH39701 + pd.show_versions(as_json=True) + stdout = capsys.readouterr().out + + # check valid json is printed to the console if as_json is True + result = json.loads(stdout) + + # Basic check that each version element is found in output + expected = { + "system": _get_sys_info(), + "dependencies": _get_dependency_info(), + } + + assert result == expected + + +def test_show_versions_console(capsys): + # gh-32041 # gh-32041 - pd.show_versions() - captured = capsys.readouterr() - result = captured.out + pd.show_versions(as_json=False) + result = capsys.readouterr().out # check header assert "INSTALLED VERSIONS" in result @@ -44,3 +87,16 @@ def test_show_versions(capsys): # check optional dependency assert re.search(r"pyarrow\s*:\s([0-9\.]+|None)\n", result) + + +def test_json_output_match(capsys, tmpdir): + # GH39701 + pd.show_versions(as_json=True) + result_console = capsys.readouterr().out + + 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 = out_fd.read() + + assert result_console == result_file diff --git a/pandas/util/_print_versions.py b/pandas/util/_print_versions.py index b81ec70c34396..cf5af0de5d3b5 100644 --- a/pandas/util/_print_versions.py +++ b/pandas/util/_print_versions.py @@ -115,7 +115,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: