rbtr-lang-python 2026.7.0.dev0__py3-none-any.whl → 2026.9.0.dev0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -24,7 +24,7 @@ from __future__ import annotations
24
24
 
25
25
  from typing import TYPE_CHECKING
26
26
 
27
- from rbtr.index.models import ImportMeta
27
+ from rbtr.domain.models import ImportMeta
28
28
  from rbtr.languages.registration import (
29
29
  ImportResolver,
30
30
  LanguageRegistration,
@@ -114,7 +114,7 @@ python = LanguageRegistration(
114
114
  index_files=frozenset({"__init__.py"}),
115
115
  source_roots=("", "src"),
116
116
  module_style=ModuleStyle.DOTTED,
117
- extraction_serial=5,
117
+ extraction_serial=6,
118
118
  )
119
119
 
120
120
  python.import_extractor(extract_import_meta)
@@ -46,6 +46,11 @@
46
46
  (import_statement
47
47
  name: (dotted_name) @_import_module) @import
48
48
 
49
+ ; `import numpy as np` nests the module inside the alias.
50
+ (import_statement
51
+ name: (aliased_import
52
+ name: (dotted_name) @_import_module)) @import
53
+
49
54
  (import_from_statement
50
55
  module_name: (dotted_name) @_import_module) @import
51
56
 
@@ -57,3 +62,7 @@
57
62
  (import_from_statement
58
63
  module_name: (relative_import
59
64
  (import_prefix) @_import_dots .)) @import
65
+
66
+ ; `from __future__ import annotations` has its own node type, and is an
67
+ ; import like any other.
68
+ (future_import_statement) @import
@@ -1,12 +1,12 @@
1
1
  [
2
2
  {
3
- "id": "8a4843f093a489a4",
4
3
  "blob_sha": "sha1",
5
4
  "file_path": "config.py",
6
5
  "kind": "comment",
7
- "name": "<anonymous>",
6
+ "name": "",
8
7
  "scope": "",
9
8
  "language": "python",
9
+ "file_language": "python",
10
10
  "content": "\"\"\"Configuration values for the greeter.\"\"\"",
11
11
  "line_start": 1,
12
12
  "line_end": 1,
@@ -15,16 +15,17 @@
15
15
  "names": "",
16
16
  "dots": "",
17
17
  "language_hint": ""
18
- }
18
+ },
19
+ "id": "5580e5551412db6c"
19
20
  },
20
21
  {
21
- "id": "e03be7d87e70e097",
22
22
  "blob_sha": "sha1",
23
23
  "file_path": "config.py",
24
24
  "kind": "variable",
25
25
  "name": "LOCALE",
26
26
  "scope": "",
27
27
  "language": "python",
28
+ "file_language": "python",
28
29
  "content": "LOCALE = \"en\"",
29
30
  "line_start": 3,
30
31
  "line_end": 3,
@@ -33,16 +34,17 @@
33
34
  "names": "",
34
35
  "dots": "",
35
36
  "language_hint": ""
36
- }
37
+ },
38
+ "id": "17132d64aac4d32b"
37
39
  },
38
40
  {
39
- "id": "90a5683217fcbf40",
40
41
  "blob_sha": "sha1",
41
42
  "file_path": "python.py",
42
43
  "kind": "comment",
43
- "name": "<anonymous>",
44
+ "name": "",
44
45
  "scope": "",
45
46
  "language": "python",
47
+ "file_language": "python",
46
48
  "content": "# Top-of-file banner comment, attached to nothing.\n# Second banner line, same block.",
47
49
  "line_start": 1,
48
50
  "line_end": 2,
@@ -51,16 +53,17 @@
51
53
  "names": "",
52
54
  "dots": "",
53
55
  "language_hint": ""
54
- }
56
+ },
57
+ "id": "b2af0545a26d7d13"
55
58
  },
56
59
  {
57
- "id": "bcb39bbdc83beb10",
58
60
  "blob_sha": "sha1",
59
61
  "file_path": "python.py",
60
62
  "kind": "comment",
61
- "name": "<anonymous>",
63
+ "name": "",
62
64
  "scope": "",
63
65
  "language": "python",
66
+ "file_language": "python",
64
67
  "content": "\"\"\"Greeter — formats greetings for named recipients.\n\nA sample module exercising the constructs the python plugin extracts:\nfunctions (sync, async, decorated), classes, methods (instance, property,\nstatic, class), module-level variables (including tuple unpacking and\nannotated assignments), nested functions (scoped to their parent), PEP 695\n`type` aliases (as classes), the import styles that carry distinct\nmetadata, and standalone / leading comments.\n\"\"\"",
65
68
  "line_start": 4,
66
69
  "line_end": 12,
@@ -69,16 +72,36 @@
69
72
  "names": "",
70
73
  "dots": "",
71
74
  "language_hint": ""
72
- }
75
+ },
76
+ "id": "31de03f2336983f1"
77
+ },
78
+ {
79
+ "blob_sha": "sha1",
80
+ "file_path": "python.py",
81
+ "kind": "import",
82
+ "name": "from __future__ import annotations",
83
+ "scope": "",
84
+ "language": "python",
85
+ "file_language": "python",
86
+ "content": "from __future__ import annotations",
87
+ "line_start": 14,
88
+ "line_end": 14,
89
+ "metadata": {
90
+ "module": "",
91
+ "names": "",
92
+ "dots": "",
93
+ "language_hint": ""
94
+ },
95
+ "id": "479d6b4b06efa7cc"
73
96
  },
