File: matchers.rst

package info (click to toggle)
python-libcst 1.8.6-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 6,240 kB
  • sloc: python: 78,096; makefile: 15; sh: 2
file content (178 lines) | stat: -rw-r--r-- 8,876 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
.. _libcst-matchers:

========
Matchers
========

Matchers are provided as a way of asking whether a particular LibCST node and its
children match a particular shape. It is possible to write a visitor that
tracks attributes using ``visit_<Node>`` methods. It is also possible to implement
manual instance checking and traversal of a node's children. However, both are
cumbersome to write and hard to understand. Matchers offer a more concise way of
defining what attributes on a node matter when matching against predefined patterns.

To accomplish this, a matcher has been created which corresponds to each LibCST
node documented in :ref:`libcst-nodes`. Matchers default each of their attributes
to the special sentinel matcher :func:`~libcst.matchers.DoNotCare`. When constructing
a matcher, you can initialize the node with only the values of attributes that
you are concerned with, leaving the rest of the attributes set to
:func:`~libcst.matchers.DoNotCare` in order to skip comparing against them.

------------
Matcher APIs
------------

Functions
^^^^^^^^^

Matchers can be used either by calling :func:`~libcst.matchers.matches` or
:func:`~libcst.matchers.findall` directly, or by using various decorators to
selectively control when LibCST calls visitor functions.

.. autofunction:: libcst.matchers.matches
.. autofunction:: libcst.matchers.findall
.. autofunction:: libcst.matchers.extract
.. autofunction:: libcst.matchers.extractall
.. autofunction:: libcst.matchers.replace

.. _libcst-matcher-decorators:

Decorators
^^^^^^^^^^

The following decorators can be placed onto a method in a visitor or transformer
in order to convert it into a visitor which is called when the provided matcher is
true.

.. autofunction:: libcst.matchers.visit
.. autofunction:: libcst.matchers.leave

The following decorators can be placed onto any existing ``visit_<Node>`` or
``leave_<Node>`` visitor, as well as any visitor created using either
:func:`~libcst.matchers.visit` or :func:`~libcst.matchers.leave`. They control
whether the visitor itself gets called or skipped by LibCST when traversing a tree.
Note that when a visitor function is skipped, its children will still be visited
based on the rules set forth in :ref:`libcst-visitors`. Namely, if you have a separate
``visit_<Node>`` visitor that returns ``False`` for a particular node, we will not
traverse to its children.

.. autofunction:: libcst.matchers.call_if_inside
.. autofunction:: libcst.matchers.call_if_not_inside

When using matcher decorators, your visitors must subclass from
:class:`~libcst.matchers.MatcherDecoratableVisitor` instead of :class:`libcst.CSTVisitor`,
and from :class:`~libcst.matchers.MatcherDecoratableTransformer` instead of
:class:`libcst.CSTTransformer`. This is so that visitors and transformers not making
use of matcher decorators do not pay the extra cost of their implementation. Note that
if you do not subclass from :class:`~libcst.matchers.MatcherDecoratableVisitor` or
:class:`~libcst.matchers.MatcherDecoratableTransformer`, you can still use the
:func:`~libcst.matchers.matches` function.

Both of these classes are strict subclasses of their corresponding LibCST base class,
so they can be used anywhere that expects a LibCST base class. See :ref:`libcst-visitors`
for more information.

.. autoclass:: libcst.matchers.MatcherDecoratableVisitor
.. autoclass:: libcst.matchers.MatcherDecoratableTransformer

Traversal Order
^^^^^^^^^^^^^^^

Visit and leave functions created using :func:`~libcst.matchers.visit` or
:func:`~libcst.matchers.leave` follow the traversal order rules laid out in
LibCST's visitor :ref:`libcst-visitor-traversal` with one additional rule. Any
visit function created using the :func:`~libcst.matchers.visit` decorator will be
called **before** a ``visit_<Node>`` function if it is defined for your visitor.
The order in which various visit functions which are created with
:func:`~libcst.matchers.visit` are called is indeterminate, but all such functions
will be called before calling the ``visit_<Node>`` method. Similarly, any leave
function created using the :func:`~libcst.matchers.leave` decorator will be called
**after** a ``leave_<Node>`` function if it is defined for your visitor. The order
in which various leave functions which are created with
:func:`~libcst.matchers.leave` are called is indeterminate, but all such functions
will be called after calling the ``visit_<Node>`` function if it is defined for
your visitor.

