Skip to content

Commit f52407b

Browse files
committed
IfThis.isAllOf and isAnyOf. type astASTattributes.
1 parent 5f927af commit f52407b

4 files changed

Lines changed: 265 additions & 257 deletions

File tree

astToolkit/__init__.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464

6565
from astToolkit._astTypes import (
6666
ast_attributes as ast_attributes, ast_attributes_int as ast_attributes_int,
67-
ast_attributes_type_comment as ast_attributes_type_comment, ConstantValueType as ConstantValueType,
67+
ast_attributes_type_comment as ast_attributes_type_comment, astASTattributes as astASTattributes, ConstantValueType as ConstantValueType,
6868
hasDOTannotation as hasDOTannotation, hasDOTannotation_expr as hasDOTannotation_expr,
6969
hasDOTannotation_exprOrNone as hasDOTannotation_exprOrNone, hasDOTarg as hasDOTarg, hasDOTarg_str as hasDOTarg_str,
7070
hasDOTarg_strOrNone as hasDOTarg_strOrNone, hasDOTargs as hasDOTargs, hasDOTargs_arguments as hasDOTargs_arguments,
@@ -110,7 +110,8 @@
110110
if sys.version_info >= (3, 13):
111111
from astToolkit._astTypes import hasDOTdefault_value as hasDOTdefault_value
112112

113-
from astToolkit._dumpHandmade import dump as dump
113+
if sys.version_info >= (3, 13):
114+
from astToolkit._dumpHandmade import dump as dump
114115

115116
from astToolkit._toolkitNodeVisitor import (
116117
NodeChanger as NodeChanger,

astToolkit/_astTypes.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import sys
66

77
type ConstantValueType = bool | bytes | complex | EllipsisType | float | int | None | range | str
8+
type astASTattributes = ast.AST | ConstantValueType | list[ast.AST] | list[ast.AST | None] | list[str]
89
type identifierDotAttribute = str
910
= typing_TypeVar('个', covariant=True)
1011
归个 = typing_TypeVar('归个', covariant=True)

astToolkit/_dumpHandmade.py

Lines changed: 90 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -1,97 +1,100 @@
1-
from ast import AST
2-
from astToolkit import ConstantValueType
1+
from astToolkit import astASTattributes
2+
import ast
3+
import sys
34

4-
def dump(node: AST, *, annotate_fields: bool = True, include_attributes: bool = False, indent: int | str | None = None, show_empty: bool = False) -> str: # noqa: C901, PLR0915
5-
"""Return a formatted string representation of an AST node.
5+
if sys.version_info >= (3, 13):
66

7-
Parameters
8-
----------
9-
node : AST
10-
The AST node to format.
11-
annotate_fields : bool = True
12-
Whether to include field names in the output.
13-
include_attributes : bool = False
14-
Whether to include node "_attributes" in addition to fields. The attributes in category `_attributes` are `lineno` (line
15-
_**n**umer**o**_ (_Latin_ "number")), `col_offset` (***col***umn offset), `end_lineno` (end line _**n**umer**o**_ (_Latin_
16-
"number")), and `end_col_offset` (end ***col***umn offset).
17-
indent : int | str | None = None
18-
String for indentation or number of spaces; `None` for single-line output.
19-
show_empty : bool = False
20-
Whether to include fields with empty list or `None` values.
7+
def dump(node: ast.AST, *, annotate_fields: bool = True, include_attributes: bool = False, indent: int | str | None = None, show_empty: bool = False) -> str: # noqa: C901, PLR0915
8+
"""Return a formatted string representation of an `ast.AST` node.
219
22-
Returns
23-
-------
24-
formattedString : str
25-
String representation of the AST node with specified formatting.
10+
Parameters
11+
----------
12+
node : ast.AST
13+
The `ast.AST` node to format.
14+
annotate_fields : bool = True
15+
Whether to include field names in the output.
16+
include_attributes : bool = False
17+
Whether to include node "_attributes" in addition to fields. The attributes in category `_attributes` are `lineno` (line
18+
_**n**umer**o**_ (_Latin_ "number")), `col_offset` (***col***umn offset), `end_lineno` (end line _**n**umer**o**_ (_Latin_
19+
"number")), and `end_col_offset` (end ***col***umn offset).
20+
indent : int | str | None = None
21+
String for indentation or number of spaces; `None` for single-line output.
22+
show_empty : bool = False
23+
Whether to include fields with empty list or `None` values.
2624
27-
"""
28-
def _format(node: ConstantValueType | AST | list[AST] | list[str], level: int = 0) -> tuple[str, bool]: # noqa: C901, PLR0912, PLR0915
29-
if indent_str is not None:
30-
level += 1
31-
ImaIndent: str = '\n' + indent_str * level
32-
separator: str = ',\n' + indent_str * level
33-
else:
34-
ImaIndent = ''
35-
separator = ', '
36-
if isinstance(node, AST):
37-
cls: type[AST] = type(node)
38-
args: list[str] = []
39-
args_buffer: list[str] = []
40-
allsimple: bool = True
41-
keywords: bool = annotate_fields
42-
for name in node._fields:
43-
try:
44-
value = getattr(node, name)
45-
except AttributeError:
46-
keywords = True
47-
continue
48-
if value is None and getattr(cls, name, ...) is None:
49-
if show_empty:
50-
args.append(f'{name}={value}')
51-
keywords = True
52-
continue
53-
if not show_empty:
54-
if value == []:
55-
field_type: ConstantValueType | AST | list[AST] | list[str] = cls._field_types.get(name, object)
56-
if getattr(field_type, '__origin__', ...) is list:
57-
if not keywords:
58-
args_buffer.append(repr(value))
59-
continue
60-
if not keywords:
61-
args.extend(args_buffer)
62-
args_buffer = []
63-
value_formatted, simple = _format(value, level)
64-
allsimple = allsimple and simple
65-
if keywords:
66-
args.append(f'{name}={value_formatted}')
67-
else:
68-
args.append(value_formatted)
69-
if include_attributes and node._attributes: # noqa: SLF001
70-
for name_attributes in node._attributes: # noqa: SLF001
25+
Returns
26+
-------
27+
formattedString : str
28+
String representation of the `ast.AST` node with specified formatting.
29+
30+
"""
31+
def _format(node: astASTattributes, level: int = 0) -> tuple[str, bool]: # noqa: C901, PLR0912, PLR0915
32+
if indentString is not None:
33+
level += 1
34+
ImaIndent: str = '\n' + indentString * level
35+
separator: str = ',\n' + indentString * level
36+
else:
37+
ImaIndent = ''
38+
separator = ', '
39+
if isinstance(node, ast.AST):
40+
astAST: type[ast.AST] = type(node)
41+
listAttributes: list[str] = []
42+
attributeStaging: list[str] = []
43+
simpleOutput: bool = True
44+
showAnnotations: bool = annotate_fields
45+
for name in node._fields:
7146
try:
72-
value_attributes = getattr(node, name_attributes)
47+
value: astASTattributes = getattr(node, name)
7348
except AttributeError:
49+
showAnnotations = True
7450
continue
75-
if value_attributes is None and getattr(cls, name_attributes, ...) is None:
51+
if value is None and getattr(astAST, name, ...) is None:
52+
if show_empty:
53+
listAttributes.append(f'{name}={value}')
54+
showAnnotations = True
7655
continue
77-
value_attributes_formatted, simple = _format(value_attributes, level)
78-
allsimple = allsimple and simple
79-
args.append(f'{name_attributes}={value_attributes_formatted}')
80-
if allsimple and len(args) <= 3: # noqa: PLR2004
81-
return (f"ast.{node.__class__.__name__}({', '.join(args)})", not args)
82-
return (f"ast.{node.__class__.__name__}({ImaIndent}{separator.join(args)})", False)
83-
elif isinstance(node, list):
84-
if not node:
85-
return ('[]', True)
86-
return (f'[{ImaIndent}{separator.join(_format(x, level)[0] for x in node)}]', False)
87-
return (repr(node), True)
56+
if not show_empty:
57+
if value == []:
58+
field_type: astASTattributes = astAST._field_types.get(name, object) # noqa: SLF001
59+
if getattr(field_type, '__origin__', ...) is list:
60+
if not showAnnotations:
61+
attributeStaging.append(repr(value))
62+
continue
63+
if not showAnnotations:
64+
listAttributes.extend(attributeStaging)
65+
attributeStaging = []
66+
valueFormatted, simpleFormat = _format(value, level)
67+
simpleOutput = simpleOutput and simpleFormat
68+
if showAnnotations:
69+
listAttributes.append(f'{name}={valueFormatted}')
70+
else:
71+
listAttributes.append(valueFormatted)
72+
if include_attributes and node._attributes: # noqa: SLF001
73+
for name_attributes in node._attributes: # noqa: SLF001
74+
try:
75+
value_attributes = getattr(node, name_attributes)
76+
except AttributeError:
77+
continue
78+
if value_attributes is None and getattr(astAST, name_attributes, ...) is None:
79+
continue
80+
value_attributesFormatted, simpleFormat = _format(value_attributes, level)
81+
simpleOutput = simpleOutput and simpleFormat
82+
listAttributes.append(f'{name_attributes}={value_attributesFormatted}')
83+
if simpleOutput and len(listAttributes) <= 3:
84+
return (f"ast.{node.__class__.__name__}({', '.join(listAttributes)})", not bool(listAttributes))
85+
return (f"ast.{node.__class__.__name__}({ImaIndent}{separator.join(listAttributes)})", False)
86+
elif isinstance(node, list):
87+
if not node:
88+
return ('[]', True)
89+
return (f'[{ImaIndent}{separator.join(_format(x, level)[0] for x in node)}]', False)
90+
return (repr(node), True)
8891

89-
if not isinstance(node, AST):
90-
message = f'expected AST, got {node.__class__.__name__!r}'
91-
raise TypeError(message)
92-
if indent is not None and not isinstance(indent, str):
93-
indent_str = ' ' * indent
94-
else:
95-
indent_str = indent
96-
return _format(node)[0]
92+
if not isinstance(node, ast.AST):
93+
message = f'expected `ast.AST`, got {node.__class__.__name__!r}'
94+
raise TypeError(message)
95+
if indent is not None and not isinstance(indent, str):
96+
indentString = " " * indent
97+
else:
98+
indentString = indent
99+
return _format(node)[0]
97100

0 commit comments

Comments
 (0)