From 4137ef73e497841d126afadc620cc47c00cdaba4 Mon Sep 17 00:00:00 2001 From: "LAPTOP-G43MA5MO\\ekarni" Date: Mon, 24 Jul 2023 03:49:09 +0300 Subject: [PATCH] changed to gpt-linter --- README.md | 20 +++++++++------- {mypy_gpt => gpt_linter}/__init__.py | 0 gpt_linter/__main__.py | 2 ++ {mypy_gpt => gpt_linter}/common.py | 8 ------- .../mypygpt.py => gpt_linter/gptlinter.py | 18 +++++++------- {mypy_gpt => gpt_linter}/guide.py | 0 {mypy_gpt => gpt_linter}/linter.py | 20 +++++++--------- gpt_linter/logger.py | 18 ++++++++++++++ gpt_linter/singleton.py | 24 +++++++++++++++++++ mypy_gpt/__main__.py | 2 -- setup.py | 10 ++++---- 11 files changed, 78 insertions(+), 44 deletions(-) rename {mypy_gpt => gpt_linter}/__init__.py (100%) create mode 100644 gpt_linter/__main__.py rename {mypy_gpt => gpt_linter}/common.py (78%) rename mypy_gpt/mypygpt.py => gpt_linter/gptlinter.py (96%) rename {mypy_gpt => gpt_linter}/guide.py (100%) rename {mypy_gpt => gpt_linter}/linter.py (89%) create mode 100644 gpt_linter/logger.py create mode 100644 gpt_linter/singleton.py delete mode 100644 mypy_gpt/__main__.py diff --git a/README.md b/README.md index 99b4401..a6c8779 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,17 @@ -# mypy-gpt -Solve mypy errors using [guidance](https://github.com/microsoft/guidance) and gpt API. +# gpt-linter +Solve linter errors using [guidance](https://github.com/microsoft/guidance) and gpt API. It runs mypy on targeted file and then uses gpt to try to fix the issues (espcially good for minor nagging issues). Displays a diff file for the required changes and ask you if you want to apply. # Installation ``` -pip install mypy-gpt +pip install gpt-linter ``` it is generally better to install the master ``` -pip install git+https://github.com/eyalk11/mypy-gpt.git +pip install git+https://github.com/eyalk11/gpt-linter.git ``` You will need openai access token for it. @@ -22,19 +22,21 @@ $env:OPEN_AI_KEY = "sk-XXX" ``` Or ``` -OPEN_AI_KEY=sk-XXX python -m mypy_gpt ... +OPEN_AI_KEY=sk-XXX python -m gpt_linter ... ``` +Of course, mypy is required too. + # Usage See ``` -python -m mypy_gpt --help +python -m gpt_linter --help ``` A typical usage is ``` -python -m mypy_gpt --proj-path [PROJECT] [PYFILE] +python -m gpt_linter --proj-path [PROJECT] [PYFILE] ``` It then tries to get a list of fixes from the chat , prints them , and finally try to come up with an updated version of the solution. It then checks the final file again , showing you the errors after the change, and displayes a diff file. It asks you if you want to apply the changes, @@ -43,12 +45,12 @@ and reruns main if not all issues were resolved. If you want it to generate diff file, use: ``` -python -m mypy_gpt --proj-path [PROJECT] --no-color --dont-ask [PYFILE] > myfile.diff +python -m gpt_linter --proj-path [PROJECT] --no-color --dont-ask [PYFILE] > myfile.diff ``` For example: -![image](https://github.com/eyalk11/mypy-gpt/assets/72234965/ed4eebb2-b4a5-4cc5-ad02-4e2299a1ec20) +![image](https://github.com/eyalk11/gpt-linter/assets/72234965/ed4eebb2-b4a5-4cc5-ad02-4e2299a1ec20) diff --git a/mypy_gpt/__init__.py b/gpt_linter/__init__.py similarity index 100% rename from mypy_gpt/__init__.py rename to gpt_linter/__init__.py diff --git a/gpt_linter/__main__.py b/gpt_linter/__main__.py new file mode 100644 index 0000000..8ab7be6 --- /dev/null +++ b/gpt_linter/__main__.py @@ -0,0 +1,2 @@ +from .gptlinter import main +main() \ No newline at end of file diff --git a/mypy_gpt/common.py b/gpt_linter/common.py similarity index 78% rename from mypy_gpt/common.py rename to gpt_linter/common.py index 9a204f9..0b0c273 100644 --- a/mypy_gpt/common.py +++ b/gpt_linter/common.py @@ -4,14 +4,6 @@ import os from typing import Tuple, Iterable -def setup_logger(logger: logging.Logger, debug: bool) -> None: - logger.setLevel(logging.DEBUG if debug else logging.INFO) - log_format = "%(levelname)s - %(message)s" - formatter = logging.Formatter(log_format) - ch = logging.StreamHandler() - ch.setFormatter(formatter) - logger.handlers = [ch] - def generate_diff(original_content: str, new_content: str, path: str) -> Tuple[str, str]: try: from colorama import Fore, init diff --git a/mypy_gpt/mypygpt.py b/gpt_linter/gptlinter.py similarity index 96% rename from mypy_gpt/mypygpt.py rename to gpt_linter/gptlinter.py index 26fce8f..cc59a15 100644 --- a/mypy_gpt/mypygpt.py +++ b/gpt_linter/gptlinter.py @@ -5,12 +5,12 @@ import logging import xml.etree.ElementTree as ET -from mypy_gpt.common import setup_logger, generate_diff -from mypy_gpt.guide import Guidance -from mypy_gpt.linter import MyPyLinter +from gpt_linter.common import generate_diff +from gpt_linter.guide import Guidance +from gpt_linter.linter import MyPyLinter -logger=logging.getLogger('mypygpt') -logger.propagate=False +from gpt_linter.logger import Logger +logger=Logger() DEFAULT_MODEL = "gpt-3.5-turbo-16k" @@ -25,7 +25,7 @@ from typing import List, Dict, Any, Optional, Iterator -class MyPyGpt: +class GPTLinter: def __init__(self,args: argparse.Namespace): #move all the attributes of args to local variables self.args = args @@ -33,7 +33,7 @@ def __init__(self,args: argparse.Namespace): self.original_content = open(self.file, 'rt').read() self.debug = args.debug - self.linter = MyPyLinter(args.debug) + self.linter = MyPyLinter() def get_new_content(self,err_res: Dict[str, Any]) -> Optional[str]: fix_guide= Guidance.guide_for_fixes(self.args) @@ -105,7 +105,7 @@ def get_issues_string(self,issues: List[Dict[str, Any]]) -> Iterator[str]: yield st def main(self) -> None: - setup_logger(logger,self.debug) + logger.setup_logger(self.debug) if 'OPEN_AI_KEY' not in os.environ: logger.error('OPEN_AI_KEY not set') @@ -216,7 +216,7 @@ def main() -> None: if len(args.mypy_args) ==0: args.mypy_args = MYPYARGS - MyPyGpt(args).main() + GPTLinter(args).main() if __name__ == '__main__': diff --git a/mypy_gpt/guide.py b/gpt_linter/guide.py similarity index 100% rename from mypy_gpt/guide.py rename to gpt_linter/guide.py diff --git a/mypy_gpt/linter.py b/gpt_linter/linter.py similarity index 89% rename from mypy_gpt/linter.py rename to gpt_linter/linter.py index 7d3c9f2..0cd0a0e 100644 --- a/mypy_gpt/linter.py +++ b/gpt_linter/linter.py @@ -1,17 +1,15 @@ -import logging import os import re import subprocess from abc import ABCMeta, abstractmethod from typing import List, Dict, Any, Optional +from subprocess import CompletedProcess import pandas -from mypy_gpt.common import setup_logger - -logger = logging.getLogger('linter') -logger.propagate = False +from gpt_linter.logger import Logger +logger = Logger() class Linter(metaclass=ABCMeta): @abstractmethod @@ -47,8 +45,6 @@ def get_issues(self, args: Any, override_file: Optional[str] = None) -> List[Dic class MyPyLinter(Linter): - def __init__(self, debug: bool): - setup_logger(logger, debug) # for now def run_checker(self, file: str, additional_args: List[str], program_path: str, proj_path: str) -> str: # Construct the mypy command @@ -73,14 +69,13 @@ def run_checker(self, file: str, additional_args: List[str], program_path: str, [@-~] # Final byte ) ''', re.VERBOSE) - result: str = ansi_escape.sub('', output) + clean_output: str = ansi_escape.sub('', output) # Print the output - return result + return clean_output @staticmethod - def parse_line(line: str) -> None: + def parse_line(line: str) -> Dict[str, Any]: import re - # Extracting message, type, and line number using regular expressions pattern = r'(.+):(\d+): (\w+): (.+) \[(.*)\]' match = re.match(pattern, line) if not match: @@ -95,3 +90,6 @@ def parse_line(line: str) -> None: return {"Line Number": linenumber, "Error Type": error_type, "Message": message, "Category": sub_type} else: logger.debug(("No match found.", line)) + + return {"Line Number": "", "Error Type": "", "Message": "", "Category": ""} + diff --git a/gpt_linter/logger.py b/gpt_linter/logger.py new file mode 100644 index 0000000..3ebb85e --- /dev/null +++ b/gpt_linter/logger.py @@ -0,0 +1,18 @@ +import logging +from gpt_linter.singleton import Singleton +class Logger(metaclass=Singleton): + def __init__(self): + self.logger= logging.getLogger(__name__) + self.logger.propagate=False + + def setup_logger(self, debug: bool) -> None: + self.logger.setLevel(logging.DEBUG if debug else logging.INFO) + log_format = "%(levelname)s - %(message)s" + formatter = logging.Formatter(log_format) + ch = logging.StreamHandler() + ch.setFormatter(formatter) + self.logger.handlers = [ch] + + def __getattr__(self, attr): + return getattr(self.logger, attr) + diff --git a/gpt_linter/singleton.py b/gpt_linter/singleton.py new file mode 100644 index 0000000..661b365 --- /dev/null +++ b/gpt_linter/singleton.py @@ -0,0 +1,24 @@ +#Taken from autogpt +"""The singleton metaclass for ensuring only one instance of a class.""" +import abc + + +class Singleton(abc.ABCMeta, type): + """ + Singleton metaclass for ensuring only one instance of a class. + """ + + _instances = {} + + def __call__(cls, *args, **kwargs): + """Call method for the singleton metaclass.""" + if cls not in cls._instances: + cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs) + return cls._instances[cls] + + +class AbstractSingleton(abc.ABC, metaclass=Singleton): + """ + Abstract singleton class for ensuring only one instance of a class. + """ + diff --git a/mypy_gpt/__main__.py b/mypy_gpt/__main__.py deleted file mode 100644 index 0f77785..0000000 --- a/mypy_gpt/__main__.py +++ /dev/null @@ -1,2 +0,0 @@ -from .mypygpt import main -main() \ No newline at end of file diff --git a/setup.py b/setup.py index c5b1c98..ef56a6d 100644 --- a/setup.py +++ b/setup.py @@ -4,8 +4,8 @@ import pkg_resources import setuptools import pathlib -desc = 'Python minor issue resolver (mypy) using gpt by openai!' -long_desc = 'Solves mypy errors using guidance and GPT api. It runs mypy on targeted file and then uses gpt to try to fix the issues (espcially good for minor nagging issues). Displays a diff file for the required changes and ask you if you want to apply.' +desc = 'Python minor issue resolver using gpt by openai!' +long_desc = 'Solves linter errors using guidance and GPT api. It runs mypy(for now) on targeted file and then uses gpt to try to fix the issues (espcially good for minor nagging issues). Displays a diff file for the required changes and ask you if you want to apply.' with pathlib.Path('requirements.txt').open() as requirements_txt: install_requires = [ str(requirement) @@ -14,9 +14,9 @@ ] setup( - name='mypy-gpt', - version='1.0.6', - packages=['mypy_gpt'], + name='gpt-linter', + version='1.0.0', + packages=['gpt_linter'], url='https://github.com/eyalk11/mypy-gpt', license=' AGPL-3.0 license', author='ekarni',