Ensure functions have docstrings for documentation
def lambda_handler(event, context):
1import json2import os3from pathlib import Path4import re5import string6import subprocess78# import boto3910from datetime import datetime, timedelta11import time12import math13from shutil import rmtree14from tempfile import gettempdir1516# s3 = boto3.client('s3')17bucket_name = 'sloccloccode'1819def lambda_handler(event, context):20 if 'path' not in event:21 return {22 "statusCode": 400,23 "statusDescription": "400",24 "isBase64Encoded": False,25 "headers": {26 "Content-Type": "text/html"27 },28 "body": '''You be invalid'''29 }3031 filename, url, path = process_path(event['path'])3233 if filename == None or url == None or path == None:34 return {35 "statusCode": 400,36 "statusDescription": "400",37 "isBase64Encoded": False,38 "headers": {39 "Content-Type": "text/html"40 },41 "body": '''You be invalid'''42 }4344 get_process_file(filename=filename, url=url, path=path)4546 with open(Path(gettempdir()) / filename, encoding='utf-8') as f:47 content = f.read()4849 j = json.loads(content)50 title = 'Total lines'51 s = format_count(sum([x['Lines'] for x in j]))5253 if 'category' in event['queryStringParameters']:54 t = event['queryStringParameters']['category']5556 if t == 'code':57 title = 'Code lines'58 s = format_count(sum([x['Code'] for x in j]))59 elif t == 'blanks':60 title = 'Blank lines'61 s = format_count(sum([x['Blank'] for x in j]))62 elif t == 'lines':63 pass # it's the default anyway64 elif t == 'comments':65 title = 'Comments'66 s = format_count(sum([x['Comment'] for x in j]))67 elif t == 'cocomo':68 title = 'COCOMO $'69 wage = '56286'70 if 'avg-wage' in event['queryStringParameters']:71 wage = event['queryStringParameters']['avg-wage']7273 if wage.isdigit():74 s = format_count(estimate_cost(sum([x['Code'] for x in j]), int(wage)))75 else:76 s = format_count(estimate_cost(sum([x['Code'] for x in j])))7778 text_length = '250'79 if len(s) <= 3:80 text_length = '200'8182 return {83 "statusCode": 200,84 "statusDescription": "200 OK",85 "isBase64Encoded": False,86 "headers": {87 "Content-Type": "image/svg+xml;charset=utf-8",88 "Cache-Control": "max-age=86400"89 },90 "body": '''<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100" height="20"><linearGradient id="b" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="a"><rect width="100" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#a)"><path fill="#555" d="M0 0h69v20H0z"/><path fill="#4c1" d="M69 0h31v20H69z"/><path fill="url(#b)" d="M0 0h100v20H0z"/></g><g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="110"> <text x="355" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="590">''' + title + '''</text><text x="355" y="140" transform="scale(.1)" textLength="590">''' + title +'''</text><text x="835" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="''' + text_length + '''">''' + s + '''</text><text x="835" y="140" transform="scale(.1)" textLength="''' + text_length + '''">''' + s + '''</text></g> </svg>'''91 }929394def get_process_file(filename, url, path):95 s = boto3.resource('s3')96 o = s.Object(bucket_name, filename)9798 try:99 unixtime = s3time_to_unix(o.last_modified)100 except Exception:101 # force an update in this case102 unixtime = time.time() - 186400103104 diff = int(time.time() - unixtime)105 if diff < 86400:106 o.download_file(Path(gettempdir()) / filename)107 else:108 clone_and_process(filename=filename, url=url, path=path)109110111def clone_and_process(filename, url, path):112 import git113114 download_scc()115116 os.chdir(gettempdir())117118 rmtree(Path(gettempdir()) / 'scc-tmp-path')119 git.exec_command('clone', '--depth=1', url, 'scc-tmp-path', cwd=gettempdir())120121 subprocess.run(['./scc', '-f', 'json', '-o', str(Path(gettempdir()) / filename), 'scc-tmp-path'])122123 with open(Path(gettempdir()) / filename, 'rb') as f:124 s3.upload_fileobj(f, bucket_name, filename)125126 rmtree(Path(gettempdir()) / 'scc-tmp-path')127128129def download_scc():130 my_file = Path(gettempdir()) / 'scc'131 if my_file.exists() == False:132 with open(my_file, 'wb') as f:133 s3.download_fileobj(bucket_name, 'scc', f)134 my_file.chmod(0o755)135136137def s3time_to_unix(last_modified):138 datetime_object = datetime.strptime(str(last_modified).split(' ')[0], '%Y-%m-%d')139 unixtime = time.mktime(datetime_object.timetuple())140 return unixtime141142143def process_path(path):144 path = re.sub('', '', path, flags=re.MULTILINE )145146 s = [clean_string(x) for x in path.lower().split('/') if x != '']147148 if len(s) != 3:149 return None, None, None150151 # Cheap clean check152 for x in s:153 if x == '':154 return None, None, None155156 # URL for cloning157 url = 'https://'158159 if s[0] == 'github':160 url += 'github.com/'161 if s[0] == 'bitbucket':162 url += 'bitbucket.org/'163 if s[0] == 'gitlab':164 url += 'gitlab.com/'165166 url += s[1] + '/'167 url += s[2] + '.git'168169 # File for json170 filename = s[0]171 filename += '.' + s[1]172 filename += '.' + s[2] + '.json'173174 # Need path175 path = s[2]176177 return (filename, url, path)178179180def clean_string(s):181 valid = string.ascii_lowercase182 valid += string.digits183 valid += '-'184 valid += '.'185 valid += '_'186187 clean = ''188189 for c in s:190 if c in valid:191 clean += c192193 return clean194195196def format_count(count):197 ranges = [198 (1e18, 'E'),199 (1e15, 'P'),200 (1e12, 'T'),201 (1e9, 'G'),202 (1e6, 'M'),203 (1e3, 'k'),204 ]205206 for x, y in ranges:207 if count >= x:208 t = str(round(count / x, 1))209 if len(t) > 3:210 t = t[:t.find('.')]211 return t + y212213 return str(round(count, 1))214215216# EstimateEffort calculate the effort applied using generic COCOMO2 weighted values217def estimate_effort(slocCount):218 return float(3.2) * math.pow(float(slocCount)/1000, 1.05) * 1219220221# EstimateCost calculates the cost in dollars applied using generic COCOMO2 weighted values based222# on the average yearly wage223def estimate_cost(slocCount, averageWage=56286):224 return estimate_effort(slocCount) * float(averageWage/12) * float(1.8)225226227if __name__ == '__main__':228229 # last_modified = '2019-06-22 07:13:19+00:00'230 # unixtime = s3time_to_unix(last_modified)231232 # diff = int(time.time() - unixtime)233 # print(diff > 86400)234 # if diff < 86400:235 # print('pull from s3 and return')236 # else:237 # print('clone him and reprocess')238239 x, y, z = process_path('/github/boyter/really-cheap-chatbot/')240 print(x, y, z)241 '''242 https://gitlab.com/esr/loccount.git243 https://bitbucket.org/grumdrig/pq-web.git244 https://github.com/boyter/scc.git245 '''246247 print(format_count(100))248 print(format_count(1000))249 print(format_count(2500))250 print(format_count(436465))251 print(format_count(263804))252 print(format_count(86400))253254 print(format_count(81.99825581739397))255256 print('')257258 # with open('/home/bboyter/Projects/scc-lambda/tmp.json', encoding='utf-8') as f:259 # content = f.read()260261 # j = json.loads(content)262 # print('lines: ' + format_count(sum([x['Lines'] for x in j])))263 # print('code: ' + format_count(sum([x['Code'] for x in j])))264 # print('comment: ' + format_count(sum([x['Comment'] for x in j])))265 # print('blank: ' + format_count(sum([x['Blank'] for x in j])))266 # print('complexity: ' + format_count(sum([x['Complexity'] for x in j])))267268269 print(format_count(estimate_cost(710)))270 # s3 = boto3.resource('s3')271 # o = s3.Object('sloccloccode','github.boyter.really-cheap-chatbot.json')272 # print(o.last_modified)273 # o.download_file('/tmp/github.boyter.really-cheap-chatbot.json')
Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.