Skip to content
This repository was archived by the owner on Apr 22, 2021. It is now read-only.

Commit 670bde9

Browse files
committed
Changes for final CR
Fixes from final CR Update to pyparsing 2.1.8 Adds build target Adds build target Moves testing utilities Increments version Minor Makefile change Fixes some issues that arose when writing patterns Version bump
1 parent 4f47f54 commit 670bde9

25 files changed

+89
-64
lines changed

Makefile

+7-2
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
all: dev pre-commit
44

55
dev: venv
6-
venv/bin/pip install -r requirements-dev.txt --upgrade
6+
venv/bin/pip install -r requirements-dev.txt
77
@echo ""
88
@echo "========================================"
99
@echo "Don't forget to source venv/bin/activate"
1010

1111
venv:
1212
test -s venv || { virtualenv -p python2.7 venv; }
13-
venv/bin/pip install -r requirements.txt --upgrade
13+
venv/bin/pip install -r requirements.txt
1414

1515
clean:
1616
find . -name '*.pyc' -delete
@@ -19,6 +19,8 @@ clean:
1919
rm -rf .tox
2020
rm -rf *.egg-info
2121
rm -rf venv
22+
rm -rf build
23+
rm -rf dist
2224

2325
pre-commit:
2426
@tox -e pre-commit -- install -f --install-hooks
@@ -30,3 +32,6 @@ test: pre-commit
3032

3133
docs:
3234
tox -e docs
35+
36+
build:
37+
python setup.py sdist bdist_wheel

README.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# Undebt
22