74
97
  {
75
- "id": "86800a35eec519ec",
76
98
  "blob_sha": "sha1",
77
99
  "file_path": "python.py",
78
100
  "kind": "import",
79
101
  "name": "import os",
80
102
  "scope": "",
81
103
  "language": "python",
104
+ "file_language": "python",
82
105
  "content": "import os",
83
106
  "line_start": 16,
84
107
  "line_end": 16,
@@ -87,384 +110,425 @@
87
110
  "names": "",
88
111
  "dots": "",
89
112
  "language_hint": ""
90
- }
113
+ },
114
+ "id": "bc0241511702f5e8"
91
115
  },
92
116
  {
93
- "id": "99f2b46e21fdc9ed",
94
117
  "blob_sha": "sha1",
95
118
  "file_path": "python.py",
96
119
  "kind": "import",
97
- "name": "from functools import lru_cache",
120
+ "name": "import os.path as osp",
98
121
  "scope": "",
99
122
  "language": "python",
100
- "content": "from functools import lru_cache",
123
+ "file_language": "python",
124
+ "content": "import os.path as osp",
101
125
  "line_start": 17,
102
126
  "line_end": 17,
127
+ "metadata": {
128
+ "module": "os.path",
129
+ "names": "",
130
+ "dots": "",
131
+ "language_hint": ""
132
+ },
133
+ "id": "df492926528bfa30"
134
+ },
135
+ {
136
+ "blob_sha": "sha1",
137
+ "file_path": "python.py",
138
+ "kind": "import",
139
+ "name": "from functools import lru_cache",
140
+ "scope": "",
141
+ "language": "python",
142
+ "file_language": "python",
143
+ "content": "from functools import lru_cache",
144
+ "line_start": 18,
145
+ "line_end": 18,
103
146
  "metadata": {
104
147
  "module": "functools",
105
148
  "names": "lru_cache",
106
149
  "dots": "",
107
150
  "language_hint": ""
108
- }
151
+ },
152
+ "id": "51d6889362d6fbd8"
109
153
  },
110
154
  {
111
- "id": "a1111f0d689a9844",
112
155
  "blob_sha": "sha1",
113
156
  "file_path": "python.py",
114
157
  "kind": "import",
115
158
  "name": "from pathlib import Path as P",
116
159
  "scope": "",
117
160
  "language": "python",
161
+ "file_language": "python",
118
162
  "content": "from pathlib import Path as P",
119
- "line_start": 18,
120
- "line_end": 18,
163
+ "line_start": 19,
164
+ "line_end": 19,
121
165
  "metadata": {
122
166
  "module": "pathlib",
123
167
  "names": "Path",
124
168
  "dots": "",
125
169
  "language_hint": ""
126
- }
170
+ },
171
+ "id": "82596e40b5cddb35"
127
172
  },
128
173
  {
129
- "id": "df33b6fad729b242",
130
174
  "blob_sha": "sha1",
131
175
  "file_path": "python.py",
132
176
  "kind": "import",
133
177
  "name": "from .config import LOCALE",
134
178
  "scope": "",
135
179
  "language": "python",
180
+ "file_language": "python",
136
181
  "content": "from .config import LOCALE",
137
- "line_start": 20,
138
- "line_end": 20,
182
+ "line_start": 21,
183
+ "line_end": 21,
139
184
  "metadata": {
140
185
  "module": "config",
141
186
  "names": "LOCALE",
142
187
  "dots": "1",
143
188
  "language_hint": ""
144
- }
189
+ },
190
+ "id": "2ed24d12b7cfe30c"
145
191
  },
