diff --git a/devtools/prettier.py b/devtools/prettier.py index 7489d33..e378030 100644 --- a/devtools/prettier.py +++ b/devtools/prettier.py @@ -1,3 +1,4 @@ +import ast import io import os from collections import OrderedDict @@ -80,6 +81,7 @@ def __init__( (bytearray, self._format_bytearray), (generator_types, self._format_generator), # put these last as the check can be slow + (ast.AST, self._format_ast_expression), (LaxMapping, self._format_dict), (DataClassType, self._format_dataclass), (SQLAlchemyClassType, self._format_sqlalchemy_class), @@ -240,6 +242,17 @@ def _format_bytearray(self, value: 'Any', _: str, indent_current: int, indent_ne lines = self._wrap_lines(bytes(value), indent_new) self._str_lines(lines, indent_current, indent_new) + def _format_ast_expression(self, value: ast.AST, _: str, indent_current: int, indent_new: int) -> None: + try: + s = ast.dump(value, indent=self._indent_step) + except TypeError: + # no indent before 3.9 + s = ast.dump(value) + lines = s.splitlines(True) + self._stream.write(lines[0]) + for line in lines[1:]: + self._stream.write(indent_current * self._c + line) + def _format_dataclass(self, value: 'Any', _: str, indent_current: int, indent_new: int) -> None: self._format_fields(value, value.__dict__.items(), indent_current, indent_new) diff --git a/requirements/testing.in b/requirements/testing.in index 7b1ad14..1976d79 100644 --- a/requirements/testing.in +++ b/requirements/testing.in @@ -5,7 +5,9 @@ pytest-mock pytest-pretty # these packages are used in tests so install the latest version pydantic -asyncpg +# no binaries for 3.7 +asyncpg; python_version>='3.8' +# no version is compatible with 3.7 and 3.11 numpy; python_version>='3.8' multidict; python_version>='3.8' sqlalchemy diff --git a/requirements/testing.txt b/requirements/testing.txt index b62eaba..2ce58bf 100644 --- a/requirements/testing.txt +++ b/requirements/testing.txt @@ -4,7 +4,7 @@ # # pip-compile --output-file=requirements/testing.txt --resolver=backtracking requirements/testing.in # -asyncpg==0.27.0 +asyncpg==0.27.0 ; python_version >= "3.8" # via -r requirements/testing.in attrs==22.2.0 # via pytest diff --git a/tests/test_prettier.py b/tests/test_prettier.py index 364447b..6a0247c 100644 --- a/tests/test_prettier.py +++ b/tests/test_prettier.py @@ -1,5 +1,7 @@ +import ast import os import string +import sys from collections import Counter, OrderedDict, namedtuple from dataclasses import dataclass from typing import List @@ -457,3 +459,26 @@ class User(SQLAlchemyBase): " nickname='test',\n" ")" ) + + +@pytest.mark.skipif(sys.version_info < (3, 9), reason='no indent on older versions') +def test_ast_expr(): + assert pformat(ast.parse('print(1, 2, round(3))', mode='eval')) == ( + "Expression(" + "\n body=Call(" + "\n func=Name(id='print', ctx=Load())," + "\n args=[" + "\n Constant(value=1)," + "\n Constant(value=2)," + "\n Call(" + "\n func=Name(id='round', ctx=Load())," + "\n args=[" + "\n Constant(value=3)]," + "\n keywords=[])]," + "\n keywords=[]))" + ) + + +@pytest.mark.skipif(sys.version_info < (3, 9), reason='no indent on older versions') +def test_ast_module(): + assert pformat(ast.parse('print(1, 2, round(3))')).startswith('Module(\n body=[')