Skip to content
This repository was archived by the owner on Aug 8, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions bowler/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -224,3 +224,30 @@ def inner(filename: Filename) -> bool:
return any(filename.endswith(e) for e in ext)

return inner


def test_pattern(pattern, code):
"""
Utility function to test lib2to3 patterns.

Args:
pattern (str): The pattern to test.
code (str): The code to match against the pattern.

Returns:
list: A list of matches found in the code.
"""
from pprint import pprint
from fissix import pytree, pygram
from fissix.patcomp import PatternCompiler
from fissix.pgen2 import driver

d = driver.Driver(pygram.python_grammar.copy(), pytree.convert)
pc = PatternCompiler()

matches = []
pat = pc.compile_pattern(pattern)
for node in d.parse_string(code).pre_order():
for match in pat.generate_matches([node]):
matches.append(match)
return matches
34 changes: 34 additions & 0 deletions docs/basics-usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,37 @@ including all references:
```bash
bowler run rename_func.py -- foo bar
```

## Testing lib2to3 Patterns

When working with Bowler, understanding and testing `lib2to3` patterns can be challenging for new users. To make this process easier, you can use the following utility function to experiment with patterns in a REPL environment:

```python
from pprint import pprint

from fissix import pytree, pygram
from fissix.patcomp import PatternCompiler
from fissix.pgen2 import driver

d = driver.Driver(pygram.python_grammar.copy(), pytree.convert)
pc = PatternCompiler()

def test(pattern, code):
pat = pc.compile_pattern(pattern)
for node in d.parse_string(code).pre_order():
for match in pat.generate_matches([node]):
pprint(match)

# Example usage:
pattern="""
call=power<
any*
trailer<"." "foo">
trailer<"(" args=any* ")">
>
"""
# Prints out details about both the f.foo and bar.foo calls
test(pattern,'a = f.foo(123) + bar.foo("adf")\n')
```

This function allows you to quickly iterate and test patterns, making it easier to write and understand them. You can copy this function into your own scripts or REPL sessions to experiment with different patterns.