146
192
  {
147
- "id": "d81a70db3e82f25a",
148
193
  "blob_sha": "sha1",
149
194
  "file_path": "python.py",
150
195
  "kind": "class",
151
196
  "name": "GreetingList",
152
197
  "scope": "",
153
198
  "language": "python",
199
+ "file_language": "python",
154
200
  "content": "type GreetingList = list[str]",
155
- "line_start": 22,
156
- "line_end": 22,
201
+ "line_start": 23,
202
+ "line_end": 23,
157
203
  "metadata": {
158
204
  "module": "",
159
205
  "names": "",
160
206
  "dots": "",
161
207
  "language_hint": ""
162
- }
208
+ },
209
+ "id": "5a0b65ab15c43c79"
163
210
  },
164
211
  {
165
- "id": "39b5a904c304c9c9",
166
212
  "blob_sha": "sha1",
167
213
  "file_path": "python.py",
168
214
  "kind": "variable",
169
215
  "name": "DEFAULT_GREETING",
170
216
  "scope": "",
171
217
  "language": "python",
218
+ "file_language": "python",
172
219
  "content": "DEFAULT_GREETING = \"Hello\"",
173
- "line_start": 24,
174
- "line_end": 24,
220
+ "line_start": 25,
221
+ "line_end": 25,
175
222
  "metadata": {
176
223
  "module": "",
177
224
  "names": "",
178
225
  "dots": "",
179
226
  "language_hint": ""
180
- }
227
+ },
228
+ "id": "662b56676dcd85d9"
181
229
  },
182
230
  {
183
- "id": "397202f732684d50",
184
231
  "blob_sha": "sha1",
185
232
  "file_path": "python.py",
186
233
  "kind": "variable",
187
234
  "name": "LOCALES",
188
235
  "scope": "",
189
236
  "language": "python",
237
+ "file_language": "python",
190
238
  "content": "LOCALES, FALLBACK = (\"en\", \"fr\"), \"en\"",
191
- "line_start": 25,
192
- "line_end": 25,
239
+ "line_start": 26,
240
+ "line_end": 26,
193
241
  "metadata": {
194
242
  "module": "",
195
243
  "names": "",
196
244
  "dots": "",
197
245
  "language_hint": ""
198
- }
246
+ },
247
+ "id": "89ac218f83d39f84"
199
248
  },
200
249
  {
201
- "id": "0ed9c20b3fe660be",
202
250
  "blob_sha": "sha1",
203
251
  "file_path": "python.py",
204
252
  "kind": "variable",
205
253
  "name": "FALLBACK",
206
254
  "scope": "",
207
255
  "language": "python",
256
+ "file_language": "python",
208
257
  "content": "LOCALES, FALLBACK = (\"en\", \"fr\"), \"en\"",
209
- "line_start": 25,
210
- "line_end": 25,
258
+ "line_start": 26,
259
+ "line_end": 26,
211
260
  "metadata": {
212
261
  "module": "",
213
262
  "names": "",
214
263
  "dots": "",
215
264
  "language_hint": ""
216
- }
265
+ },
266
+ "id": "f59fb45b47181f25"
217
267
  },
218
268
  {
219
- "id": "9ac255b17801a682",
220
269
  "blob_sha": "sha1",
221
270
  "file_path": "python.py",
222
271
  "kind": "variable",
223
272
  "name": "MAX_RECIPIENTS",
224
273
  "scope": "",
225
274
  "language": "python",
275
+ "file_language": "python",
226
276
  "content": "MAX_RECIPIENTS: int = 100",
227
- "line_start": 26,
228
- "line_end": 26,
277
+ "line_start": 27,
278
+ "line_end": 27,
229
279
  "metadata": {
230
280
  "module": "",
231
281
  "names": "",
232
282
  "dots": "",
233
283
  "language_hint": ""
234
- }
284
+ },
285
+ "id": "420c1c7134cac624"
235
286
  },
236
287
  {
237
- "id": "7f441b61192c0790",
238
288
  "blob_sha": "sha1",
239
289
  "file_path": "python.py",
240
290
  "kind": "comment",
241
- "name": "<anonymous>",
291
+ "name": "",
242
292
  "scope": "",
243
293
  "language": "python",
294
+ "file_language": "python",
244
295
  "content": "# trailing comment: not folded, its own chunk",
245
- "line_start": 26,
246
- "line_end": 26,
296
+ "line_start": 27,
297
+ "line_end": 27,
247
298
  "metadata": {
248
299
  "module": "",
249
300
  "names": "",
250
301
  "dots": "",
251
302
  "language_hint": ""
252
- }
303
+ },
304
+ "id": "9758c6cfb2e4fc86"
253
305
  },
254
306
  {
255
- "id": "faa176a42cc8b903",
256
307
  "blob_sha": "sha1",
257
308
  "file_path": "python.py",
258
309
  "kind": "comment",
259
- "name": "<anonymous>",
310
+ "name": "",
260
311
  "scope": "",
261
312
  "language": "python",
313
+ "file_language": "python",
262
314
  "content": "# Section: greeting helpers.\n# A standalone block between definitions.",
263
- "line_start": 28,
264
- "line_end": 29,
315
+ "line_start": 29,
316
+ "line_end": 30,
265
317
  "metadata": {
266
318
  "module": "",
267
319
  "names": "",
268
320
  "dots": "",
269
321
  "language_hint": ""
270
- }
322
+ },
323
+ "id": "1cd0a40dcf750dcf"
271
324
  },
