Skip to content

Commit

Permalink
changed to gpt-linter
Browse files Browse the repository at this point in the history
  • Loading branch information
eyalk11 committed Jul 24, 2023
1 parent 95140e3 commit 4137ef7
Show file tree
Hide file tree
Showing 11 changed files with 78 additions and 44 deletions.
20 changes: 11 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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,
Expand All @@ -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)


File renamed without changes.
2 changes: 2 additions & 0 deletions gpt_linter/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from .gptlinter import main
main()
8 changes: 0 additions & 8 deletions mypy_gpt/common.py → gpt_linter/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
18 changes: 9 additions & 9 deletions mypy_gpt/mypygpt.py → gpt_linter/gptlinter.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand All @@ -25,15 +25,15 @@
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
self.file = args.file
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)
Expand Down Expand Up @@ -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')
Expand Down Expand Up @@ -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__':
Expand Down
File renamed without changes.
20 changes: 9 additions & 11 deletions mypy_gpt/linter.py → gpt_linter/linter.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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:
Expand All @@ -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": ""}

18 changes: 18 additions & 0 deletions gpt_linter/logger.py
Original file line number Diff line number Diff line change
@@ -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)

24 changes: 24 additions & 0 deletions gpt_linter/singleton.py
Original file line number Diff line number Diff line change
@@ -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.
"""

2 changes: 0 additions & 2 deletions mypy_gpt/__main__.py

This file was deleted.

10 changes: 5 additions & 5 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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',
Expand Down

0 comments on commit 4137ef7

Please sign in to comment.