refex.python.matcher
¶
Support for high-level AST matchers.
These return extended match objects that can carry syntactic and/or lexical information about the match.
-
parse_ast
(source_code: str, filename: str = '<string>') → refex.python.matcher.PythonParsedFile¶ Parses an AST in a way that supports the built-in matchers.
This includes auxiliary information / post-processing / etc. which are not provided by
ast.parse()
.- Parameters
source_code – Python source code.
filename – file name (for reporting syntax errors and the like).
- Returns
The resulting
PythonParsedFile
- Raises
ParseError – The file failed to parse.
-
find_iter
(matcher: refex.python.matcher.Matcher, parsed: refex.python.matcher.PythonParsedFile) → Iterator[refex.python.matcher.MatchInfo]¶ Finds all matches in an AST.
This is analogous to
re.finditer()
. If a node is matched, then any sub-nodes are skipped. Otherwise,find_iter()
recurses inside of the node to find matches inside of it.- Parameters
matcher – a
Matcher
.parsed – A
PythonParsedFile
as returned byparse_ast()
.
- Yields
The successful results of
matcher.match()
(MatchInfo
).
Parsing¶
-
exception
ParseError
¶ Bases:
Exception
Exception raised if input failed to parse.
The stringified exception specifies all the necessary/available debug information about the error, location, etc., but does not include the filename.
-
class
PythonParsedFile
(text: str, path: str, pragmas: Iterable[Pragma], ast_tokens: asttokens.asttokens.ASTTokens, tree: _ast.Module, nav: AstNav)¶ Bases:
refex.parsed_file.ParsedFile
Preprocessed file information, including the AST etc.
-
class
MatchContext
(parsed_file: refex.python.matcher.PythonParsedFile, has_successful_run: Set[Hashable] = NOTHING, has_match_run: Set[Hashable] = NOTHING)¶ Bases:
object
Per-match and per-file context.
One prototype
MatchContext
exists per file, containing shared data across all successful runs. A separate derived instance is made per top-level invocation of a matcher, which can be used to keep state across a match that shouldn’t transfer to subsequent match attempts. (For example, a matcher that must match exactly the same string across all invocations inside a match, or similar.)
Matches¶
-
class
LexicalMatch
(text: str, first_token: asttokens.util.Token, last_token: asttokens.util.Token, include_first: bool = True, include_last: bool = True)¶ Bases:
refex.match.Match
Lexical match with no AST information.
-
first_token
¶ The first token delimiting the matched lexical span.
-
last_token
¶ The last token delimiting the matched lexical span.
-
include_first
¶ Whether this starts before or after the first token.
-
include_last
¶ Whether this ends before or after the last token.
-
string
¶ The matched string.
-
span
¶ The matched span.
-
-
class
LexicalASTMatch
(matched: Any, text: str, first_token: asttokens.util.Token, last_token: asttokens.util.Token, include_first: bool = True, include_last: bool = True)¶ Bases:
refex.match.ObjectMatch
,refex.python.matcher.LexicalMatch
AST match with adjustable start/end tokens.
Bindings¶
-
class
BoundValue
(value: Any, on_conflict=None, on_merge=None)¶ Mergeable bound values.
Two
BoundValue
objects will only be merged if they have equal merge attributes – i.e. if they both agree on how to merge with each other. Anything else results in aMatchError
.-
value
¶ A value that has a bound name somewhere.
-
on_conflict
¶ A strategy from
BindConflict
for merging two bound values. Defaults toMERGE
.
-
rebind
(on_conflict=None, on_merge=None)¶ Returns a new BoundValue with different merge settings.
- Parameters
on_conflict – if not
None
, a new value foron_conflict
.on_merge – if not
None
, a new value foron_merge
.
- Returns
A new
BoundValue
with the samevalue
, and the updated merge settings.
-
-
class
BindMerge
¶ Bind conflict merge strategies.
If a conflict is considered mergeable by the
BindConflict
parameter, this says how to merge the two.-
KEEP_FIRST
¶
-
KEEP_LAST
¶
-
-
class
BindConflict
¶ What to do if two bindings share the same name.
Each of these is a value that can be passed as the
merge
parameter toBoundValue
, or theon_conflict
parameter tobase_matchers.Bind
.-
SKIP
¶ Fail this match.
-
ERROR
¶ Raise a
MatchError
-
MERGE_IDENTICAL
¶ Merge if the values are equal, otherwise
SKIP
.
-
MERGE_IDENTICAL_OR_ERROR
¶ Merge if the values are equal, otherwise
ERROR
.
-
MERGE_EQUIVALENT_AST
¶ Merge if the values are “equivalent” ASTs, otherwise
SKIP
.Two ASTs are equivalent if they are structurally identical, modulo lvalue/rvalue distinctions. (Variables are considered equivalent if they have the same name, even if one is used for a load and the other is used for a store.)
-
MERGE_EQUIVALENT_AST_OR_ERROR
¶ Merge if the values are “equivalent” ASTs, otherwise
ERROR
.
-
Matchers¶
-
exception
MatchError
¶ An error raised when something went wrong in the match.
This exception represents a bug in the way a matcher was used, not a bug in the matcher implementation or in refex itself.
-
class
MatchInfo
(match: refex.match.Match, bindings: Dict[str, refex.python.matcher.BoundValue] = NOTHING, replacements: Dict[str, refex.formatting.Template] = NOTHING)¶ A result object containing a successful match.
-
match
¶ The match for the top-level matcher.
-
replacement
¶ the replacement for the match, if any.
-
bindings
¶ A dict of bound matches for later reuse.
-
replacements
¶ A dict of replacements for given bindings.
-
-
class
Matcher
¶ An immutable AST node matcher.
Reusable subclasses are in
refex.python.matchers
.-
match
(context: refex.python.matcher.MatchContext, candidate: Any) → Optional[refex.python.matcher.MatchInfo]¶ Matches a candidate value.
- Parameters
context – A
MatchContext
object with additional metadata.candidate – A candidate object to be matched against.
- Returns
A
MatchInfo
object, orNone
if the match failed.
-
Concrete Matchers¶
-
class
DebugLabeledMatcher
(debug_label: str, submatcher, log_level: int = 1)¶ A matcher which wraps another matcher with a label for debugging.
-
class
ImplicitEquals
(value: Any)¶ Matches a candidate iff it equals the provided value.
This is implicitly created whenever a matcher was expected, but a non-matcher value was provided. For example,
Contains(3)
creates the matcherContains(ImplicitEquals(3))
.To explicitly compare for equality, use
base_matchers.Equals
.ImplicitEquals
should never be used explicitly (but is fine to use implicitly).