272
325
  {
273
- "id": "b2c0884b8be95035",
274
326
  "blob_sha": "sha1",
275
327
  "file_path": "python.py",
276
328
  "kind": "function",
277
329
  "name": "format_greeting",
278
330
  "scope": "",
279
331
  "language": "python",
332
+ "file_language": "python",
280
333
  "content": "# Leading doc comment folded into format_greeting.\ndef format_greeting(name: str) -> str:\n \"\"\"Return a greeting for ``name`` in the configured locale.\"\"\"\n\n def normalise(raw: str) -> str:\n \"\"\"Trim and title-case a raw recipient name.\"\"\"\n return raw.strip().title()\n\n return f\"{DEFAULT_GREETING}, {normalise(name)} ({LOCALE})\"",
281
- "line_start": 32,
282
- "line_end": 40,
334
+ "line_start": 33,
335
+ "line_end": 41,
283
336
  "metadata": {
284
337
  "module": "",
285
338
  "names": "",
286
339
  "dots": "",
287
340
  "language_hint": ""
288
- }
341
+ },
342
+ "id": "07f780afe34f832f"
289
343
  },
290
344
  {
291
- "id": "a7a4d2b076bcecd6",
292
345
  "blob_sha": "sha1",
293
346
  "file_path": "python.py",
294
347
  "kind": "function",
295
348
  "name": "normalise",
296
349
  "scope": "format_greeting",
297
350
  "language": "python",
351
+ "file_language": "python",
298
352
  "content": "def normalise(raw: str) -> str:\n \"\"\"Trim and title-case a raw recipient name.\"\"\"\n return raw.strip().title()",
299
- "line_start": 36,
300
- "line_end": 38,
353
+ "line_start": 37,
354
+ "line_end": 39,
301
355
  "metadata": {
302
356
  "module": "",
303
357
  "names": "",
304
358
  "dots": "",
305
359
  "language_hint": ""
306
- }
360
+ },
361
+ "id": "640a3da9f90df1ab"
307
362
  },
308
363
  {
309
- "id": "4781f65b33434b65",
310
364
  "blob_sha": "sha1",
311
365
  "file_path": "python.py",
312
366
  "kind": "function",
313
367
  "name": "fetch_remote_greeting",
314
368
  "scope": "",
315
369
  "language": "python",
370
+ "file_language": "python",
316
371
  "content": "async def fetch_remote_greeting(url: str) -> str:\n \"\"\"Fetch a greeting template from a remote source.\"\"\"\n return os.environ.get(\"GREETING\", DEFAULT_GREETING)",
317
- "line_start": 43,
318
- "line_end": 45,
372
+ "line_start": 44,
373
+ "line_end": 46,
319
374
  "metadata": {
320
375
  "module": "",
321
376
  "names": "",
322
377
  "dots": "",
323
378
  "language_hint": ""
324
- }
379
+ },
380
+ "id": "8169bc94456142b8"
325
381
  },
326
382
  {
327
- "id": "512e3f71a402f3b7",
328
383
  "blob_sha": "sha1",
329
384
  "file_path": "python.py",
330
385
  "kind": "function",
331
386
  "name": "cached_default",
332
387
  "scope": "",
333
388
  "language": "python",
389
+ "file_language": "python",
334
390
  "content": "def cached_default() -> str:\n \"\"\"Cache and return the default greeting prefix.\"\"\"\n return DEFAULT_GREETING",
335
- "line_start": 49,
336
- "line_end": 51,
391
+ "line_start": 50,
392
+ "line_end": 52,
337
393
  "metadata": {
338
394
  "module": "",
339
395
  "names": "",
340
396
  "dots": "",
341
397
  "language_hint": ""
342
- }
398
+ },
399
+ "id": "eb0e1237e14c20cb"
343
400
  },
