Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Script to add new rule file #123

Merged
merged 23 commits into from
Sep 10, 2020
Merged
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ build/
docs/source/rules/
coverage.xml
coverage_report.html
.idea/
52 changes: 51 additions & 1 deletion docs/source/build_a_lint_rule.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,56 @@
"Iteration order of attributes is the same as the order they appear in the source code.\n",
"In this case, that means visit_If_test is called before visit_If_body and visit_If_orelse.\n",
"\n",
"Use fixit's cli to generate a skeleton of adding a new rule file::\n",
"\n",
" $ python -m fixit.cli.add_new_rule # Creates new_rule.py at fixit/rules/new_rule.py\n",
" $ python -m fixit.cli.add_new_rule --path fixit/rules/my_rule.py # Creates rule file at path specified\n",
"\n",
"This will generate a rule file used to create and add new rule to fixit module."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"nbsphinx": "hidden"
},
"outputs": [],
"source": [
"import os\n",
"os.chdir(\"../../\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"pycharm": {
"name": "#%%\n"
}
},
"outputs": [],
"source": [
"! python3 -m fixit.cli.add_new_rule --path fixit/rules/my_rule.py"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"! cat fixit/rules/my_rule.py"
]
},
{
"cell_type": "raw",
"metadata": {
"raw_mimetype": "text/restructuredtext"
},
"source": [
"Now, you can add rule's functionality on top of above generated file. \n",
"\n",
"The Declarative Matcher API\n",
"===========================\n",
"\n",
Expand Down Expand Up @@ -323,7 +373,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.5"
"version": "3.7.3"
}
},
"nbformat": 4,
Expand Down
2 changes: 1 addition & 1 deletion docs/source/getting_started.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.5"
"version": "3.7.3"
}
},
"nbformat": 4,
Expand Down
95 changes: 95 additions & 0 deletions fixit/cli/add_new_rule.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# Copyright (c) Facebook, Inc. and its affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.

# Usage:
#
# $ python -m fixit.cli.add_new_rule --help
# $ python -m fixit.cli.add_new_rule
# $ python -m fixit.cli.add_new_rule --path fixit/rules/new_rule.py

import argparse
from pathlib import Path

from libcst.codemod._cli import invoke_formatter

from fixit.common.config import get_lint_config


_LICENCE = """# Copyright (c) Facebook, Inc. and its affiliates.
acharles7 marked this conversation as resolved.
Show resolved Hide resolved
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.

"""

_IMPORTS = """
acharles7 marked this conversation as resolved.
Show resolved Hide resolved
import libcst as cst
import libcst.matchers as m

from fixit import CstLintRule, InvalidTestCase as Invalid, ValidTestCase as Valid

"""

_TO_DOS = """
\"""
This is a model rule file for adding a new rule to fixit module
\"""

"""

_RULE_CLASS = """
class Rule(CstLintRule):
\"""
docstring or new_rule description
\"""

MESSAGE = "Enter rule description message"

VALID = [Valid("'example'")]

INVALID = [Invalid("'example'")]
"""


def is_path_exists(path: str) -> Path:
"""Check for valid path, if yes, return `Path` else raise `Error` """
filepath = Path(path)
if filepath.exists():
raise FileExistsError(f"{filepath} already exists")
elif not filepath.parent.exists():
raise TypeError(f"{filepath} is not a valid path, provide path with file name")
else:
return filepath


def create_rule_file(file_path: Path) -> None:
"""Create a new rule file."""
context = _LICENCE + _IMPORTS + _TO_DOS + _RULE_CLASS
acharles7 marked this conversation as resolved.
Show resolved Hide resolved
updated_context = invoke_formatter(get_lint_config().formatter, context)

with open(file_path, "w") as f:
f.write(updated_context)

print(f"Successfully created {file_path.name} rule file at {file_path.parent}")


def main() -> None:
parser = argparse.ArgumentParser(
description="Creates a skeleton of adding new rule file"
)
parser.add_argument(
"-p",
"--path",
type=is_path_exists,
default=Path("fixit/rules/new_rule.py"),
help="Path to add rule file, Default is fixit/rules/new_rule.py",
)

args = parser.parse_args()
create_rule_file(args.path)


if __name__ == "__main__":
main()