Skip to content

Commit

Permalink
Add rewrite fixer to remove Salt's __utils__ usage
Browse files Browse the repository at this point in the history
Signed-off-by: Pedro Algarvio <[email protected]>
  • Loading branch information
s0undt3ch committed Jun 23, 2022
1 parent 2423bef commit 2dfaf19
Show file tree
Hide file tree
Showing 4 changed files with 235 additions and 1 deletion.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "salt-rewrite"
version = "1.3.3"
version = "2.0.0"
description = "A set of Bowler code to rewrite parts of Salt"
authors = ["Pedro Algarvio <[email protected]>"]
license = "Apache-2.0"
Expand Down
1 change: 1 addition & 0 deletions src/saltrewrite/salt/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# pylint: disable=missing-module-docstring
from saltrewrite.salt import fix_docstrings
from saltrewrite.salt import fix_dunder_utils

__all__ = [modname for modname in list(globals()) if modname.startswith("fix_")]

Expand Down
89 changes: 89 additions & 0 deletions src/saltrewrite/salt/fix_dunder_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
"""
saltrewrite.salt.fix_docstrings
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@todo: add description
"""
import logging

from bowler import Query
from bowler import SYMBOL
from bowler import TOKEN
from bowler.types import Leaf
from bowler.types import Node
from fissix.fixer_util import Call
from fissix.fixer_util import Dot
from fissix.fixer_util import touch_import

log = logging.getLogger(__name__)


def rewrite(paths, interactive=False, silent=False):
"""
Rewrite the passed in paths
"""
(
Query(paths)
.select(
"""
(
dunder_call=power<
'__utils__'
trailer< '[' dunder_mod_func=any* ']' >
trailer< '(' function_arguments=any* ')' >
>
)
"""
)
.modify(fix_module_docstrings)
.execute(write=True, interactive=interactive, silent=silent)
)


def fix_module_docstrings(node, capture, filename):
"""
Automaticaly run fixes against docstrings
"""
if "dunder_mod_func" not in capture:
return
dunder_mod_func = capture["dunder_mod_func"][0].value.strip("'").strip('"')
utils_module, utils_module_funcname = dunder_mod_func.split(".")

# Make sure we import the right utils module
touch_import(None, f"salt.utils.{utils_module}", node)
log.info("Dunder Module Func: %r", dunder_mod_func)

# Un-parent the function arguments so we can add them to a new call
for leaf in capture["function_arguments"]:
leaf.parent = None

# Create the new function call
call_node = Call(
Leaf(TOKEN.NAME, utils_module_funcname, prefix=""),
capture["function_arguments"],
)

# Create replacement node
replacement = Node(
SYMBOL.power,
[
Leaf(TOKEN.NAME, "salt", prefix=capture["node"].prefix),
Node(
SYMBOL.trailer,
[
Dot(),
Leaf(TOKEN.NAME, "utils", prefix=""),
Dot(),
Leaf(TOKEN.NAME, utils_module, prefix=""),
Dot(),
call_node,
],
),
],
)
# Replace the whole node with the new function call
node.replace(replacement)


# pylint: enable=missing-function-docstring
144 changes: 144 additions & 0 deletions tests/salt/test_dunder_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
# pylint: disable=missing-module-docstring,missing-function-docstring,too-many-lines
import textwrap

from saltrewrite.salt import fix_dunder_utils


def test_fix_call_one_arg(tempfiles):
code = textwrap.dedent(
"""
import one.two
def one():
one.two.three("four")
__utils__["foo.bar"]("one")
"""
)
expected_code = textwrap.dedent(
"""
import one.two
import salt.utils.foo
def one():
one.two.three("four")
salt.utils.foo.bar("one")
"""
)
fpath = tempfiles.makepyfile(code, prefix="test_")
fix_dunder_utils.rewrite(fpath)
with open(fpath) as rfh:
new_code = rfh.read()
assert new_code == expected_code


def test_fix_call_multiple_args(tempfiles):
code = textwrap.dedent(
"""
import one.two
def one():
one.two.three("four")
__utils__["foo.bar"]("one", True, 1, 2.0)
"""
)
expected_code = textwrap.dedent(
"""
import one.two
import salt.utils.foo
def one():
one.two.three("four")
salt.utils.foo.bar("one", True, 1, 2.0)
"""
)
fpath = tempfiles.makepyfile(code, prefix="test_")
fix_dunder_utils.rewrite(fpath)
with open(fpath) as rfh:
new_code = rfh.read()
assert new_code == expected_code


def test_fix_call_keyword_arguments(tempfiles):
code = textwrap.dedent(
"""
import one.two
def one():
one.two.three("four")
__utils__["foo.bar"](one="one")
"""
)
expected_code = textwrap.dedent(
"""
import one.two
import salt.utils.foo
def one():
one.two.three("four")
salt.utils.foo.bar(one="one")
"""
)
fpath = tempfiles.makepyfile(code, prefix="test_")
fix_dunder_utils.rewrite(fpath)
with open(fpath) as rfh:
new_code = rfh.read()
assert new_code == expected_code


def test_fix_call_multiple_keyword_arguments(tempfiles):
code = textwrap.dedent(
"""
import one.two
def one():
one.two.three("four")
__utils__["foo.bar"](
one="one",
two="two"
)
"""
)
expected_code = textwrap.dedent(
"""
import one.two
import salt.utils.foo
def one():
one.two.three("four")
salt.utils.foo.bar(
one="one",
two="two")
"""
)
fpath = tempfiles.makepyfile(code, prefix="test_")
fix_dunder_utils.rewrite(fpath)
with open(fpath) as rfh:
new_code = rfh.read()
assert new_code == expected_code


def test_fix_call_mixed(tempfiles):
code = textwrap.dedent(
"""
import one.two
def one():
one.two.three("four")
__utils__["foo.bar"]("one", two="two")
"""
)
expected_code = textwrap.dedent(
"""
import one.two
import salt.utils.foo
def one():
one.two.three("four")
salt.utils.foo.bar("one", two="two")
"""
)
fpath = tempfiles.makepyfile(code, prefix="test_")
fix_dunder_utils.rewrite(fpath)
with open(fpath) as rfh:
new_code = rfh.read()
assert new_code == expected_code

0 comments on commit 2dfaf19

Please sign in to comment.