File: proxy_list.rst

package info (click to toggle)
python-redbaron 0.9.2-4
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, sid, trixie
  • size: 772 kB
  • sloc: python: 6,650; makefile: 145; sh: 28
file content (358 lines) | stat: -rw-r--r-- 7,985 bytes parent folder | download
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
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
.. ipython:: python
    :suppress:

    import sys
    sys.path.append("..")

    import redbaron
    redbaron.ipython_behavior = False

    from redbaron import RedBaron


Proxy List
==========

Problem
-------

For a python developer, the list :file:`[1, 2, 3]` has 3 members, which
is true in the python world, but in the "source code modification"
world, this list has 5 elements because you have to count the 2 commas.
Indeed each comma needs to be taken into account separately because they
can have a different formatting.

This makes things quite annoying to deal with because you have to think
about the formatting too! For example, if you want to append an item to
a list, you need to take care of a lot of details:

* if the list is empty you don't have to put a comma
* otherwise yes
* but wait, what happens if there is a trailing comma?
* also, what to do if the list is declared in an indented way (with :file:`"\\n    "` after every comma for example)?
* etc...

And that's only for a comma separated list of things: you also have the
same formatting details to care about for dot separated lists
(e.g. :file:`a.b.c().d[plop]`) and endl separated lists (a python code block,
or you whole source file).

You don't want to have to deal with this.

Solution
--------

To avoid you to deal with all this boring low level details, RedBaron
implements "proxy lists". This abstraction gives you the impression that the
list of things you are dealing with behave the same way than in the python
world while taking care of all the low level formatting details.

The "proxy lists" has the same API than a python list so they should be
really intuitive to use.

For example:

.. ipython:: python

    red = RedBaron("[1, 2, 3]")
    red[0].value.append("42")
    red
    del red[0].value[2]
    red

There are, for now, 4 kind of proxy lists:

* :file:`CommaProxyList` which handles comma separated lists
* :file:`DotProxyList` which handles :file:`atomtrailers` (those kind of constructions: :file:`a.b[plop].c()`)
* :file:`LineProxyList` which handles lines of code (like the body of a function or the
  whole source code)
* :file:`DecoratorLineProxyList` which handles lists of decorators (they are nearly the
  same as :file:`LineProxyList`)

**Be aware that the proxy list are set on the attribute that is a list, not
on the node holding the list. See the 'value' attribute access in the
examples below.**

Usage
-----