344
401
  {
345
- "id": "c509d883ae06d023",
346
402
  "blob_sha": "sha1",
347
403
  "file_path": "python.py",
348
404
  "kind": "class",
349
405
  "name": "Greeter",
350
406
  "scope": "",
351
407
  "language": "python",
408
+ "file_language": "python",
352
409
  "content": "class Greeter:\n \"\"\"Stateful greeter holding a prefix and recipient log.\"\"\"\n\n def __init__(self, prefix: str = DEFAULT_GREETING) -> None:\n self.prefix = prefix\n self._seen: list[str] = []\n\n def greet(self, name: str) -> str:\n \"\"\"Greet ``name`` and record the recipient.\"\"\"\n self._seen.append(name)\n return format_greeting(name)\n\n @property\n def seen(self) -> list[str]:\n \"\"\"Recipients greeted so far.\"\"\"\n return list(self._seen)\n\n @staticmethod\n def shout(message: str) -> str:\n \"\"\"Upper-case a message.\"\"\"\n return message.upper()\n\n @classmethod\n def default(cls) -> Greeter:\n \"\"\"Build a greeter with the default prefix.\"\"\"\n return cls(DEFAULT_GREETING)",
353
- "line_start": 54,
354
- "line_end": 79,
410
+ "line_start": 55,
411
+ "line_end": 80,
355
412
  "metadata": {
356
413
  "module": "",
357
414
  "names": "",
358
415
  "dots": "",
359
416
  "language_hint": ""
360
- }
417
+ },
418
+ "id": "7624e0c692fb11f2"
361
419
  },
362
420
  {
363
- "id": "f5316a1306021dbf",
364
421
  "blob_sha": "sha1",
365
422
  "file_path": "python.py",
366
423
  "kind": "method",
367
424
  "name": "__init__",
368
425
  "scope": "Greeter",
369
426
  "language": "python",
427
+ "file_language": "python",
370
428
  "content": "def __init__(self, prefix: str = DEFAULT_GREETING) -> None:\n self.prefix = prefix\n self._seen: list[str] = []",
371
- "line_start": 57,
372
- "line_end": 59,
429
+ "line_start": 58,
430
+ "line_end": 60,
373
431
  "metadata": {
374
432
  "module": "",
375
433
  "names": "",
376
434
  "dots": "",
377
435
  "language_hint": ""
378
- }
436
+ },
437
+ "id": "8b5737f1d5f8265a"
379
438
  },
380
439
  {
381
- "id": "04526264daec6180",
382
440
  "blob_sha": "sha1",
383
441
  "file_path": "python.py",
384
442
  "kind": "method",
385
443
  "name": "greet",
386
444
  "scope": "Greeter",
387
445
  "language": "python",
446
+ "file_language": "python",
388
447
  "content": "def greet(self, name: str) -> str:\n \"\"\"Greet ``name`` and record the recipient.\"\"\"\n self._seen.append(name)\n return format_greeting(name)",
389
- "line_start": 61,
390
- "line_end": 64,
448
+ "line_start": 62,
449
+ "line_end": 65,
391
450
  "metadata": {
392
451
  "module": "",
393
452
  "names": "",
394
453
  "dots": "",
395
454
  "language_hint": ""
396
- }
455
+ },
456
+ "id": "966765d257a7ffce"
397
457
  },
398
458
  {
399
- "id": "404ed4eb32f154f2",
400
459
  "blob_sha": "sha1",
401
460
  "file_path": "python.py",
402
461
  "kind": "method",
403
462
  "name": "seen",
404
463
  "scope": "Greeter",
405
464
  "language": "python",
465
+ "file_language": "python",
406
466
  "content": "def seen(self) -> list[str]:\n \"\"\"Recipients greeted so far.\"\"\"\n return list(self._seen)",
407
- "line_start": 67,
408
- "line_end": 69,
467
+ "line_start": 68,
468
+ "line_end": 70,
409
469
  "metadata": {
410
470
  "module": "",
411
471
  "names": "",
412
472
  "dots": "",
413
473
  "language_hint": ""
414
- }
474
+ },
475
+ "id": "c748f4dd7a7d49ff"
415
476
  },
416
477
  {
417
- "id": "4174241e8ca95cc9",
418
478
  "blob_sha": "sha1",
419
479
  "file_path": "python.py",
420
480
  "kind": "method",
421
481
  "name": "shout",
422
482
  "scope": "Greeter",
423
483
  "language": "python",
484
+ "file_language": "python",
424
485
  "content": "def shout(message: str) -> str:\n \"\"\"Upper-case a message.\"\"\"\n return message.upper()",
425
- "line_start": 72,
426
- "line_end": 74,
486
+ "line_start": 73,
487
+ "line_end": 75,
427
488
  "metadata": {
428
489
  "module": "",
429
490
  "names": "",
430
491
  "dots": "",
431
492
  "language_hint": ""
432
- }
493
+ },
494
+ "id": "d3d098dc03b10302"
433
495
  },
