Skip to content

Commit 67234d0

Browse files
committed
update and fix a lot of stuff, including tests
1 parent 260acd0 commit 67234d0

File tree

14 files changed

+107
-71
lines changed

14 files changed

+107
-71
lines changed

.vscode/settings.json

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@
22
"cSpell.words": [
33
"codegpt"
44
],
5-
"python.testing.pytestArgs": [
6-
"next"
7-
],
85
"python.testing.unittestEnabled": false,
96
"python.testing.pytestEnabled": true
107
}

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Codegpt
22

3-
## 0.2.12
3+
## 0.2.13
44

55
A tool for using GPT just a little quicker. A nearly truly automated footgun. Learn how to revert with git before trying please.
66

@@ -27,7 +27,7 @@ Usage
2727
To try Codegpt, you can run the following command:
2828

2929
```bash
30-
codegpt do <instructions (quoted)> <filenames>
30+
codegpt do <instructions (quoted)> -f readme.md
3131
```
3232

3333
It can do basically anything. Try handing in some files for context and telling it to generate something new - SQL queries, new features, documentation, whatever.

pyproject.toml

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,24 @@ requires = ["poetry>=0.12"]
2121
build-backend = "poetry.masonry.api"
2222

2323
[tool.poetry.scripts]
24-
codegpt = "codegpt.main:app"
24+
codegpt = "src.main:app"
25+
26+
[tool.pytest]
27+
addopts = "--capture=fd --cov=my_module"
28+
29+
# Directory where cache files should be stored
30+
cache_dir = ".pytest_cache"
31+
32+
# List of plugins to load
33+
plugins = ["pytest-cov"]
34+
35+
# List of files or directories to ignore during testing
36+
norecursedirs = ["venv"]
37+
38+
# List of markers to exclude from test discovery
39+
markers = ["not_ready: mark tests that are not yet ready to be run"]
40+
41+
[tool.pytest.ini_options]
42+
pythonpath = ["src"]
43+
testpaths = ["tests"]
44+

pytest.ini

Lines changed: 0 additions & 3 deletions
This file was deleted.
File renamed without changes.
File renamed without changes.
File renamed without changes.

codegpt/gpt_interface.py renamed to src/gpt_interface.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,23 @@
33
import typer
44
from typing import Dict
55
from textwrap import dedent
6-
from codegpt.parse import parse_resp
6+
from parse import parse_resp
77

88
try:
99
nltk.data.find('tokenizers/punkt')
1010
except LookupError:
1111
typer.secho("Downloading punkt for nltk... Only once!", fg=typer.colors.GREEN, bold=True)
1212
nltk.download('punkt', quiet=True)
1313

14-
def confirm_send(prompt, max_tokens=4000, yes=False):
14+
def confirm_send(prompt, max_tokens=4000, yes=False, silent=False):
1515
tokens = nltk.word_tokenize(prompt)
1616

1717
#! Yeah this math is BS, closeish though...
1818
max_tokens = round(max_tokens - (7 / 4) * len(tokens))
1919