3-
Undebt is a fast, simple, reliable tool for performing massive, automated code refactoring used [@Yelp](https://github.com/Yelp). Undebt lets you define complex find-and-replace rules using simple, straightforward Python that can be applied quickly to an entire code base with a simple command.
3+
Undebt is a fast, straightforward, reliable tool for performing massive, automated code refactoring used [@Yelp](https://github.com/Yelp). Undebt lets you define complex find-and-replace rules using standard, straightforward Python that can be applied quickly to an entire code base with a simple command.
4+
5+
To learn about what Undebt is and why we created it, check out our [post on the Yelp Engineering Blog](http://engineeringblog.yelp.com/).
46

57
To get started using Undebt, install with
68
```

docs/source/cli.rst

+2-3
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,8 @@ Read it
3131
--pattern path, -p path
3232
paths to pattern definition files
3333
--extension ext, -e ext
34-
extensions of files to be modified when using
35-
searching a directory (exclude ".", e.g. "py" instead
36-
of ".py")
34+
extensions of files to be modified when searching a
35+
directory (exclude ".", e.g. "py" instead of ".py")
3736
--multiprocess processes, -m processes
3837
number of processes to run in parallel (default is 16)
3938
--verbose

docs/source/examples.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -145,5 +145,5 @@ In files where `from __future__ import unicode_literals` appears, removes unnece
145145
Example of:
146146

147147
- an advanced style pattern file making use of multi-pass parsing
148-
- `originalTextFor` to get make a grammar parse to the original text that matched it
148+
- `originalTextFor` to make grammar elements parse to the original text that matched them
149149
- `STRING` to match any valid string

docs/source/patterns.rst

+5-5
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ Undebt_: Pattern Files
77
Undebt requires a pattern file that describes what to replace and how to replace it. There are two different ways to write pattern files: basic style, and advanced style. Unless you know you need multi-pass parsing, you should use basic style by default.
88

99
Basic Style
10-
---------------
10+
-----------
1111

12-
When writing an basic style pattern, you must define the following names in your pattern file:
12+
If you don't know what style you should be using, you should be using basic style. When writing a basic style pattern, you must define the following names in your pattern file:
1313

1414
- `grammar` defines what pattern you want to replace, and must be a pyparsing_ grammar object.
1515
- `replace` is a function of one argument, the tokens produced by `grammar`, that returns the string they should be replaced with, or `None` to do nothing (this is the single-argument form—multi-argument is also allowed as documented `below`_).
@@ -24,9 +24,9 @@ That sounds complicated, but it's actually very simple. To start learning more,
2424
.. _`pattern utilities`: util.html
2525

2626
Advanced Style
27-
------------------
27+
--------------
2828

29-
When writing an advanced style pattern, you need only define one name:
29+
Unlike basic style, advanced style allows you to use custom multi-pass parsing—if that's not something you need, you should use basic style. When writing an advanced style pattern, you need only define one name:
3030

3131
- `patterns` is a list of `(grammar, replace)` tuples, where each tuple in the list is only run if the previous one succeeded
3232

@@ -58,4 +58,4 @@ Or equivalently but more succinctly::
5858
Multi-Argument Replace
5959
----------------------
6060

61-
In both styles, when writing a `replace` function, it is sometimes useful to have access to the location in and/or text of the original file. If your `replace` function takes two arguments, it will be passed `location, tokens`, and for three arguments, it will get `text, location, tokens`. This will work even if you are using one of the `tokens_as_list` or `tokens_as_dict` decorator.
61+
In both styles, when writing a `replace` function, it is sometimes useful to have access to the parsing location in the file and/or the text of the original file. If your `replace` function takes two arguments, it will be passed `location, tokens`, and for three arguments, it will get `text, location, tokens`. This will work even if you are using one of the `tokens_as_list` or `tokens_as_dict` decorators.

docs/source/util.rst

+8-4
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,13 @@ Returns the whitespace at the end of `text`.
4141

4242
Modifies a grammar element to always parse to the same fixed `output`.
4343

44+
**debug(item)**
45+
46+
Modifies a grammar element to print the tokens that it matches.
47+
4448
**attach(item, action)**
4549

46-
Modifies a grammar element to parse to the result of calling `action` on the tokens produced by that grammar element. Used to implement `condense`, `addspace`, and `fixto`.
50+
Modifies a grammar element to parse to the result of calling `action` on the tokens produced by that grammar element.
4751

4852
`undebt.pattern.common`
4953
-----------------------
@@ -90,12 +94,12 @@ Grammar elements that match different types of multi-line strings.
9094
**COMMA_IND, LPAREN_IND, IND_RPAREN**
9195
Same as `COMMA`, `LPAREN`, and `RPAREN`, but allow for an `INDENT` after (for `COMMA_IND` and `LPAREN_IND`) or before (for `IND_RPAREN`).
9296

93-
**NO_BS_NL**
94-
Matches a new line not preceded by a backslash.
95-
9697
**LINE_START**
9798
Matches the start of a line, either after a new line, or at the start of the file.
9899

100+
**NO_BS_NL**
101+
Matches a new line not preceded by a backslash.
102+
99103
**START_OF_FILE**
100104
Grammar element that only matches at the very beginning of the file.
101105

requirements.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
argparse==1.4.0
2-
pyparsing==2.1.7
2+
pyparsing==2.1.8

tests/__init__.py

-32
Original file line numberDiff line numberDiff line change
@@ -1,33 +1 @@
11
# -*- coding: utf-8 -*-
2-
from __future__ import absolute_import
3-
from __future__ import division
4-
from __future__ import print_function
5-
6-
import os.path
7-
8-
from undebt.pattern.interface import create_find_and_replace
9-
from undebt.pattern.interface import parse_grammar
10-
11-
12-
tests_inputs_directory = os.path.join(os.path.dirname(__file__), "inputs")
13-
14-
15-
def assert_parse(grammar, text, tokens_list, interval_list):
16-
assert len(tokens_list) == len(interval_list)
17-
expected = [(tokens_list[i],) + interval_list[i] for i in range(len(tokens_list))]
18-
raw_assert_parse(grammar, text, expected)
19-
20-
21-
def raw_assert_parse(grammar, text, expected):
22-
results = parse_grammar(grammar, text)
23-
assert len(results) == len(expected)
24-
assert expected == [(tokens.asList(), start, stop) for tokens, start, stop in results]
25-
26-
27-
def assert_transform(pattern, text, expected):
28-
assert not hasattr(pattern, "patterns"), "assert_transform only works with old/basic style patterns"
29-
find_and_replace = create_find_and_replace(pattern.grammar, pattern.replace)
30-
results = parse_grammar(find_and_replace, text)
31-
assert len(results) == len(expected)
32-
assert all(len(tokens) == 1 for tokens, _, _ in results)
33-
assert expected == [tokens.asList()[0] for tokens, _, _ in results]

tests/cmd/main_test.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@
77

88
import mock
99

10-
from tests import tests_inputs_directory
1110
from undebt.cmd.main import main
1211
from undebt.examples import method_to_function
1312

1413

14+
tests_inputs_directory = os.path.join(os.path.dirname(os.path.dirname(__file__)), "inputs")
15+
1516
method_to_function_path = os.path.splitext(method_to_function.__file__)[0] + ".py"
1617

1718
method_to_function_input_path = os.path.join(tests_inputs_directory, "method_to_function_input.txt")

tests/examples/attribute_to_function_test.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
from __future__ import division
44
from __future__ import print_function
55

6-
from tests import assert_transform
76
from undebt.cmd.logic import process
87
from undebt.examples import attribute_to_function
98
from undebt.pattern.interface import get_patterns
9+
from undebt.pattern.testing import assert_transform
1010

1111

1212
def test_simple():

tests/examples/class_inherit_object_test.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
from __future__ import division
44
from __future__ import print_function
55

6-
from tests import assert_transform
76
from undebt.cmd.logic import process
87
from undebt.examples import class_inherit_object
98
from undebt.pattern.interface import get_patterns
9+
from undebt.pattern.testing import assert_transform
1010

1111

1212
def test_no_parens():

tests/examples/dbl_quote_docstring_test.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
from __future__ import division
44
from __future__ import print_function
55

6-
from tests import assert_transform
76
from undebt.cmd.logic import process
87
from undebt.examples import dbl_quote_docstring
98
from undebt.pattern.interface import get_patterns
9+
from undebt.pattern.testing import assert_transform
1010

1111

1212
def test_actual_code():

tests/examples/exec_function_test.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
from __future__ import division
44
from __future__ import print_function
55

6-
from tests import assert_transform
76
from undebt.cmd.logic import process
87
from undebt.examples import exec_function
98
from undebt.pattern.interface import get_patterns
9+
from undebt.pattern.testing import assert_transform
1010

1111

1212
def test_globals():

tests/examples/hex_to_bitshift_test.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
from __future__ import division
44
from __future__ import print_function
55

6-
from tests import assert_transform
76
from undebt.cmd.logic import process
87
from undebt.examples import hex_to_bitshift
98
from undebt.pattern.interface import get_patterns
9+
from undebt.pattern.testing import assert_transform
1010

1111

1212
def test_simple():

tests/examples/method_to_function_test.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
from __future__ import division
44
from __future__ import print_function
55

6-
from tests import assert_transform
76
from undebt.cmd.logic import process
87
from undebt.examples import method_to_function
98
from undebt.pattern.interface import get_patterns
9+
from undebt.pattern.testing import assert_transform
1010

1111

1212
def test_simple():

tests/examples/nl_at_eof_test.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
from __future__ import division
44
from __future__ import print_function
55

6-
from tests import assert_transform
76
from undebt.cmd.logic import process
87
from undebt.examples import nl_at_eof
98
from undebt.pattern.interface import get_patterns
9+
from undebt.pattern.testing import assert_transform
1010

1111

1212
def test_match():

tests/examples/sqla_count_test.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
from __future__ import division
44
from __future__ import print_function
55

6-
from tests import assert_transform
76
from undebt.cmd.logic import process
87
from undebt.examples import sqla_count
98
from undebt.pattern.interface import get_patterns
9+
from undebt.pattern.testing import assert_transform
1010

1111

1212
def test_one_liner():

tests/pattern/common_test.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@
33
from __future__ import division
44
from __future__ import print_function
55

6-
from tests import assert_parse
76
from undebt.pattern.common import DOTTED_NAME
87
from undebt.pattern.common import INDENT
98
from undebt.pattern.common import NL_WHITE
109
from undebt.pattern.common import PARENS
1110
from undebt.pattern.common import STRING
1211
from undebt.pattern.common import WHITE
12+
from undebt.pattern.testing import assert_parse
1313

1414

1515
def test_INDENT():

tests/pattern/python_test.py

+11-1
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@
33
from __future__ import division
44
from __future__ import print_function
55

6-
from tests import assert_parse
76
from undebt.pattern.python import ATOM
7+
from undebt.pattern.python import BINARY_OP
88
from undebt.pattern.python import EXPR
99
from undebt.pattern.python import HEADER
1010
from undebt.pattern.python import OP
11+
from undebt.pattern.testing import assert_parse
1112

1213

1314
def test_OP():
@@ -33,6 +34,15 @@ def test_OP():
3334
)
3435

3536

37+
def test_BINARY_OP():
38+
assert_parse(
39+
grammar=BINARY_OP,
40+
text="==",
41+
tokens_list=[["=="]],
42+
interval_list=[(0, 2)],
43+
)
44+
45+
3646
def test_ATOM():
3747
assert_parse(
3848
grammar=ATOM,

tests/pattern/util_test.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from __future__ import division
44
from __future__ import print_function
55

6-
from tests import assert_parse
6+
from undebt.pattern.testing import assert_parse
77
from undebt.pattern.util import leading_whitespace
88
from undebt.pattern.util import quoted
99
from undebt.pattern.util import trailing_whitespace

undebt/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@
66

77
# this should be the only place where the version is kept, if you
88
# need to know the version somewhere else just import it from here
9-
__version__ = "0.1.0"
9+
__version__ = "0.2.1"

undebt/cmd/main.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ def _handle_arguments():
7070
'-e',
7171
metavar='ext',
7272
action='append',
73-
help='extensions of files to be modified when using searching a directory'
73+
help='extensions of files to be modified when searching a directory'
7474
' (exclude ".", e.g. "py" instead of ".py")')
7575
parser.add_argument(
7676
'--multiprocess', '-m', metavar='processes', type=int, default=16,

undebt/pattern/python.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
from undebt.pattern.util import condense
3131

3232

33-
ASSIGN_OP = Combine(Optional(Word("~%^&*-+|/")) + Literal("="))
33+
ASSIGN_OP = Combine((Word("~%^&*-+|/") | ~Literal("==")) + Literal("="))
3434

3535

3636
UNARY_OP = addspace(OneOrMore(

undebt/pattern/testing.py

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# -*- coding: utf-8 -*-
2+
from __future__ import absolute_import
3+
from __future__ import division
4+
from __future__ import print_function
5+
6+
from undebt.pattern.interface import create_find_and_replace
7+
from undebt.pattern.interface import parse_grammar
8+
9+
10+
def assert_parse(grammar, text, tokens_list, interval_list):
11+
"""Assert that grammar parses text to tokens_list on interval_list."""
12+
assert len(tokens_list) == len(interval_list)
13+
expected = [(tokens_list[i],) + interval_list[i] for i in range(len(tokens_list))]
14+
raw_assert_parse(grammar, text, expected)
15+
16+
17+
def raw_assert_parse(grammar, text, token_interval_list):
18+
"""Assert grammar parses text to expected tokens and intervals."""
19+
results = parse_grammar(grammar, text)
20+
assert len(results) == len(token_interval_list)
21+
assert token_interval_list == [(tokens.asList(), start, stop) for tokens, start, stop in results]
22+
23+
24+
def assert_transform(pattern, text, transformed_tokens):
25+
"""Assert grammar parses text to expected transformed tokens."""
26+
assert not hasattr(pattern, "patterns"), "assert_transform only works with basic style patterns"
27+
find_and_replace = create_find_and_replace(pattern.grammar, pattern.replace)
28+
results = parse_grammar(find_and_replace, text)
29+
assert len(results) == len(transformed_tokens)
30+
assert all(len(tokens) == 1 for tokens, _, _ in results)
31+
assert transformed_tokens == [tokens.asList()[0] for tokens, _, _ in results]

undebt/pattern/util.py

+5
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@ def condense(item):
3333
return attach(item, "".join)
3434

3535

36+
def debug(item):
37+
"""Modifies a grammar element to print whatever it matches."""
38+
return attach(item, lambda tokens: print(tokens))
39+
40+
3641
def quoted(string):
3742
"""Match a string containing the given string."""
3843
return originalTextFor(Combine("'" + string + "'") | Combine('"' + string + '"'))

0 commit comments

Comments
 (0)