434
496
  {
435
- "id": "b4873c720ebf2b3b",
436
497
  "blob_sha": "sha1",
437
498
  "file_path": "python.py",
438
499
  "kind": "method",
439
500
  "name": "default",
440
501
  "scope": "Greeter",
441
502
  "language": "python",
503
+ "file_language": "python",
442
504
  "content": "def default(cls) -> Greeter:\n \"\"\"Build a greeter with the default prefix.\"\"\"\n return cls(DEFAULT_GREETING)",
443
- "line_start": 77,
444
- "line_end": 79,
505
+ "line_start": 78,
506
+ "line_end": 80,
445
507
  "metadata": {
446
508
  "module": "",
447
509
  "names": "",
448
510
  "dots": "",
449
511
  "language_hint": ""
450
- }
512
+ },
513
+ "id": "e64ddefa4df1e58f"
451
514
  },
452
515
  {
453
- "id": "290aeaf830254689",
454
516
  "blob_sha": "sha1",
455
517
  "file_path": "python.py",
456
518
  "kind": "function",
457
519
  "name": "config_path",
458
520
  "scope": "",
459
521
  "language": "python",
522
+ "file_language": "python",
460
523
  "content": "def config_path() -> P:\n \"\"\"Return the path to the greeter config file.\"\"\"\n return P.home() / \".greeter\"",
461
- "line_start": 82,
462
- "line_end": 84,
524
+ "line_start": 83,
525
+ "line_end": 85,
463
526
  "metadata": {
464
527
  "module": "",
465
528
  "names": "",
466
529
  "dots": "",
467
530
  "language_hint": ""
468
- }
531
+ },
532
+ "id": "64cbb79e676b4e9d"
469
533
  }
470
534
  ]
@@ -14,6 +14,7 @@ metadata, and standalone / leading comments.
14
14
  from __future__ import annotations
15
15
 
16
16
  import os
17
+ import os.path as osp
17
18
  from functools import lru_cache
18
19
  from pathlib import Path as P
19
20
 
@@ -9,8 +9,8 @@ from __future__ import annotations
9
9
 
10
10
  from pytest_cases import parametrize_with_cases
11
11
 
12
+ from rbtr.domain.models import ChunkKind, ImportMeta
12
13
  from rbtr.git import FileEntry
13
- from rbtr.index.models import ChunkKind, ImportMeta
14
14
  from rbtr.languages.extract import extract_file
15
15
 
16
16
 
@@ -108,3 +108,31 @@ a, b = compute()
108
108
  variables = [c for c in chunks if c.kind == ChunkKind.VARIABLE]
109
109
  assert {c.name for c in variables} == {"a", "b"}
110
110
  assert all(c.content.strip() == "a, b = compute()" for c in variables)
111
+
112
+
113
+ def test_python_future_import_is_an_import() -> None:
114
+ """`from __future__ import annotations` is an import like any other.
115
+
116
+ The grammar gives it its own node type, so a query matching only
117
+ `import_statement` and `import_from_statement` leaves it in no chunk.
118
+ """
119
+ src = """\
120
+ from __future__ import annotations
121
+
122
+ import os
123
+ """
124
+ chunks = list(extract_file(FileEntry("input", "sha1", src.encode()), "python"))
125
+ imports = [c.content for c in chunks if c.kind == ChunkKind.IMPORT]
126
+ assert "from __future__ import annotations" in imports
127
+
128
+
129
+ def test_python_aliased_import_is_an_import() -> None:
130
+ """`import numpy as np` is an import of `numpy`.
131
+
132
+ The grammar nests the module inside an `aliased_import`, so a pattern
133
+ matching only a bare `dotted_name` leaves the statement in no chunk.
134
+ """
135
+ src = "import numpy as np\n"
136
+ chunks = list(extract_file(FileEntry("input", "sha1", src.encode()), "python"))
137
+ imports = [(c.metadata.module, c.content) for c in chunks if c.kind == ChunkKind.IMPORT]
138
+ assert imports == [("numpy", "import numpy as np")]
@@ -12,8 +12,8 @@ from typing import TYPE_CHECKING
12
12
  import pytest
13
13
  from tree_sitter import Parser
14
14
 
15
+ from rbtr.domain.models import Chunk, ChunkKind, Edge
15
16
  from rbtr.git import FileEntry
16
- from rbtr.index.models import Chunk, ChunkKind, Edge
17
17
  from rbtr.languages.edges import build_resolution_map, infer_import_edges
18
18
  from rbtr.languages.extract import extract_file
19
19
  from rbtr.languages.manager import get_manager