As said, proxy lists have the exact same API than python lists (at the exception
that they don't implement the :file:`sort` and :file:`reverse` methods).
Every method accepts as input the same inputs that you can use to modify a node
in RedBaron. This means that you can pass a string containing source code,
an FST or a RedBaron node.

Here is a session demonstrating every method of a proxy list:

.. ipython:: python

    red = RedBaron("[1, 2, 3]")

Please refer to `python list documentation
<https://docs.python.org/2/tutorial/datastructures.html>`_ if you want to
know the exact behavior or those methods (or `send a patch
<https://github.com/PyCQA/redbaron>`_ to improve this documentation).

append
~~~~~~

.. ipython:: python

    red
    red[0].value.append("plop")
    red
    red[0].value

insert
~~~~~~

.. ipython:: python

    red
    red[0].value.insert(1, "42")
    red
    red[0].value

extend
~~~~~~

.. ipython:: python

    red
    red[0].value.extend(["pif", "paf", "pouf"])
    red
    red[0].value

pop
~~~

.. ipython:: python

    red
    red[0].value.pop()
    red
    red[0].value
    red[0].value.pop(3)
    red
    red[0].value

__getitem__
~~~~~~~~~~~

.. ipython:: python

    red
    red[0].value
    red[0].value[2]

__setitem__
~~~~~~~~~~~

.. ipython:: python

    red
    red[0].value[2] = "1 + 1"
    red
    red[0].value

remove
~~~~~~

.. ipython:: python

    red
    red[0].value.remove(red[0].value[2])
    red
    red[0].value

index
~~~~~

.. ipython:: python

    red
    red[0].value
    red[0].value.index(red[0].value[2])

count
~~~~~

.. ipython:: python

    red
    red[0].value
    red[0].value.count(red[0].value[2])

len
~~~

.. ipython:: python

    red
    red[0].value
    len(red[0].value)

__delitem__
~~~~~~~~~~~

.. ipython:: python

    red
    del red[0].value[2]
    red
    red[0].value

in
~~

.. ipython:: python

    red
    red[0].value[2] in red[0].value

__iter__
~~~~~~~~

.. ipython:: python

    red
    for i in red[0].value:
        print(i.dumps())

__getslice__
~~~~~~~~~~~~

.. ipython:: python

    red
    red[0].value
    red[0].value[2:4]

__setslice__
~~~~~~~~~~~~

.. ipython:: python

    red
    red[0].value[2:4] = ["1 + 1", "a", "b", "c"]
    red
    red[0].value

__delslice__
~~~~~~~~~~~~

.. ipython:: python

    red
    red[0].value[2:5]
    del red[0].value[2:5]
    red
    red[0].value

Access the unproxified node list
--------------------------------

The unproxified node list is stored under the attribute :file:`node_list` of
the proxy list. **Be aware that, for now, the proxy won't detect if you
directly modify the unproxified node list, this will cause bugs if you modify
the unproxified list then use the proxy list directly**. So, for now, only use
one or the other.

.. ipython:: python

    red = RedBaron("[1, 2, 3]")
    red[0].value.node_list
    red[0].value

Omitting ".value"
-----------------

For convenience, and because this is a super common typo error, if a node has a
proxy list on its :file:`.value` attribute, you can omit to access it and the
method access will be automatically redirect to it.

This means that the 2 next lines are equivalent:

.. ipython:: python

    red[0]
    red[0].value.append("plop")
    red[0].append("plop")

CommaProxyList
--------------

CommaProxyList is the most generic and most obvious proxy list, all the examples
above are made using it.

It is used everywhere where values are separated by commas.

DotProxyList
------------

DotProxyList is nearly as generic as the CommaProxyList. The specific case of a
DotProxyList is that it is intelligent enough to not add a "." before a "call"
(:file:`(a, b=c, *d, **e)`) or a "getitem" (:file:`[foobar]`).

.. ipython:: python

    red = RedBaron("a.b(c).d[e]")
    red[0].value
    red[0].extend(["[stuff]", "f", "(g, h)"])
    red[0]
    red[0].value

It is used everywhere where values are separated by ".".

You can see a complete example with a DotProxyList, like for the CommaProxyList,
here: :doc:`dotproxylist`.

LineProxyList
-------------

LineProxyList is used to handle lines of code, it takes care to place the
correct endl node between and to set the correct indentation and not to break
the indentation of the next block (if there is one).

One particularity of LineProxyList is that it shows you explicitly the empty
line (while other proxy lists never show you formatting). This is done because
you'll often want to be able to manage those blank lines because you want to
put some space in your code or separate group of lines.

.. ipython:: python

    red = RedBaron("while 42:\n    stuff\n    other_stuff\n\n    there_is_an_empty_line_before_me")
    red
    red[0].value
    red[0].append("plouf")
    red
    red[0].value

You can see a complete example with a LineProxyList, like for the CommaProxyList,
here: :doc:`lineproxylist`.

DecoratorLineProxyList
----------------------

A DecoratorLineProxyList is exactly the same as a LineProxyList except it has
a small modification to indent decorators correctly. Just think of it as
a simple LineProxyList and everything will be fine.

*Don't forget to add the :file:`@` when you add a new decorator (omitting it
will raise an exception)*.

Example:

.. ipython:: python

    red = RedBaron("@plop\ndef stuff():\n    pass\n")
    red
    red[0].decorators.append("@plouf")
    red[0].decorators
    red

Next
~~~~

To learn about various helpers and features in RedBaron, read :doc:`other`.
Be sure to check the :file:`.replace()` method on that page as it can be very useful.