This has a few implications. The first is that if you return ``False`` from a
``visit_<Node>`` method, we are guaranteed to call your decorated visit functions
as well. Second, when modifying a node in both ``leave_<Node>`` and a visitor
created with :func:`~libcst.matchers.leave`, the ``original_node`` will be unchanged
for both and the ``updated_node`` available to the decorated leave method will be
the node that is returned by the ``leave_<Node>`` method. Chaining modifications
across multiple leave functions is supported, but must be done with care.

-------------
Matcher Types
-------------

Concrete Matchers
^^^^^^^^^^^^^^^^^

For each node found in :ref:`libcst-nodes`, a corresponding concrete matcher
has been generated. Each matcher has attributes identical to its LibCST node
counterpart. For example, :class:`libcst.Expr` includes the ``value`` and ``semicolon``
attributes, and therefore :class:`libcst.matchers.Expr` similarly includes the same
attributes. Just as :class:`libcst.Expr`'s ``value`` is typed as taking a
:class:`libcst.BaseExpression`, :class:`libcst.matchers.Expr`'s ``value`` is typed
as taking a :class:`libcst.matchers.BaseExpression`. For every node that exists in
LibCST, both concrete and abstract, a corresponding matcher has been defined.

There are a few special cases to the rules laid out above. For starters, matchers
don't support evaluating :class:`~libcst.MaybeSentinel`. There is no way to specify
that you wish to match against a :class:`~libcst.MaybeSentinel` except with the
:func:`~libcst.matchers.DoNotCare` matcher. This tends not to be an issue in
practice because :class:`~libcst.MaybeSentinel` is only found on syntax nodes.

While there are base classes such as :class:`libcst.matchers.BaseExpression`, you
cannot match directly on them. They are provided for typing purposes only in order
to exactly match the types on LibCST node attributes. If you need to match on
all concrete subclasses of a base class, we recommend using the special matcher
:class:`~libcst.matchers.OneOf`.

.. autoclass:: libcst.matchers.BaseMatcherNode

Special Matchers
^^^^^^^^^^^^^^^^

Special matchers are matchers that don't have a corresponding LibCST node. Concrete
matchers only match against their corresponding LibCST node, limiting their use
under certain circumstances. Special matchers fill in the gap by allowing
higher-level logic constructs such as inversion. You can use any special matcher
in place of a concrete matcher when specifying matcher attributes. Additionally,
you can also use the :class:`~libcst.matchers.AllOf` and
:class:`~libcst.matchers.OneOf` special matchers in place of a concrete matcher
when calling :func:`~libcst.matchers.matches` or using decorators.

.. autoclass:: libcst.matchers.OneOf
.. autoclass:: libcst.matchers.AllOf
.. autoclass:: libcst.matchers.TypeOf
.. autofunction:: libcst.matchers.DoesNotMatch
.. autoclass:: libcst.matchers.MatchIfTrue
.. autofunction:: libcst.matchers.MatchRegex
.. autoclass:: libcst.matchers.MatchMetadata
.. autoclass:: libcst.matchers.MatchMetadataIfTrue
.. autofunction:: libcst.matchers.SaveMatchedNode
.. autofunction:: libcst.matchers.DoNotCare

Sequence Wildcard Matchers
^^^^^^^^^^^^^^^^^^^^^^^^^^

Sequence wildcard matchers are matchers that only get used when constructing a
sequence to match against. Not all LibCST nodes have attributes which are sequences,
but for those that do, sequence wildcard matchers offer a great degree of
flexibility. Unlike all other matcher types, these allow you to match against
more than one LibCST node, much like wildcards in regular expressions do.

LibCST does not implicitly match on partial sequences for you. So, when matching
against a sequence you will need to provide a complete pattern. This often means
using helpers such as :func:`~libcst.matchers.ZeroOrMore` as the first and last
element of your sequence. Think of it as the difference between Python's
`re.match <https://docs.python.org/3/library/re.html#re.match>`_ and
`re.fullmatch <https://docs.python.org/3/library/re.html#re.fullmatch>`_ functions.
LibCST matchers behave like the latter so that it is possible to specify sequences
which must start with, end with or be exactly equal to some pattern.

.. autoclass:: libcst.matchers.AtLeastN
.. autofunction:: libcst.matchers.ZeroOrMore
.. autoclass:: libcst.matchers.AtMostN
.. autofunction:: libcst.matchers.ZeroOrOne