Spaces:
Runtime error
Runtime error
mayureshagashe2105
commited on
Commit
•
808bf67
1
Parent(s):
4e54bd9
CLI tool
Browse files- .gitignore +3 -1
- TechdocsAPI/backend/core/Exceptions.py +3 -3
- TechdocsAPI/backend/models/inference.py +5 -1
- TechdocsAPI/backend/router.py +3 -7
- TechdocsAPI/backend/services/auth/ops.py +2 -3
- TechdocsAPI/backend/services/db/utils/DBQueries.py +0 -1
- frontend/pages/Code.py +2 -1
- techdocs/__init__.py +1 -0
- techdocs/cli.py +42 -22
- techdocs/dtypes.py +5 -0
- techdocs/ops.py +124 -0
- techdocs/utils/functools.py +45 -13
- techdocs/utils/subcommand_signatures.json +45 -0
- testing/DBQueries.py +47 -1
- testing/test.py +89 -0
.gitignore
CHANGED
@@ -15,4 +15,6 @@ tempCodeRunnerFile.py
|
|
15 |
#pypi files
|
16 |
build
|
17 |
dist
|
18 |
-
techdocs.egg-info
|
|
|
|
|
|
15 |
#pypi files
|
16 |
build
|
17 |
dist
|
18 |
+
techdocs.egg-info
|
19 |
+
|
20 |
+
test.py
|
TechdocsAPI/backend/core/Exceptions.py
CHANGED
@@ -13,7 +13,7 @@ class InvalidCredentialsException(Exception):
|
|
13 |
self.token_result.status = 'login_failed'
|
14 |
|
15 |
def __repr__(self):
|
16 |
-
return
|
17 |
|
18 |
class ExistingUserException(Exception):
|
19 |
def __init__(self, response_result: GeneralResponse):
|
@@ -27,7 +27,7 @@ class ExistingUserException(Exception):
|
|
27 |
self.response_result.message[0] = 'authenticated'
|
28 |
|
29 |
def __repr__(self):
|
30 |
-
return
|
31 |
|
32 |
class InfoNotFoundException(Exception):
|
33 |
def __init__(self, response_result: GeneralResponse, message: str):
|
@@ -42,4 +42,4 @@ class InfoNotFoundException(Exception):
|
|
42 |
self.response_result['message'].append(self.message)
|
43 |
|
44 |
def __repr__(self):
|
45 |
-
return
|
|
|
13 |
self.token_result.status = 'login_failed'
|
14 |
|
15 |
def __repr__(self):
|
16 |
+
return "exception.InvalidCredentialsException()"
|
17 |
|
18 |
class ExistingUserException(Exception):
|
19 |
def __init__(self, response_result: GeneralResponse):
|
|
|
27 |
self.response_result.message[0] = 'authenticated'
|
28 |
|
29 |
def __repr__(self):
|
30 |
+
return "exception.ExistingUserException()"
|
31 |
|
32 |
class InfoNotFoundException(Exception):
|
33 |
def __init__(self, response_result: GeneralResponse, message: str):
|
|
|
42 |
self.response_result['message'].append(self.message)
|
43 |
|
44 |
def __repr__(self):
|
45 |
+
return "exception.InfoNotFoundException()"
|
TechdocsAPI/backend/models/inference.py
CHANGED
@@ -3,4 +3,8 @@ from typing import List
|
|
3 |
from .generic import Base
|
4 |
|
5 |
class Inference(Base):
|
6 |
-
docstr:str
|
|
|
|
|
|
|
|
|
|
3 |
from .generic import Base
|
4 |
|
5 |
class Inference(Base):
|
6 |
+
docstr:str
|
7 |
+
|
8 |
+
class Generate(Base):
|
9 |
+
code_block:str
|
10 |
+
api_key:str
|
TechdocsAPI/backend/router.py
CHANGED
@@ -22,7 +22,6 @@ def api_home():
|
|
22 |
|
23 |
@app.get("/api/response_check", tags=["Resource Server"])
|
24 |
def api_response_check():
|
25 |
-
print("api_response_check")
|
26 |
response_result = GeneralResponse.get_instance(data={},
|
27 |
status="not_allowed",
|
28 |
message=["Not authenticated"]
|
@@ -38,13 +37,12 @@ def api_response_check():
|
|
38 |
response_result.message.append(db_msg)
|
39 |
|
40 |
except Exception as e:
|
41 |
-
|
42 |
|
43 |
return response_result
|
44 |
|
45 |
@app.post("/auth/signup", summary="Creates new user account", response_model=GeneralResponse, tags=["Auth Server"])
|
46 |
async def signup(response: UserAuth):
|
47 |
-
print("signup")
|
48 |
response_result = GeneralResponse.get_instance(data={},
|
49 |
status="not_allowed",
|
50 |
message=["Not authenticated"]
|
@@ -59,14 +57,12 @@ async def login(response:LoginCreds):
|
|
59 |
|
60 |
@app.put("/auth/regenerate_api_key",summary="Forget Password",response_model=APIKey,tags=["Auth Server"],dependencies=[Depends(JWTBearer())])
|
61 |
async def regenerate_api_key(access_token: str = Depends(JWTBearer())):
|
62 |
-
print("regenerate_api_key")
|
63 |
user_sub=Auth.get_user_credentials(access_token)
|
64 |
|
65 |
return ops_regenerate_api_key(user_sub)
|
66 |
|
67 |
@app.post("/api/inference", summary="Inference", response_model=Inference, tags=["Resource Server"], dependencies=[Depends(JWTBearer())])
|
68 |
-
async def inference(
|
69 |
-
print("inference")
|
70 |
user_sub=Auth.get_user_credentials(access_token)
|
71 |
|
72 |
-
return ops_inference(code_block,api_key,user_sub)
|
|
|
22 |
|
23 |
@app.get("/api/response_check", tags=["Resource Server"])
|
24 |
def api_response_check():
|
|
|
25 |
response_result = GeneralResponse.get_instance(data={},
|
26 |
status="not_allowed",
|
27 |
message=["Not authenticated"]
|
|
|
37 |
response_result.message.append(db_msg)
|
38 |
|
39 |
except Exception as e:
|
40 |
+
pass
|
41 |
|
42 |
return response_result
|
43 |
|
44 |
@app.post("/auth/signup", summary="Creates new user account", response_model=GeneralResponse, tags=["Auth Server"])
|
45 |
async def signup(response: UserAuth):
|
|
|
46 |
response_result = GeneralResponse.get_instance(data={},
|
47 |
status="not_allowed",
|
48 |
message=["Not authenticated"]
|
|
|
57 |
|
58 |
@app.put("/auth/regenerate_api_key",summary="Forget Password",response_model=APIKey,tags=["Auth Server"],dependencies=[Depends(JWTBearer())])
|
59 |
async def regenerate_api_key(access_token: str = Depends(JWTBearer())):
|
|
|
60 |
user_sub=Auth.get_user_credentials(access_token)
|
61 |
|
62 |
return ops_regenerate_api_key(user_sub)
|
63 |
|
64 |
@app.post("/api/inference", summary="Inference", response_model=Inference, tags=["Resource Server"], dependencies=[Depends(JWTBearer())])
|
65 |
+
async def inference(generate: Generate, access_token:str=Depends(JWTBearer())):
|
|
|
66 |
user_sub=Auth.get_user_credentials(access_token)
|
67 |
|
68 |
+
return ops_inference(generate.code_block,generate.api_key,user_sub)
|
TechdocsAPI/backend/services/auth/ops.py
CHANGED
@@ -3,6 +3,7 @@ from .utils.JWTBearer import *
|
|
3 |
from backend.models import *
|
4 |
from backend.services.db.utils.DBQueries import DBQueries
|
5 |
from backend.core.Exceptions import *
|
|
|
6 |
from backend import app
|
7 |
|
8 |
# import openai
|
@@ -101,9 +102,7 @@ def ops_inference(source_code:str,api_key:str,username:str):
|
|
101 |
|
102 |
llm_response = app.state.llmchain.run({"instruction": source_code_message})
|
103 |
|
104 |
-
docstring = Inference(docstr=llm_response)
|
105 |
-
print(docstring)
|
106 |
-
|
107 |
|
108 |
return docstring
|
109 |
|
|
|
3 |
from backend.models import *
|
4 |
from backend.services.db.utils.DBQueries import DBQueries
|
5 |
from backend.core.Exceptions import *
|
6 |
+
from backend.core.ExceptionHandlers import *
|
7 |
from backend import app
|
8 |
|
9 |
# import openai
|
|
|
102 |
|
103 |
llm_response = app.state.llmchain.run({"instruction": source_code_message})
|
104 |
|
105 |
+
docstring = Inference(docstr=llm_response)
|
|
|
|
|
106 |
|
107 |
return docstring
|
108 |
|
TechdocsAPI/backend/services/db/utils/DBQueries.py
CHANGED
@@ -13,7 +13,6 @@ class DBQueries:
|
|
13 |
f'({",".join(cols)}) '
|
14 |
'VALUES '
|
15 |
).format(table_name=table_name)
|
16 |
-
print(data)
|
17 |
if isinstance(data, list):
|
18 |
QUERY+="("+",".join(["%s" for _ in range(len(data[0]))])+")"
|
19 |
cursor.executemany(QUERY, data)
|
|
|
13 |
f'({",".join(cols)}) '
|
14 |
'VALUES '
|
15 |
).format(table_name=table_name)
|
|
|
16 |
if isinstance(data, list):
|
17 |
QUERY+="("+",".join(["%s" for _ in range(len(data[0]))])+")"
|
18 |
cursor.executemany(QUERY, data)
|
frontend/pages/Code.py
CHANGED
@@ -92,7 +92,8 @@ def code_page():
|
|
92 |
if st.button("🤖 Generate Documentation"):
|
93 |
if code_input:
|
94 |
headers['Authorization'] = f"Bearer {st.session_state.access_token}"
|
95 |
-
response = query_post(base_url + '/api/inference', headers=headers,
|
|
|
96 |
docstr = response.json()["docstr"]
|
97 |
comment_placeholder.subheader("Generated Documentation:")
|
98 |
comment_placeholder.markdown(f"<pre><code>{docstr}</code></pre>", unsafe_allow_html=True)
|
|
|
92 |
if st.button("🤖 Generate Documentation"):
|
93 |
if code_input:
|
94 |
headers['Authorization'] = f"Bearer {st.session_state.access_token}"
|
95 |
+
response = query_post(base_url + '/api/inference', headers=headers,
|
96 |
+
data=json.dumps({'code_block':code_input, 'api_key':API_KEY}))
|
97 |
docstr = response.json()["docstr"]
|
98 |
comment_placeholder.subheader("Generated Documentation:")
|
99 |
comment_placeholder.markdown(f"<pre><code>{docstr}</code></pre>", unsafe_allow_html=True)
|
techdocs/__init__.py
CHANGED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
__version__ = "0.1.0"
|
techdocs/cli.py
CHANGED
@@ -1,36 +1,56 @@
|
|
1 |
-
from .
|
2 |
|
3 |
-
import argparse
|
4 |
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
9 |
|
10 |
-
parser.add_argument('--api_key','-k',type=str,required=True,help='API key for Techdocs')
|
11 |
|
12 |
-
parser.add_argument('--username','-u',type=str,required=True,help='Username for Techdocs')
|
13 |
|
14 |
-
parser.add_argument('--password','-p',type=str,required=True,help='Password for Techdocs')
|
15 |
|
16 |
-
parser.add_argument('--dir','-d',type=str,required=True,help='Root directory to be documented')
|
17 |
|
18 |
-
parser.add_argument('--version','-v',action='version',version="%(prog)s 0.0.1")
|
19 |
|
20 |
-
args=parser.parse_args()
|
21 |
|
22 |
-
|
23 |
-
arg[0]:arg[1] for arg in args._get_kwargs()
|
24 |
-
}
|
25 |
|
26 |
-
data = {
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
|
31 |
-
config.update({"access_token":functools.get_access_token(data)})
|
32 |
|
33 |
-
parse.extract_functions_from_directory(config)
|
34 |
|
35 |
if __name__ == '__main__':
|
36 |
-
main()
|
|
|
1 |
+
from .ops import Ops
|
2 |
|
|
|
3 |
|
4 |
+
@Ops.configure_and_build_subcommand
|
5 |
+
def main(log_info: bool = False):
|
6 |
+
if log_info:
|
7 |
+
print(
|
8 |
+
"""
|
9 |
+
|
10 |
+
👋 Hi there! Welcome to techdocs. Here are some cool things you can do:
|
11 |
+
|
12 |
+
|
13 |
+
💫 try out a demo with or new GUI 🚀 and explore how to use the CLI:
|
14 |
+
|
15 |
+
➡️ https://techdocs.streamlit.app/
|
16 |
+
|
17 |
+
💫 signup here to get an API key 👤:
|
18 |
+
|
19 |
+
$ techdocs signup -u <username> -p <password> -e <email>
|
20 |
+
|
21 |
+
💫 use the line below to issue a new API key 🗝️:
|
22 |
+
|
23 |
+
$ techdocs apikey -u <username> -p <password>
|
24 |
+
|
25 |
+
💫 use the CLI to generate documentation for your project 📚:
|
26 |
+
|
27 |
+
$ techdocs generate -k <api_key> -u <username> -p <password> -d <directory>
|
28 |
+
|
29 |
+
"""
|
30 |
+
)
|
31 |
|
32 |
+
# parser.add_argument('--api_key','-k',type=str,required=True,help='API key for Techdocs')
|
33 |
|
34 |
+
# parser.add_argument('--username','-u',type=str,required=True,help='Username for Techdocs')
|
35 |
|
36 |
+
# parser.add_argument('--password','-p',type=str,required=True,help='Password for Techdocs')
|
37 |
|
38 |
+
# parser.add_argument('--dir','-d',type=str,required=True,help='Root directory to be documented')
|
39 |
|
40 |
+
# # parser.add_argument('--version','-v',action='version',version="%(prog)s 0.0.1")
|
41 |
|
42 |
+
# args=parser.parse_args()
|
43 |
|
44 |
+
|
|
|
|
|
45 |
|
46 |
+
# data = {
|
47 |
+
# "username":config['username'],
|
48 |
+
# "password":config['password']
|
49 |
+
# }
|
50 |
|
51 |
+
# config.update({"access_token":functools.get_access_token(data)})
|
52 |
|
53 |
+
# parse.extract_functions_from_directory(config)
|
54 |
|
55 |
if __name__ == '__main__':
|
56 |
+
main()
|
techdocs/dtypes.py
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
data_types = {'str': str,
|
2 |
+
'int': int,
|
3 |
+
'float': float,
|
4 |
+
'bool': bool
|
5 |
+
}
|
techdocs/ops.py
ADDED
@@ -0,0 +1,124 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import argparse
|
2 |
+
import json
|
3 |
+
from typing import Dict, List, Optional, Any, Callable
|
4 |
+
|
5 |
+
import techdocs
|
6 |
+
from .dtypes import data_types
|
7 |
+
from .utils.functools import *
|
8 |
+
from .utils.parse import *
|
9 |
+
|
10 |
+
|
11 |
+
parser = argparse.ArgumentParser(
|
12 |
+
description='Code documentation generation',
|
13 |
+
epilog="Thanks for using Techdocs")
|
14 |
+
subparsers = parser.add_subparsers(help='subcommands')
|
15 |
+
|
16 |
+
|
17 |
+
def depends_login(func: Callable):
|
18 |
+
def update_config(cls: Any, config: Dict[str, Any]):
|
19 |
+
data = {
|
20 |
+
"username":config['username'],
|
21 |
+
"password":config['password']
|
22 |
+
}
|
23 |
+
|
24 |
+
config.update({"access_token":get_access_token(data)})
|
25 |
+
return func(cls, config)
|
26 |
+
return update_config
|
27 |
+
|
28 |
+
|
29 |
+
class _SubCommand:
|
30 |
+
def __init__(self, name: str, help: str, args_parse: Optional[List[Dict[str, Any]]] = None, pre_compile: bool = False):
|
31 |
+
self.name = name
|
32 |
+
self.parser = subparsers.add_parser(name, help=help)
|
33 |
+
self.parser.set_defaults(subcommand=name)
|
34 |
+
|
35 |
+
self.pre_compile = pre_compile
|
36 |
+
|
37 |
+
if args_parse and pre_compile:
|
38 |
+
self.build(args_parse)
|
39 |
+
else:
|
40 |
+
self.arg_parse = args_parse
|
41 |
+
|
42 |
+
def _run(self):
|
43 |
+
raise NotImplementedError()
|
44 |
+
|
45 |
+
def build(self, args_parse: Optional[List[Dict[str, Any]]] = None):
|
46 |
+
if not args_parse:
|
47 |
+
args_parse = self.arg_parse
|
48 |
+
|
49 |
+
if not isinstance(args_parse, list):
|
50 |
+
args_parse = list(args_parse)
|
51 |
+
|
52 |
+
for args_sig in args_parse:
|
53 |
+
args_sig['kwargs']['type'] = data_types[args_sig['kwargs']['type']]
|
54 |
+
self.parser.add_argument(*args_sig['args'], **args_sig['kwargs'])
|
55 |
+
|
56 |
+
@property
|
57 |
+
def bind(self):
|
58 |
+
raise PermissionError('Property bind is not allowed to be accessed')
|
59 |
+
|
60 |
+
@bind.setter
|
61 |
+
def bind(self, func: Callable):
|
62 |
+
self._run = func
|
63 |
+
self.parser.set_defaults(ops=self._run)
|
64 |
+
|
65 |
+
|
66 |
+
|
67 |
+
|
68 |
+
class Ops:
|
69 |
+
sub_commands: Dict[str, _SubCommand] = {}
|
70 |
+
with open('techdocs/utils/subcommand_signatures.json') as f:
|
71 |
+
encoded_sub_commands = json.load(f)
|
72 |
+
|
73 |
+
|
74 |
+
if encoded_sub_commands['dynamic signatures']:
|
75 |
+
sub_commands.update({sub_command['name']: _SubCommand(**sub_command, pre_compile=False)
|
76 |
+
for sub_command in encoded_sub_commands['dynamic signatures']
|
77 |
+
})
|
78 |
+
|
79 |
+
if encoded_sub_commands['pre-compiled signatures']:
|
80 |
+
sub_commands.update({sub_command['name']: _SubCommand(**sub_command, pre_compile=True)
|
81 |
+
for sub_command in encoded_sub_commands['pre-compiled signatures']
|
82 |
+
})
|
83 |
+
|
84 |
+
@classmethod
|
85 |
+
def configure_and_build_subcommand(cls, func):
|
86 |
+
config = None
|
87 |
+
try:
|
88 |
+
args = parser.parse_args()
|
89 |
+
sub_command = cls.sub_commands[args.subcommand]
|
90 |
+
|
91 |
+
if not sub_command.pre_compile:
|
92 |
+
sub_command.build()
|
93 |
+
|
94 |
+
|
95 |
+
sub_command.bind = cls.__getattribute__(cls(), args.subcommand)
|
96 |
+
|
97 |
+
func = sub_command.parser.get_default('ops')
|
98 |
+
config = {k: v for k, v in vars(args).items() if k not in ['subcommand', 'ops']}
|
99 |
+
|
100 |
+
except AttributeError as e:
|
101 |
+
config = True
|
102 |
+
|
103 |
+
def run_subcommand(**kwargs):
|
104 |
+
return func(config)
|
105 |
+
return run_subcommand
|
106 |
+
|
107 |
+
|
108 |
+
@classmethod
|
109 |
+
@depends_login
|
110 |
+
def generate(cls, config: Dict[str, Any]):
|
111 |
+
extract_functions_from_directory(config)
|
112 |
+
|
113 |
+
@classmethod
|
114 |
+
@depends_login
|
115 |
+
def apikey(cls, config: Dict[str, Any]):
|
116 |
+
issue_api_key(config)
|
117 |
+
|
118 |
+
@classmethod
|
119 |
+
def signup(cls, config: Dict[str, Any]):
|
120 |
+
signup(config)
|
121 |
+
|
122 |
+
@classmethod
|
123 |
+
def version(cls, config: Dict[str, Any]):
|
124 |
+
print(f"{techdocs.__version__}")
|
techdocs/utils/functools.py
CHANGED
@@ -1,22 +1,27 @@
|
|
1 |
import json
|
2 |
import requests
|
3 |
|
4 |
-
BASE_URL = "https://caffeinecrew-techdocs.hf.space"
|
|
|
5 |
|
6 |
|
7 |
|
8 |
def get_access_token(data, return_refresh_token=False):
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
|
|
|
|
|
|
|
|
20 |
|
21 |
|
22 |
|
@@ -29,7 +34,7 @@ def request_inference(config, code_block, max_retries=1):
|
|
29 |
url = BASE_URL+"/api/inference"
|
30 |
headers={"accept":"application/json", "Authorization": f"Bearer {config['access_token']}"}
|
31 |
code_input = code_block
|
32 |
-
response = requests.post(url=url, headers=headers,
|
33 |
if response.status_code == 200:
|
34 |
return response.json()["docstr"]
|
35 |
else:
|
@@ -47,4 +52,31 @@ def update_file(file_path, docstr_code):
|
|
47 |
with open(file_path, "w",errors='ignore') as file:
|
48 |
file.write(docstr_code)
|
49 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
50 |
|
|
|
|
|
|
|
|
|
|
1 |
import json
|
2 |
import requests
|
3 |
|
4 |
+
# BASE_URL = "https://caffeinecrew-techdocs.hf.space"
|
5 |
+
BASE_URL = "http://127.0.0.1:8000"
|
6 |
|
7 |
|
8 |
|
9 |
def get_access_token(data, return_refresh_token=False):
|
10 |
+
try:
|
11 |
+
url = BASE_URL + "/auth/login"
|
12 |
+
headers = {
|
13 |
+
"accept": "application/json",
|
14 |
+
}
|
15 |
+
data = json.dumps(data)
|
16 |
+
response = requests.post(url, data=data, headers=headers)
|
17 |
+
access_token = response.json()['access_token']
|
18 |
+
if return_refresh_token:
|
19 |
+
refresh_token = response.json()['refresh_token']
|
20 |
+
return access_token, refresh_token
|
21 |
+
return access_token
|
22 |
+
except Exception as e:
|
23 |
+
print("Invlaid Credentials")
|
24 |
+
return None
|
25 |
|
26 |
|
27 |
|
|
|
34 |
url = BASE_URL+"/api/inference"
|
35 |
headers={"accept":"application/json", "Authorization": f"Bearer {config['access_token']}"}
|
36 |
code_input = code_block
|
37 |
+
response = requests.post(url=url, headers=headers, data=json.dumps({'code_block':code_input, 'api_key':config['api_key']}))
|
38 |
if response.status_code == 200:
|
39 |
return response.json()["docstr"]
|
40 |
else:
|
|
|
52 |
with open(file_path, "w",errors='ignore') as file:
|
53 |
file.write(docstr_code)
|
54 |
|
55 |
+
|
56 |
+
|
57 |
+
def issue_api_key(config):
|
58 |
+
try:
|
59 |
+
headers={"accept":"application/json", "Authorization": f"Bearer {config['access_token']}"}
|
60 |
+
response = requests.put(url=BASE_URL + "/auth/regenerate_api_key", headers=headers,
|
61 |
+
data=json.dumps({"username": config['username']})
|
62 |
+
)
|
63 |
+
if (response.status_code!=200):
|
64 |
+
raise Exception("API Key Generation Failed")
|
65 |
+
print(f"$ API_KEY: {response.json()['api_key']}")
|
66 |
+
except Exception as e:
|
67 |
+
print(f"$ {e}")
|
68 |
+
|
69 |
+
|
70 |
+
def signup(config):
|
71 |
+
try:
|
72 |
+
headers={"accept":"application/json"}
|
73 |
+
response = requests.post(url=BASE_URL + "/auth/signup", headers=headers, data=json.dumps(config))
|
74 |
+
if (response.status_code==226):
|
75 |
+
raise Exception("username or email already exists")
|
76 |
+
elif (response.status_code!=200):
|
77 |
+
raise Exception("Something went wrong, please try again later")
|
78 |
|
79 |
+
print("Signed up successfully, please issue a new `API_KEY` to continue")
|
80 |
+
|
81 |
+
except Exception as e:
|
82 |
+
print(e)
|
techdocs/utils/subcommand_signatures.json
ADDED
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"pre-compiled signatures":
|
3 |
+
[
|
4 |
+
{
|
5 |
+
"name": "generate",
|
6 |
+
"help": "Generate Documentation from a given directory root",
|
7 |
+
"args_parse":
|
8 |
+
[
|
9 |
+
{"args": ["--api_key", "-k"], "kwargs": {"type": "str", "required": true, "help": "API key for techdocs"}},
|
10 |
+
{"args": ["--username", "-u"], "kwargs": {"type": "str", "required": true, "help": "Username for techdocs"}},
|
11 |
+
{"args": ["--password", "-p"], "kwargs": {"type": "str", "required": true, "help": "Password for techdocs"}},
|
12 |
+
{"args": ["--dir", "-d"], "kwargs": {"type": "str", "required": true, "help": "Root directory to be documented"}}
|
13 |
+
]
|
14 |
+
},
|
15 |
+
{
|
16 |
+
"name": "apikey",
|
17 |
+
"help": "Issue a new API key for techdocs",
|
18 |
+
"args_parse":
|
19 |
+
[
|
20 |
+
{"args": ["-username", "-u"], "kwargs": {"type": "str", "required": true, "help": "Username for techdocs"}},
|
21 |
+
{"args": ["-password", "-p"], "kwargs": {"type": "str", "required": true, "help": "Password for techdocs"}}
|
22 |
+
]
|
23 |
+
},
|
24 |
+
{
|
25 |
+
"name": "version",
|
26 |
+
"help": "Print the version of the techdocs CLI",
|
27 |
+
"args_parse": []
|
28 |
+
},
|
29 |
+
{
|
30 |
+
"name": "signup",
|
31 |
+
"help": "Sign up for a new techdocs account",
|
32 |
+
"args_parse":
|
33 |
+
[
|
34 |
+
{"args": ["-username", "-u"], "kwargs": {"type": "str", "required": true, "help": "Username for Techdocs"}},
|
35 |
+
{"args": ["-password", "-p"], "kwargs": {"type": "str", "required": true, "help": "Password for Techdocs"}},
|
36 |
+
{"args": ["-email", "-e"], "kwargs": {"type": "str", "required": true, "help": "Email for techdocs"}}
|
37 |
+
]
|
38 |
+
}
|
39 |
+
],
|
40 |
+
"dynamic signatures":
|
41 |
+
[
|
42 |
+
|
43 |
+
]
|
44 |
+
}
|
45 |
+
|
testing/DBQueries.py
CHANGED
@@ -9,10 +9,25 @@ class DBQueries:
|
|
9 |
|
10 |
@classmethod
|
11 |
def insert_to_database(cls, table_name: str, data: Union[Tuple, List[Tuple]], cols: List[str]=None):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
12 |
con = DBConnection.get_client()
|
13 |
cursor = con.cursor()
|
14 |
QUERY = f"INSERT INTO {{table_name}} ({','.join(cols)}) VALUES ".format(table_name=table_name)
|
15 |
-
print(data)
|
16 |
if isinstance(data, list):
|
17 |
QUERY += '(' + ','.join(['%s' for _ in range(len(data[0]))]) + ')'
|
18 |
cursor.executemany(QUERY, data)
|
@@ -23,6 +38,22 @@ class DBQueries:
|
|
23 |
|
24 |
@classmethod
|
25 |
def fetch_data_from_database(cls, table_name: str, cols_to_fetch: Union[str, List[str]], where_clause: str=None):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
26 |
con = DBConnection.get_client()
|
27 |
cursor = con.cursor()
|
28 |
if isinstance(cols_to_fetch, str):
|
@@ -36,6 +67,21 @@ class DBQueries:
|
|
36 |
|
37 |
@classmethod
|
38 |
def update_data_in_database(cls, table_name: str, cols_to_update: Union[str, List[str]], where_clause: str=None, new_values: Union[str, List[str]]=None):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
39 |
con = DBConnection.get_client()
|
40 |
cursor = con.cursor()
|
41 |
if isinstance(cols_to_update, str):
|
|
|
9 |
|
10 |
@classmethod
|
11 |
def insert_to_database(cls, table_name: str, data: Union[Tuple, List[Tuple]], cols: List[str]=None):
|
12 |
+
"""
|
13 |
+
This method is used to insert data into a specified table in the database.
|
14 |
+
|
15 |
+
Args:
|
16 |
+
table_name (str): The name of the table into which the data will be inserted.
|
17 |
+
data (Union[Tuple, List[Tuple]]): The data to be inserted into the table. It can be either a tuple or a list of tuples.
|
18 |
+
cols (List[str], optional): A list of column names in the table. If not provided, the method will assume all columns are needed. Defaults to None.
|
19 |
+
|
20 |
+
Raises:
|
21 |
+
Exception: If the data type of 'data' is not a tuple or a list of tuples.
|
22 |
+
|
23 |
+
Returns:
|
24 |
+
None
|
25 |
+
"""
|
26 |
+
"\n This method is used to insert data into a specified table in the database.\n\n Args:\n table_name (str): The name of the table into which the data will be inserted.\n data (Union[Tuple, List[Tuple]]): The data to be inserted into the table. It can be either a tuple or a list of tuples.\n cols (List[str], optional): A list of column names in the table. If not provided, the method will assume all columns are needed. Defaults to None.\n\n Raises:\n Exception: If the data type of 'data' is not a tuple or a list of tuples.\n\n Returns:\n None\n "
|
27 |
+
"\n This method is used to insert data into a specified table in the database.\n\n Args:\n table_name (str): The name of the table into which the data will be inserted.\n data (Union[Tuple, List[Tuple]]): The data to be inserted into the table. It can be either a tuple or a list of tuples.\n cols (List[str], optional): A list of column names in the table. If not provided, the method will assume all columns are needed. Defaults to None.\n\n Raises:\n Exception: If the data type of 'data' is not a tuple or a list of tuples.\n\n Returns:\n None\n "
|
28 |
con = DBConnection.get_client()
|
29 |
cursor = con.cursor()
|
30 |
QUERY = f"INSERT INTO {{table_name}} ({','.join(cols)}) VALUES ".format(table_name=table_name)
|
|
|
31 |
if isinstance(data, list):
|
32 |
QUERY += '(' + ','.join(['%s' for _ in range(len(data[0]))]) + ')'
|
33 |
cursor.executemany(QUERY, data)
|
|
|
38 |
|
39 |
@classmethod
|
40 |
def fetch_data_from_database(cls, table_name: str, cols_to_fetch: Union[str, List[str]], where_clause: str=None):
|
41 |
+
"""
|
42 |
+
This method fetches data from a specified table in the database based on the specified column(s) and optional WHERE clause.
|
43 |
+
|
44 |
+
Args:
|
45 |
+
table_name (str): The name of the table from which to fetch data.
|
46 |
+
cols_to_fetch (Union[str, List[str]]): The column(s) to fetch from the table. Can be a single string or a list of strings.
|
47 |
+
If a single string, it will be treated as a comma-separated list of columns.
|
48 |
+
where_clause (str, optional): An optional WHERE clause to filter the data. Defaults to None.
|
49 |
+
|
50 |
+
Returns:
|
51 |
+
List[List[str]]: A list of lists, where each inner list represents a row of data fetched from the database.
|
52 |
+
The order of the columns in the inner lists corresponds to the order specified in the cols_to_fetch parameter.
|
53 |
+
|
54 |
+
Raises:
|
55 |
+
None
|
56 |
+
"""
|
57 |
con = DBConnection.get_client()
|
58 |
cursor = con.cursor()
|
59 |
if isinstance(cols_to_fetch, str):
|
|
|
67 |
|
68 |
@classmethod
|
69 |
def update_data_in_database(cls, table_name: str, cols_to_update: Union[str, List[str]], where_clause: str=None, new_values: Union[str, List[str]]=None):
|
70 |
+
"""
|
71 |
+
This method updates the data in the specified table in the database.
|
72 |
+
|
73 |
+
Args:
|
74 |
+
table_name (str): The name of the table to be updated.
|
75 |
+
cols_to_update (Union[str, List[str]]): The column(s) to be updated. If a single string, it should end with '=%s'. If a list, it should contain strings representing the column names followed by '=%s'.
|
76 |
+
where_clause (str, optional): The WHERE clause to specify the conditions for the update. Defaults to None.
|
77 |
+
new_values (Union[str, List[str]], optional): The new values to be updated in the specified columns. If a single string, it should be a list of values. If a list, it should contain the new values for the columns. Defaults to None.
|
78 |
+
|
79 |
+
Returns:
|
80 |
+
bool: Returns True if the update is successful.
|
81 |
+
|
82 |
+
Raises:
|
83 |
+
Exception: Raises an exception if the database connection fails.
|
84 |
+
"""
|
85 |
con = DBConnection.get_client()
|
86 |
cursor = con.cursor()
|
87 |
if isinstance(cols_to_update, str):
|
testing/test.py
CHANGED
@@ -1,18 +1,107 @@
|
|
1 |
def add(a, b):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
return a + b
|
3 |
|
4 |
def multiply(a, b):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5 |
return a * b
|
6 |
|
7 |
def subtract(a, b):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8 |
return a - b
|
9 |
|
10 |
def divide(a, b):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
11 |
if b == 0:
|
12 |
raise ValueError('Cannot divide by zero')
|
13 |
return a / b
|
14 |
|
15 |
def func(*args, **kwargs):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
16 |
def wrapper(*args, **kwargs):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
17 |
return func(*args, **kwargs)
|
18 |
return wrapper
|
|
|
1 |
def add(a, b):
|
2 |
+
"""
|
3 |
+
This function adds two numbers.
|
4 |
+
|
5 |
+
Arguments:
|
6 |
+
a (int): The first number to be added.
|
7 |
+
b (int): The second number to be added.
|
8 |
+
|
9 |
+
Returns:
|
10 |
+
int: The sum of the two numbers.
|
11 |
+
"""
|
12 |
+
'\n This function adds two numbers.\n\n Arguments:\n a (int): The first number to be added.\n b (int): The second number to be added.\n\n Returns:\n int: The sum of the two numbers.\n '
|
13 |
return a + b
|
14 |
|
15 |
def multiply(a, b):
|
16 |
+
"""
|
17 |
+
This function multiplies two numbers.
|
18 |
+
|
19 |
+
Args:
|
20 |
+
a: A number to be multiplied.
|
21 |
+
This should be a numeric value (int or float).
|
22 |
+
b: Another number to be multiplied.
|
23 |
+
This should be a numeric value (int or float).
|
24 |
+
|
25 |
+
Returns:
|
26 |
+
The product of the two numbers.
|
27 |
+
This will be a numeric value (int or float), representing the result of the multiplication.
|
28 |
+
|
29 |
+
Raises:
|
30 |
+
None
|
31 |
+
|
32 |
+
"""
|
33 |
+
'\n This function multiplies two numbers.\n\n Args:\n a: A number to be multiplied.\n b: Another number to be multiplied.\n\n Returns:\n The product of the two numbers.\n '
|
34 |
return a * b
|
35 |
|
36 |
def subtract(a, b):
|
37 |
+
"""
|
38 |
+
Subtracts the second number from the first.
|
39 |
+
|
40 |
+
Args:
|
41 |
+
a (int): The first number to be subtracted.
|
42 |
+
b (int): The second number to be subtracted from the first.
|
43 |
+
|
44 |
+
Returns:
|
45 |
+
int: The result of the subtraction.
|
46 |
+
"""
|
47 |
+
'\ndef subtract(a, b):\n '
|
48 |
return a - b
|
49 |
|
50 |
def divide(a, b):
|
51 |
+
"""
|
52 |
+
This function divides the first argument by the second argument.
|
53 |
+
|
54 |
+
Arguments:
|
55 |
+
a (float): The first number to be divided.
|
56 |
+
b (float): The second number to be divided.
|
57 |
+
|
58 |
+
Raises:
|
59 |
+
ValueError: If the second argument is zero, it raises a ValueError with the message 'Cannot divide by zero'.
|
60 |
+
|
61 |
+
Returns:
|
62 |
+
float: The result of the division of the first argument by the second argument.
|
63 |
+
"""
|
64 |
+
"\n This function divides the first argument by the second argument.\n\n Arguments:\n a -- The first number to be divided. It should be of type float.\n b -- The second number to be divided. It should be of type float.\n\n Raises:\n ValueError -- If the second argument is zero, it raises a ValueError with the message 'Cannot divide by zero'.\n\n Returns:\n float -- The result of the division of the first argument by the second argument.\n "
|
65 |
if b == 0:
|
66 |
raise ValueError('Cannot divide by zero')
|
67 |
return a / b
|
68 |
|
69 |
def func(*args, **kwargs):
|
70 |
+
"""
|
71 |
+
Usage: query(input_string, search_terms, search_type='AND')
|
72 |
+
|
73 |
+
This function searches for specified terms within the input string using a specified search type.
|
74 |
+
|
75 |
+
Parameters:
|
76 |
+
- input_string (str): The string to search within.
|
77 |
+
- search_terms (list): A list of strings to search for within the input_string.
|
78 |
+
- search_type (str, optional): Specifies how the search_terms should be searched within the input_string.
|
79 |
+
Possible values: 'AND' (all search_terms must be present in the input_string), 'OR' (at least one search_term must be present in the input_string). Default is 'AND'.
|
80 |
+
|
81 |
+
Returns:
|
82 |
+
- search_results (list): A list of all occurrences of the search_terms within the input_string.
|
83 |
+
|
84 |
+
Raises:
|
85 |
+
- ValueError: If the search_type is not 'AND' or 'OR'.
|
86 |
+
"""
|
87 |
+
"\nUsage: func(*args, **kwargs)\n\nThis function returns a wrapper function that calls the original function.\n\nParameters:\n- args (tuple): A tuple of non-keyworded arguments to pass to the function.\n- kwargs (dict): A dictionary of keyworded arguments to pass to the function.\n\nReturns:\n- wrapper (function): A new function that calls the original function with the given arguments.\n\nRaises:\n- TypeError: If the arguments passed to the wrapper function do not match the original function's signature.\n"
|
88 |
+
|
89 |
def wrapper(*args, **kwargs):
|
90 |
+
"""
|
91 |
+
This function performs a specific operation on the given arguments.
|
92 |
+
|
93 |
+
Arguments:
|
94 |
+
arg1 -- a string argument (default: None)
|
95 |
+
arg2 -- an integer argument (default: None)
|
96 |
+
arg3 -- a floating point number argument (default: None)
|
97 |
+
arg4 -- a boolean argument (default: None)
|
98 |
+
|
99 |
+
Returns:
|
100 |
+
None
|
101 |
+
|
102 |
+
Raises:
|
103 |
+
TypeError -- If any argument is not of the expected type.
|
104 |
+
"""
|
105 |
+
'\n This function acts as a wrapper for another function, allowing it to be called with a variety of arguments.\n\n Arguments:\n *args -- any number of positional arguments (default: None)\n **kwargs -- any number of keyword arguments (default: None)\n\n Returns:\n Whatever the wrapped function returns (default: None)\n\n Raises:\n Whatever exceptions the wrapped function raises (default: None)\n '
|
106 |
return func(*args, **kwargs)
|
107 |
return wrapper
|