diff --git a/pyproject.toml b/pyproject.toml index 1339e34e..27c37a72 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,7 +30,6 @@ classifiers = [ ] dependencies = [ "azure-identity>=1.22.0", - "black>=25.12.0", "colorama>=0.4.6", "mcp[cli]>=1.12.1", "numpy>=2.2.6", @@ -81,6 +80,7 @@ known_local_folder = ["conftest"] dev = [ "azure-mgmt-authorization>=4.0.0", "azure-mgmt-keyvault>=12.1.1", + "black>=25.12.0", "coverage[toml]>=7.9.1", "google-api-python-client>=2.184.0", "google-auth-httplib2>=0.2.0", diff --git a/src/typeagent/aitools/utils.py b/src/typeagent/aitools/utils.py index eb21f9ec..51621f79 100644 --- a/src/typeagent/aitools/utils.py +++ b/src/typeagent/aitools/utils.py @@ -44,27 +44,24 @@ def timelog(label: str, verbose: bool = True): def pretty_print(obj: object, prefix: str = "", suffix: str = "") -> None: - """Pretty-print an object using black. + """Pretty-print an object using pprint.""" + import pprint - NOTE: Only works if its repr() is a valid Python expression. - """ - print(prefix + format_code(repr(obj)) + suffix) + line_width = min(200, shutil.get_terminal_size().columns) + print(pprint.pformat(obj, width=line_width)) def format_code(text: str, line_width=None) -> str: - """Format a block of code using black, then reindent to 2 spaces. + """Format a Python literal expression using pprint. - NOTE: The text must be a valid Python expression or code block. + NOTE: The text must be a valid Python literal expression (as produced by repr()). """ - import black + import ast + import pprint if line_width is None: - # Use the terminal width, but cap it to 200 characters. line_width = min(200, shutil.get_terminal_size().columns) - formatted_text = black.format_str( - text, mode=black.Mode(line_length=line_width) - ).rstrip() - return reindent(formatted_text) + return pprint.pformat(ast.literal_eval(text), width=line_width) def reindent(text: str) -> str: diff --git a/src/typeagent/knowpro/answers.py b/src/typeagent/knowpro/answers.py index 58a536ed..eb77e12f 100644 --- a/src/typeagent/knowpro/answers.py +++ b/src/typeagent/knowpro/answers.py @@ -125,12 +125,12 @@ def create_question_prompt(question: str) -> str: def create_context_prompt(context: AnswerContext) -> str: # TODO: Use a more compact representation of the context than JSON. - import black + import pprint prompt = [ "[ANSWER CONTEXT]", "===", - black.format_str(str(dictify(context)), mode=black.Mode(line_length=200)), + pprint.pformat(dictify(context), width=200), "===", ] return "\n".join(prompt) diff --git a/tests/test_utils.py b/tests/test_utils.py index 7f806f74..4c3edbe5 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -24,14 +24,36 @@ def test_timelog(): def test_pretty_print(): - # Use a simple object and check output is formatted by black obj = {"a": 1} buf = StringIO() with redirect_stdout(buf): utils.pretty_print(obj) out = buf.getvalue() - # Should be valid Python and contain the dict - assert out == '{"a": 1}\n', out + assert out == "{'a': 1}\n", out + + +def test_pretty_print_nested(): + obj = {"b": [1, 2], "a": {"nested": True}} + buf = StringIO() + with redirect_stdout(buf): + utils.pretty_print(obj) + out = buf.getvalue() + # pprint sorts keys and formats nested structures + assert "'a'" in out + assert "'nested'" in out + + +def test_format_code_simple(): + text = repr({"a": 1}) + result = utils.format_code(text) + assert result == "{'a': 1}" + + +def test_format_code_nested(): + obj = {"b": [1, 2, 3], "a": {"nested": True}} + result = utils.format_code(repr(obj)) + parsed = eval(result) + assert parsed == obj def test_load_dotenv(really_needs_auth):