diff --git a/Makefile b/Makefile index 4877dc4..89c2933 100644 --- a/Makefile +++ b/Makefile @@ -1,2 +1,10 @@ run: - python src/ruff_in_python/main.py \ No newline at end of file + python src/ruff_in_python/main.py + +lint: + ruff check . --fix & ruff format . +install: + pip install -e . + +test: + pytest -vv \ No newline at end of file diff --git a/README.md b/README.md index 8a6ecc5..c9b6bbb 100644 --- a/README.md +++ b/README.md @@ -13,8 +13,32 @@ linter.rs message.rs parser.rs +## Libraries used for 1st version of ruff +The first-ever version of Ruff used the following Rust packages + +fern: for logging +rayon: for parallelizing computation +clap: for cli argument parsing +serde: for serializing and deserializing data +rustpython: for parsing, uses the provided AST +colored: for adding colors to the terminal +walkdir: for walking a directory recursively +anyhow: Flexible concrete Error type built on std::error::Error + +## Libraries I used for the Python verrsion +logging: std logging library +?: parallel computation +typer: cli argument parsing +?: serialising +ast: Python native ast library +rich: color terminal +os/pathlib: walking directory +?: error +pytest: write simple tests + ## Rebuild with Rust Reference: Blog: https://compileralchemy.substack.com/p/ruff-internals-of-a-rust-backed-python Commit: + diff --git a/images/cli.png b/images/cli.png new file mode 100644 index 0000000..3e6bf3f Binary files /dev/null and b/images/cli.png differ diff --git a/images/note.md b/images/note.md new file mode 100644 index 0000000..171d3dd --- /dev/null +++ b/images/note.md @@ -0,0 +1 @@ +![alt text](cli.png) \ No newline at end of file diff --git a/src/ruff_in_python/cache.py b/src/ruff_in_python/cache.py new file mode 100644 index 0000000..e69de29 diff --git a/src/ruff_in_python/lib.py b/src/ruff_in_python/lib.py new file mode 100644 index 0000000..e69de29 diff --git a/src/ruff_in_python/linter.py b/src/ruff_in_python/linter.py new file mode 100644 index 0000000..e69de29 diff --git a/src/ruff_in_python/main.py b/src/ruff_in_python/main.py index c55a5ce..c200b46 100644 --- a/src/ruff_in_python/main.py +++ b/src/ruff_in_python/main.py @@ -1,7 +1,37 @@ -def main(name: str): - print(f"Hello {name}") +import logging +from rich.logging import RichHandler +logger = logging.getLogger() + +logging.basicConfig( + level="NOTSET", + format="%(message)s", + datefmt="[%X]", + handlers=[RichHandler(rich_tracebacks=True)], +) + + +def main(filepath: str = None): + if not filepath: + filepath = "tests/bar.py" + logger.info(f"flie path: {filepath}") + set_up_logging() + run_once(filepath) + + +def set_up_logging(): + logger.info("dummy: set up logging") + + +def run_once(filepath: str = None): + logger.info("run once") + logger.info("Identified files to lint in") + logger.info("Checked files in ") + logger.info("Found TODO errors") + errors = [] + for error in errors: + logger.warning(error) if __name__ == "__main__": - main("dummy") \ No newline at end of file + main("dummy") diff --git a/src/ruff_in_python/message.py b/src/ruff_in_python/message.py new file mode 100644 index 0000000..e69de29 diff --git a/src/ruff_in_python/parser.py b/src/ruff_in_python/parser.py new file mode 100644 index 0000000..b517d65 --- /dev/null +++ b/src/ruff_in_python/parser.py @@ -0,0 +1,15 @@ +import ast +from pathlib import Path + + +def pretty_print_ast(self): + # Monkeypatch so it's easier to visualise the ast module + return ast.dump(self, indent=2) + + +ast.Module.__repr__ = pretty_print_ast + + +def parse(path: Path): + with open(path) as f: + return ast.parse(f.read()) diff --git a/src/ruff_in_python/scratch.ipynb b/src/ruff_in_python/scratch.ipynb new file mode 100644 index 0000000..0da6041 --- /dev/null +++ b/src/ruff_in_python/scratch.ipynb @@ -0,0 +1,150 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "import ast" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "stmt = \"print(123)\"" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "parsed = ast.parse(stmt)" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Module(\n", + " body=[\n", + " Expr(\n", + " value=Call(\n", + " func=Name(id='print', ctx=Load()),\n", + " args=[\n", + " Constant(value=123)],\n", + " keywords=[]))],\n", + " type_ignores=[])\n" + ] + } + ], + "source": [ + "print(ast.dump(parsed, indent=2))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This works fine, but it's easier to make a pretty print function to avoid doing this everytime. Actually, in Python I can just monkeypatch the class to do this." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "ast.Module" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "type(parsed)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [], + "source": [ + "def pretty_print_ast(self):\n", + " return ast.dump(self, indent=2)\n", + "ast.Module.__repr__ = pretty_print_ast" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Module(\n", + " body=[\n", + " Expr(\n", + " value=Call(\n", + " func=Name(id='print', ctx=Load()),\n", + " args=[\n", + " Constant(value=123)],\n", + " keywords=[]))],\n", + " type_ignores=[])" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "parsed" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "kedro", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.14" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/tests/test_parse.py b/tests/test_parse.py new file mode 100644 index 0000000..90e3488 --- /dev/null +++ b/tests/test_parse.py @@ -0,0 +1,8 @@ +import ast +from ruff_in_python.parser import parse + + +def test_parser(): + stmt = "print(123)" + res = parse(stmt) + assert isinstance(res, ast.Module)