20-
if yes:
20+
if silent:
21+
pass
22+
elif yes:
2123
typer.secho(f"This prompt is {len(tokens)}ish tokens, GPT-3 can return {max_tokens}ish.", color=typer.colors.GREEN)
2224
else:
2325
typer.confirm(
@@ -65,7 +67,7 @@ def send_iffy_edit(prompt: str, code: Dict[str, str], clipboard: bool = False, y
6567
> <code line 1>
6668
> <code line n...>""")
6769

68-
max_tokens = confirm_send(full_prompt, yes=yes)
70+
max_tokens = confirm_send(full_prompt, yes=yes, silent=clipboard)
6971

7072
response = openai.Completion.create(
7173
engine="text-davinci-003",
@@ -75,8 +77,11 @@ def send_iffy_edit(prompt: str, code: Dict[str, str], clipboard: bool = False, y
7577
temperature=0.5,
7678
)
7779

78-
parsed = parse_resp(response)
79-
80+
try:
81+
parsed = parse_resp(response)
82+
except KeyError as e:
83+
print("ERROR: Response was malformed. Might still be usable, but is likely missing an explanation. Printing >\n")
84+
print(response["choices"][0]["text"])
8085
return parsed[0] if clipboard else parsed
8186

8287

codegpt/main.py renamed to src/main.py

Lines changed: 37 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
import os
22
import typer
33
import json
4+
import logging
45

5-
from codegpt import prompts
66

7-
from codegpt import gpt_interface as gpt
8-
from codegpt import files
7+
import gpt_interface as gpt
98

10-
from typing import List
9+
import prompts
10+
import files
11+
12+
from typing import List, Optional
1113
from pathlib import Path
1214

1315
app = typer.Typer(
@@ -23,10 +25,6 @@ def edit_file(
2325
...,
2426
help="Instruction to edit the file(s). Keep it short! Wrap with quotes.",
2527
),
26-
filenames: List[Path] = typer.Argument(
27-
["#CLIPBOARD"],
28-
help="List of filenames to edit. If not provided, will prompt for input.",
29-
),
3028
backup: bool = typer.Option(
3129
False,
3230
"--backup",
@@ -54,7 +52,8 @@ def edit_file(
5452
"-r",
5553
help="Output the raw 'code' from the response and exit the function.",
5654
),
57-
):
55+
filenames: Optional[List[Path]] = typer.Argument(None, help="File(s) to edit or for context."),
56+
):
5857
"""
5958
Do something given some code for context. Asking for documents, queries, etc. should work okay. Edits are iffy, but work a lot of the time.
6059
@@ -63,10 +62,13 @@ def edit_file(
6362
FILENAMES: list of filenames to edit. If not provided, will prompt for input.
6463
INSTRUCTION: the instruction to edit the file(s). Keep it short!
6564
"""
65+
66+
if raw_out or json_out:
67+
logging.basicConfig(level=logging.CRITICAL)
6668

6769
if not filenames and not raw_code:
6870
raise typer.BadParameter(
69-
"Either filenames or --raw-code (-c) must be provided."
71+
"Either --filenames (-f) or --raw-code (-c) must be provided."
7072
)
7173

7274
code = {"code": raw_code} if raw_code else files.load_text(filenames)
@@ -77,10 +79,12 @@ def edit_file(
7779
result = gpt.send_iffy_edit(instruction, code, yes=yes, clipboard=bool(raw_code))
7880

7981
if json_out:
80-
return json.dumps(result, sort_keys=True, indent=4)
82+
print(json.dumps(result, sort_keys=True, indent=4))
83+
return
8184

8285
if raw_out:
83-
return 'result["code"]'
86+
print(result['code'])
87+
return
8488

8589
files.write_text(result, backup)
8690
typer.secho("Done!", color=typer.colors.BRIGHT_BLUE)
@@ -89,9 +93,6 @@ def edit_file(
8993
@app.command("quick")
9094
def quick_edit_file(
9195
option: str = typer.Argument(..., help=f"{{{'|'.join(prompts.prompts.keys())}}}"),
92-
filenames: List[str] = typer.Argument(
93-
..., help="Enter the filenames to edit, separated by spaces"
94-
),
9596
backup: bool = typer.Option(
9697
False,
9798
"--backup",
@@ -105,9 +106,21 @@ def quick_edit_file(
105106
help="Don't ask for confirmation.",
106107
),
107108
raw_code: str = typer.Option(
108-
None, "--raw-code", "-c", help="Raw code to edit. Overrides filenames"
109+
None,
110+
"--raw-code",
111+
"-c",
112+
help="Raw code to edit. Overrides filenames. Use quotes to wrap the code.",
109113
),
110-
json_out: bool = typer.Option(False, "--json", "-j", help="Output in JSON format"),
114+
json_out: bool = typer.Option(
115+
False, "--json-out", "-j", help="Output the response in raw json format."
116+
),
117+
raw_out: bool = typer.Option(
118+
False,
119+
"--raw-out",
120+
"-r",
121+
help="Output the raw 'code' from the response and exit the function.",
122+
),
123+
filenames: Optional[List[Path]] = typer.Argument(None, help="File(s) to edit or for context."),
111124
):
112125
"""
113126
Edit a file using codegpt's built in prompts.
@@ -124,7 +137,7 @@ def quick_edit_file(
124137
raise typer.BadParameter(
125138
f"{option} is not a valid option. Must be one of {list(prompts.prompts.keys())}"
126139
)
127-
140+
128141
if not filenames and not raw_code:
129142
raise typer.BadParameter(
130143
"Either FILENAMES or --raw-code (-c) must be provided."
@@ -136,7 +149,12 @@ def quick_edit_file(
136149
)
137150

138151
if json_out:
139-
return json.dumps(result, sort_keys=True, indent=4)
152+
print(json.dumps(result, sort_keys=True, indent=4))
153+
return
154+
155+
if raw_out:
156+
print(result['code'])
157+
return
140158

141159
files.write_text(result, backup)
142160
typer.secho("Done!", color=typer.colors.BRIGHT_BLUE)

codegpt/parse.py renamed to src/parse.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
def parse_resp(response:dict):
2-
resp = response["choices"][0]["text"].splitlines()
2+
resp = response["choices"][0]["text"].strip().splitlines()
33

44
# Initialize an empty list to hold the dictionaries
55
out = []
@@ -35,4 +35,8 @@ def parse_resp(response:dict):
3535
# Add the final dictionary to the output list
3636
out.append(curr_dict)
3737

38+
# Backtop just in case this fails. Tests don't tend to use whole code, so it gets weird.
39+
if 'code' not in out:
40+
out = [{'code': response["choices"][0]["text"]}]
41+
3842
return out

0 commit comments

Comments
 (0)