@@ -0,0 +1,68 @@
1
+ Metadata-Version: 2.4
2
+ Name: rbtr-lang-python
3
+ Version: 2026.9.0.dev0
4
+ Summary: rbtr — Python language plugin
5
+ Keywords: code-search,code-index,tree-sitter,static-analysis,semantic-search,developer-tools,python
6
+ Author: Alejandro Giacometti
7
+ Author-email: Alejandro Giacometti <alejandro.giacometti@gmail.com>
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Programming Language :: Python
13
+ Classifier: Programming Language :: Python :: 3 :: Only
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Classifier: Topic :: Software Development :: Libraries
16
+ Classifier: Topic :: Text Processing :: Indexing
17
+ Classifier: Typing :: Typed
18
+ Requires-Dist: rbtr==2026.9.0.dev0
19
+ Requires-Dist: tree-sitter-python
20
+ Requires-Python: >=3.13
21
+ Project-URL: Homepage, https://github.com/janrito/rbtr
22
+ Project-URL: Repository, https://github.com/janrito/rbtr
23
+ Project-URL: Documentation, https://github.com/janrito/rbtr/tree/main/packages/rbtr-lang-python#readme
24
+ Project-URL: Issues, https://github.com/janrito/rbtr/issues
25
+ Project-URL: Changelog, https://github.com/janrito/rbtr/releases
26
+ Description-Content-Type: text/markdown
27
+
28
+ # rbtr-lang-python
29
+
30
+ Python support for [rbtr]. A **default** plugin — installed with rbtr
31
+ itself (`pip install rbtr`).
32
+
33
+ [rbtr]: https://github.com/janrito/rbtr/tree/main/packages/rbtr#readme
34
+
35
+ ## What it ingests
36
+
37
+ - **Functions & methods** — `def` / `async def`; methods are scoped to their
38
+ enclosing class.
39
+ - **Classes** — class definitions (which also form a scope for their members).
40
+ - **Variables** — module-level assignments, including flat tuple unpacking.
41
+ Function locals and class attributes stay within their enclosing chunk.
42
+ - **Imports** — `import` and `from … import` (relative, aliased, multi-name)
43
+ → import chunks with resolved module + names, for cross-file edges.
44
+
45
+ A symbol's docstring (the leading `"""…"""`) is folded into its chunk content.
46
+
47
+ ## Chunks produced
48
+
49
+ ```python
50
+ def greet(name): ... # function "greet"
51
+
52
+
53
+ class User: # class "User"
54
+ def save(self): ... # method "save", scope "User"
55
+
56
+
57
+ MAX = 100 # variable "MAX"
58
+ from .utils import helper # import, metadata {module: ".utils", names: "helper"}
59
+ ```
60
+
61
+ ## Embedded / injected chunks
62
+
63
+ None of its own — Python is embedded *by* Markdown fenced code blocks, which
64
+ delegate ` ```python ` blocks here.
65
+
66
+ ## Grammar & dependencies
67
+
68
+ Uses the `tree-sitter-python` grammar. No dependency on other language plugins.
@@ -0,0 +1,19 @@
1
+ rbtr_lang_python/__init__.py,sha256=mdH22CFTQNelM0_lyVdigVKZOL4ErqZoCFVDc01DvHE,38
2
+ rbtr_lang_python/plugin.py,sha256=xfmZe5Ri31qpDwtJh6-c3QEsdZjiKVmJHw2HL711qCY,4158
3
+ rbtr_lang_python/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ rbtr_lang_python/python.scm,sha256=htAU-JmLxVCCYDjTRbVA0AS8pdn5S0NvYBZGQP-Ljns,1885
5
+ rbtr_lang_python/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
+ rbtr_lang_python/tests/__snapshots__/test_samples/test_edges_match_snapshot.json,sha256=7KeVtn7c62Hfz8Kv3p-Tp8Q88IMympsICYe935jDXwc,77
7
+ rbtr_lang_python/tests/__snapshots__/test_samples/test_extraction_matches_snapshot.json,sha256=YSq5jKsqyQCclP-mQZo6q6s4rW9qgeKpqRRGE1VjSYc,14301
8
+ rbtr_lang_python/tests/cases_docstrings.py,sha256=zqIjJHom1mSP0X42RpfsFf4jjrPSrM3X7jd7pMQeaxQ,4851
9
+ rbtr_lang_python/tests/cases_extraction.py,sha256=dlGp-_M-BB1TQYG5w6BSXP2F0qfaPqa0mhC1I_rMG2Y,14436
10
+ rbtr_lang_python/tests/samples/python/config.py,sha256=vq19QIAEQ4RSj5JNq5sprVVMACq7nwgEZ6ikCFpHnpM,59
11
+ rbtr_lang_python/tests/samples/python/python.py,sha256=lMu2NtzCbIqgLp-LZX6aVQ3wEs4-cGTfAhkFAtRXNwM,2464
12
+ rbtr_lang_python/tests/test_docstrings.py,sha256=YvjbJVWsASmSmEBGTJUgYaCeQqgHoxzyisEsplQg95U,2081
13
+ rbtr_lang_python/tests/test_extraction.py,sha256=_O2XO0RhTgxW7_V3BDl-QMftowb3I5Z2Ak9nVUKRk6I,5674
14
+ rbtr_lang_python/tests/test_samples.py,sha256=hSQqLwJX9sZQRJBOthev3efHSx0TNmOtTER-7RxOGwY,2827
15
+ rbtr_lang_python-2026.9.0.dev0.dist-info/licenses/LICENSE,sha256=3LvNTMhogXUXkHsDvTWaXdtGd9C-uuoIVD1ey8w9ITs,1077
16
+ rbtr_lang_python-2026.9.0.dev0.dist-info/WHEEL,sha256=-i9oRNYVXXZJUIYl5zclLIg6onEb0NLibTX34uln84w,81
17
+ rbtr_lang_python-2026.9.0.dev0.dist-info/entry_points.txt,sha256=RNfHUZ0LplE85FNOnadS_BV0BM1jhRtsz_qPal60sTk,58
18
+ rbtr_lang_python-2026.9.0.dev0.dist-info/METADATA,sha256=WK5SIEYLJNSPz8hUM5zPA7lJLJ2iCTJiguuuv6nTJbs,2505
19
+ rbtr_lang_python-2026.9.0.dev0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: uv 0.11.28
2
+ Generator: uv 0.12.13
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Alejandro Giacometti
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -1,8 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: rbtr-lang-python
3
- Version: 2026.7.0.dev0
4
- Summary: rbtr — Python language plugin
5
- License-Expression: MIT
6
- Requires-Dist: rbtr==2026.7.0.dev0
7
- Requires-Dist: tree-sitter-python
8
- Requires-Python: >=3.13
@@ -1,18 +0,0 @@
1
- rbtr_lang_python/__init__.py,sha256=mdH22CFTQNelM0_lyVdigVKZOL4ErqZoCFVDc01DvHE,38
2
- rbtr_lang_python/plugin.py,sha256=FTnc6Vt7nog5Z2WhK3G0AbWx3kRJ-CPMvIo4gsDVaVw,4157
3
- rbtr_lang_python/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
- rbtr_lang_python/python.scm,sha256=aIeFFw1i0nvcAWkdqJLB-B0N7FNiOdF0wKuKjxVmJiM,1602
5
- rbtr_lang_python/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- rbtr_lang_python/tests/__snapshots__/test_samples/test_edges_match_snapshot.json,sha256=7KeVtn7c62Hfz8Kv3p-Tp8Q88IMympsICYe935jDXwc,77
7
- rbtr_lang_python/tests/__snapshots__/test_samples/test_extraction_matches_snapshot.json,sha256=I4jAqsjOvt5wLIda25Tk9BpoIt0Jv9mctTAx3q2DIN0,12687
8
- rbtr_lang_python/tests/cases_docstrings.py,sha256=zqIjJHom1mSP0X42RpfsFf4jjrPSrM3X7jd7pMQeaxQ,4851
9
- rbtr_lang_python/tests/cases_extraction.py,sha256=dlGp-_M-BB1TQYG5w6BSXP2F0qfaPqa0mhC1I_rMG2Y,14436
10
- rbtr_lang_python/tests/samples/python/config.py,sha256=vq19QIAEQ4RSj5JNq5sprVVMACq7nwgEZ6ikCFpHnpM,59
11
- rbtr_lang_python/tests/samples/python/python.py,sha256=Q2Ggu-RMMM_iIHpg_YttbBK835sQ1AcfQ86BYFxemw0,2442
12
- rbtr_lang_python/tests/test_docstrings.py,sha256=YvjbJVWsASmSmEBGTJUgYaCeQqgHoxzyisEsplQg95U,2081
13
- rbtr_lang_python/tests/test_extraction.py,sha256=4OGNGIE8rOMaB00jdr5UkwNtgFxmsBg8Fyj8LfJX2bs,4580
14
- rbtr_lang_python/tests/test_samples.py,sha256=lrT_iSY85rl1wNOMqpfwtUB4Ys2d5OKSRJrjTYenxnE,2826
15
- rbtr_lang_python-2026.7.0.dev0.dist-info/WHEEL,sha256=CoDSoyhtC_eO_tlxRYzsTraPv1fPJRXFx91k6ISeAvA,81
16
- rbtr_lang_python-2026.7.0.dev0.dist-info/entry_points.txt,sha256=RNfHUZ0LplE85FNOnadS_BV0BM1jhRtsz_qPal60sTk,58
17
- rbtr_lang_python-2026.7.0.dev0.dist-info/METADATA,sha256=LIJFl35OAPWU5JuQQ5zkiPnMJ75C3mnT_rZJ2Z-aXOU,226
18
- rbtr_lang_python-2026.7.0.dev0.dist-info/RECORD,,