setta 0.0.1.dev0__py3-none-any.whl → 0.0.2.dev0__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (265) hide show
  1. setta/__init__.py +1 -1
  2. setta/cli/__init__.py +1 -0
  3. setta/cli/connect.py +43 -0
  4. setta/cli/logger.py +225 -0
  5. setta/code_gen/__init__.py +0 -0
  6. setta/code_gen/create_runnable_scripts.py +466 -0
  7. setta/code_gen/export_selected.py +776 -0
  8. setta/code_gen/find_placeholders.py +13 -0
  9. setta/code_gen/python/__init__.py +0 -0
  10. setta/code_gen/python/ast_utils.py +183 -0
  11. setta/code_gen/python/check_scope.py +187 -0
  12. setta/code_gen/python/generate_code.py +280 -0
  13. setta/code_gen/python/make_parseable.py +97 -0
  14. setta/code_gen/python/position_line_col.py +33 -0
  15. setta/code_gen/python/validate_imports.py +87 -0
  16. setta/code_gen/utils.py +120 -0
  17. setta/code_gen/yaml/__init__.py +0 -0
  18. setta/code_gen/yaml/generate_yaml.py +23 -0
  19. setta/code_gen/yaml/section_dict.py +93 -0
  20. setta/database/__init__.py +0 -0
  21. setta/database/backup.py +80 -0
  22. setta/database/db/__init__.py +0 -0
  23. setta/database/db/artifacts/__init__.py +0 -0
  24. setta/database/db/artifacts/load.py +93 -0
  25. setta/database/db/artifacts/save.py +85 -0
  26. setta/database/db/artifacts/save_or_create.py +68 -0
  27. setta/database/db/artifacts/utils.py +13 -0
  28. setta/database/db/codeInfo/__init__.py +0 -0
  29. setta/database/db/codeInfo/copy.py +26 -0
  30. setta/database/db/codeInfo/load.py +65 -0
  31. setta/database/db/codeInfo/save.py +75 -0
  32. setta/database/db/codeInfo/utils.py +33 -0
  33. setta/database/db/evRefs/__init__.py +0 -0
  34. setta/database/db/evRefs/load.py +45 -0
  35. setta/database/db/evRefs/save.py +95 -0
  36. setta/database/db/projects/__init__.py +0 -0
  37. setta/database/db/projects/copy.py +36 -0
  38. setta/database/db/projects/delete.py +7 -0
  39. setta/database/db/projects/load.py +184 -0
  40. setta/database/db/projects/save.py +267 -0
  41. setta/database/db/projects/saveAs.py +40 -0
  42. setta/database/db/projects/utils.py +135 -0
  43. setta/database/db/sectionVariants/__init__.py +0 -0
  44. setta/database/db/sectionVariants/copy.py +28 -0
  45. setta/database/db/sectionVariants/load.py +139 -0
  46. setta/database/db/sectionVariants/save.py +140 -0
  47. setta/database/db/sectionVariants/utils.py +44 -0
  48. setta/database/db/sections/__init__.py +0 -0
  49. setta/database/db/sections/copy.py +70 -0
  50. setta/database/db/sections/jsonSource.py +119 -0
  51. setta/database/db/sections/load.py +350 -0
  52. setta/database/db/sections/save.py +204 -0
  53. setta/database/db/sections/utils.py +13 -0
  54. setta/database/db/uiTypes/__init__.py +0 -0
  55. setta/database/db/uiTypes/copy.py +33 -0
  56. setta/database/db/uiTypes/load.py +51 -0
  57. setta/database/db/uiTypes/save.py +99 -0
  58. setta/database/db/uiTypes/utils.py +27 -0
  59. setta/database/db_init.py +36 -0
  60. setta/database/db_objs.py +102 -0
  61. setta/database/db_path.py +8 -0
  62. setta/database/export_db/__init__.py +0 -0
  63. setta/database/export_db/export_db.py +43 -0
  64. setta/database/export_db/export_raw.py +53 -0
  65. setta/database/export_db/export_readable.py +242 -0
  66. setta/database/export_db/utils.py +16 -0
  67. setta/database/import_db.py +28 -0
  68. setta/database/seed.py +41 -0
  69. setta/database/settings_file.py +118 -0
  70. setta/database/utils.py +32 -0
  71. setta/lsp/__init__.py +0 -0
  72. setta/lsp/file_watcher.py +113 -0
  73. setta/lsp/reader.py +184 -0
  74. setta/lsp/reader_fns/__init__.py +0 -0
  75. setta/lsp/reader_fns/completion.py +84 -0
  76. setta/lsp/reader_fns/definition.py +2 -0
  77. setta/lsp/reader_fns/diagnostics.py +99 -0
  78. setta/lsp/reader_fns/documentHighlight.py +25 -0
  79. setta/lsp/reader_fns/references.py +34 -0
  80. setta/lsp/reader_fns/signatureHelp.py +99 -0
  81. setta/lsp/server.py +150 -0
  82. setta/lsp/utils.py +60 -0
  83. setta/lsp/writer.py +306 -0
  84. setta/routers/__init__.py +11 -0
  85. setta/routers/artifact.py +105 -0
  86. setta/routers/code_info.py +32 -0
  87. setta/routers/dependencies.py +49 -0
  88. setta/routers/in_memory_fn_stdout_websocket.py +21 -0
  89. setta/routers/interactive.py +119 -0
  90. setta/routers/lsp.py +14 -0
  91. setta/routers/projects.py +188 -0
  92. setta/routers/reference_renaming.py +111 -0
  93. setta/routers/sections.py +174 -0
  94. setta/routers/settings.py +40 -0
  95. setta/routers/terminals.py +83 -0
  96. setta/routers/websocket.py +36 -0
  97. setta/server.py +141 -0
  98. setta/start.py +112 -0
  99. setta/static/constants/BaseUITypes.json +153 -0
  100. setta/static/constants/Settings.json +113 -0
  101. setta/static/constants/constants.json +117 -0
  102. setta/static/constants/db_init.sql +249 -0
  103. setta/static/constants/defaultValues.json +125 -0
  104. setta/static/constants/settingsProject.json +276 -0
  105. setta/static/frontend/android-chrome-192x192.png +0 -0
  106. setta/static/frontend/android-chrome-512x512.png +0 -0
  107. setta/static/frontend/apple-touch-icon.png +0 -0
  108. setta/static/frontend/assets/KaTeX_AMS-Regular-0cdd387c.woff2 +0 -0
  109. setta/static/frontend/assets/KaTeX_AMS-Regular-30da91e8.woff +0 -0
  110. setta/static/frontend/assets/KaTeX_AMS-Regular-68534840.ttf +0 -0
  111. setta/static/frontend/assets/KaTeX_Caligraphic-Bold-07d8e303.ttf +0 -0
  112. setta/static/frontend/assets/KaTeX_Caligraphic-Bold-1ae6bd74.woff +0 -0
  113. setta/static/frontend/assets/KaTeX_Caligraphic-Bold-de7701e4.woff2 +0 -0
  114. setta/static/frontend/assets/KaTeX_Caligraphic-Regular-3398dd02.woff +0 -0
  115. setta/static/frontend/assets/KaTeX_Caligraphic-Regular-5d53e70a.woff2 +0 -0
  116. setta/static/frontend/assets/KaTeX_Caligraphic-Regular-ed0b7437.ttf +0 -0
  117. setta/static/frontend/assets/KaTeX_Fraktur-Bold-74444efd.woff2 +0 -0
  118. setta/static/frontend/assets/KaTeX_Fraktur-Bold-9163df9c.ttf +0 -0
  119. setta/static/frontend/assets/KaTeX_Fraktur-Bold-9be7ceb8.woff +0 -0
  120. setta/static/frontend/assets/KaTeX_Fraktur-Regular-1e6f9579.ttf +0 -0
  121. setta/static/frontend/assets/KaTeX_Fraktur-Regular-51814d27.woff2 +0 -0
  122. setta/static/frontend/assets/KaTeX_Fraktur-Regular-5e28753b.woff +0 -0
  123. setta/static/frontend/assets/KaTeX_Main-Bold-0f60d1b8.woff2 +0 -0
  124. setta/static/frontend/assets/KaTeX_Main-Bold-138ac28d.ttf +0 -0
  125. setta/static/frontend/assets/KaTeX_Main-Bold-c76c5d69.woff +0 -0
  126. setta/static/frontend/assets/KaTeX_Main-BoldItalic-70ee1f64.ttf +0 -0
  127. setta/static/frontend/assets/KaTeX_Main-BoldItalic-99cd42a3.woff2 +0 -0
  128. setta/static/frontend/assets/KaTeX_Main-BoldItalic-a6f7ec0d.woff +0 -0
  129. setta/static/frontend/assets/KaTeX_Main-Italic-0d85ae7c.ttf +0 -0
  130. setta/static/frontend/assets/KaTeX_Main-Italic-97479ca6.woff2 +0 -0
  131. setta/static/frontend/assets/KaTeX_Main-Italic-f1d6ef86.woff +0 -0
  132. setta/static/frontend/assets/KaTeX_Main-Regular-c2342cd8.woff2 +0 -0
  133. setta/static/frontend/assets/KaTeX_Main-Regular-c6368d87.woff +0 -0
  134. setta/static/frontend/assets/KaTeX_Main-Regular-d0332f52.ttf +0 -0
  135. setta/static/frontend/assets/KaTeX_Math-BoldItalic-850c0af5.woff +0 -0
  136. setta/static/frontend/assets/KaTeX_Math-BoldItalic-dc47344d.woff2 +0 -0
  137. setta/static/frontend/assets/KaTeX_Math-BoldItalic-f9377ab0.ttf +0 -0
  138. setta/static/frontend/assets/KaTeX_Math-Italic-08ce98e5.ttf +0 -0
  139. setta/static/frontend/assets/KaTeX_Math-Italic-7af58c5e.woff2 +0 -0
  140. setta/static/frontend/assets/KaTeX_Math-Italic-8a8d2445.woff +0 -0
  141. setta/static/frontend/assets/KaTeX_SansSerif-Bold-1ece03f7.ttf +0 -0
  142. setta/static/frontend/assets/KaTeX_SansSerif-Bold-e99ae511.woff2 +0 -0
  143. setta/static/frontend/assets/KaTeX_SansSerif-Bold-ece03cfd.woff +0 -0
  144. setta/static/frontend/assets/KaTeX_SansSerif-Italic-00b26ac8.woff2 +0 -0
  145. setta/static/frontend/assets/KaTeX_SansSerif-Italic-3931dd81.ttf +0 -0
  146. setta/static/frontend/assets/KaTeX_SansSerif-Italic-91ee6750.woff +0 -0
  147. setta/static/frontend/assets/KaTeX_SansSerif-Regular-11e4dc8a.woff +0 -0
  148. setta/static/frontend/assets/KaTeX_SansSerif-Regular-68e8c73e.woff2 +0 -0
  149. setta/static/frontend/assets/KaTeX_SansSerif-Regular-f36ea897.ttf +0 -0
  150. setta/static/frontend/assets/KaTeX_Script-Regular-036d4e95.woff2 +0 -0
  151. setta/static/frontend/assets/KaTeX_Script-Regular-1c67f068.ttf +0 -0
  152. setta/static/frontend/assets/KaTeX_Script-Regular-d96cdf2b.woff +0 -0
  153. setta/static/frontend/assets/KaTeX_Size1-Regular-6b47c401.woff2 +0 -0
  154. setta/static/frontend/assets/KaTeX_Size1-Regular-95b6d2f1.ttf +0 -0
  155. setta/static/frontend/assets/KaTeX_Size1-Regular-c943cc98.woff +0 -0
  156. setta/static/frontend/assets/KaTeX_Size2-Regular-2014c523.woff +0 -0
  157. setta/static/frontend/assets/KaTeX_Size2-Regular-a6b2099f.ttf +0 -0
  158. setta/static/frontend/assets/KaTeX_Size2-Regular-d04c5421.woff2 +0 -0
  159. setta/static/frontend/assets/KaTeX_Size3-Regular-500e04d5.ttf +0 -0
  160. setta/static/frontend/assets/KaTeX_Size3-Regular-6ab6b62e.woff +0 -0
  161. setta/static/frontend/assets/KaTeX_Size4-Regular-99f9c675.woff +0 -0
  162. setta/static/frontend/assets/KaTeX_Size4-Regular-a4af7d41.woff2 +0 -0
  163. setta/static/frontend/assets/KaTeX_Size4-Regular-c647367d.ttf +0 -0
  164. setta/static/frontend/assets/KaTeX_Typewriter-Regular-71d517d6.woff2 +0 -0
  165. setta/static/frontend/assets/KaTeX_Typewriter-Regular-e14fed02.woff +0 -0
  166. setta/static/frontend/assets/KaTeX_Typewriter-Regular-f01f3e87.ttf +0 -0
  167. setta/static/frontend/assets/cormorant-garamond-all-700-italic-c9b58582.woff +0 -0
  168. setta/static/frontend/assets/cormorant-garamond-cyrillic-700-italic-9101ad5f.woff2 +0 -0
  169. setta/static/frontend/assets/cormorant-garamond-cyrillic-ext-700-italic-950de0d6.woff2 +0 -0
  170. setta/static/frontend/assets/cormorant-garamond-latin-700-italic-0bc53e12.woff2 +0 -0
  171. setta/static/frontend/assets/cormorant-garamond-latin-ext-700-italic-525738e0.woff2 +0 -0
  172. setta/static/frontend/assets/cormorant-garamond-vietnamese-700-italic-99563037.woff2 +0 -0
  173. setta/static/frontend/assets/erase-5e0448ea.svg +15 -0
  174. setta/static/frontend/assets/index-1d4b4ecf.css +32 -0
  175. setta/static/frontend/assets/index-ee99dc72.js +678 -0
  176. setta/static/frontend/assets/inter-all-400-normal-054f12d0.woff +0 -0
  177. setta/static/frontend/assets/inter-all-600-normal-c03769e5.woff +0 -0
  178. setta/static/frontend/assets/inter-all-800-normal-15dc6e4b.woff +0 -0
  179. setta/static/frontend/assets/inter-cyrillic-400-normal-a4eee61a.woff2 +0 -0
  180. setta/static/frontend/assets/inter-cyrillic-600-normal-8b14f703.woff2 +0 -0
  181. setta/static/frontend/assets/inter-cyrillic-800-normal-e706eaaa.woff2 +0 -0
  182. setta/static/frontend/assets/inter-cyrillic-ext-400-normal-70047a3b.woff2 +0 -0
  183. setta/static/frontend/assets/inter-cyrillic-ext-600-normal-d4ab9bc4.woff2 +0 -0
  184. setta/static/frontend/assets/inter-cyrillic-ext-800-normal-eae7515a.woff2 +0 -0
  185. setta/static/frontend/assets/inter-greek-400-normal-381ea30d.woff2 +0 -0
  186. setta/static/frontend/assets/inter-greek-600-normal-601f93a2.woff2 +0 -0
  187. setta/static/frontend/assets/inter-greek-800-normal-7af4fb64.woff2 +0 -0
  188. setta/static/frontend/assets/inter-greek-ext-400-normal-27027b17.woff2 +0 -0
  189. setta/static/frontend/assets/inter-greek-ext-600-normal-f2ddf9de.woff2 +0 -0
  190. setta/static/frontend/assets/inter-greek-ext-800-normal-4cb6189e.woff2 +0 -0
  191. setta/static/frontend/assets/inter-latin-400-normal-d56fec21.woff2 +0 -0
  192. setta/static/frontend/assets/inter-latin-600-normal-ff769fa6.woff2 +0 -0
  193. setta/static/frontend/assets/inter-latin-800-normal-5eea1309.woff2 +0 -0
  194. setta/static/frontend/assets/inter-latin-ext-400-normal-bb698d85.woff2 +0 -0
  195. setta/static/frontend/assets/inter-latin-ext-600-normal-ca4808f9.woff2 +0 -0
  196. setta/static/frontend/assets/inter-latin-ext-800-normal-ebdacc0f.woff2 +0 -0
  197. setta/static/frontend/assets/logo/logo.svg +8 -0
  198. setta/static/frontend/assets/pen-455d7d8a.svg +19 -0
  199. setta/static/frontend/assets/source-code-pro-all-500-normal-6bdaa03b.woff +0 -0
  200. setta/static/frontend/assets/source-code-pro-cyrillic-500-normal-288a0d68.woff2 +0 -0
  201. setta/static/frontend/assets/source-code-pro-cyrillic-ext-500-normal-b110a13b.woff2 +0 -0
  202. setta/static/frontend/assets/source-code-pro-greek-500-normal-04328acb.woff2 +0 -0
  203. setta/static/frontend/assets/source-code-pro-latin-500-normal-06edef1e.woff2 +0 -0
  204. setta/static/frontend/assets/source-code-pro-latin-ext-500-normal-6dc60d5e.woff2 +0 -0
  205. setta/static/frontend/assets/web-vitals-44a8e082.js +1 -0
  206. setta/static/frontend/assets/work-sans-all-400-normal-38034a3c.woff +0 -0
  207. setta/static/frontend/assets/work-sans-all-500-normal-550d64e5.woff +0 -0
  208. setta/static/frontend/assets/work-sans-all-600-normal-ccf14060.woff +0 -0
  209. setta/static/frontend/assets/work-sans-all-700-normal-494c2971.woff +0 -0
  210. setta/static/frontend/assets/work-sans-latin-400-normal-36735bc1.woff2 +0 -0
  211. setta/static/frontend/assets/work-sans-latin-500-normal-3790bfda.woff2 +0 -0
  212. setta/static/frontend/assets/work-sans-latin-600-normal-5fba494e.woff2 +0 -0
  213. setta/static/frontend/assets/work-sans-latin-700-normal-a5033d0a.woff2 +0 -0
  214. setta/static/frontend/assets/work-sans-latin-ext-400-normal-c20f571a.woff2 +0 -0
  215. setta/static/frontend/assets/work-sans-latin-ext-500-normal-0f5ac96c.woff2 +0 -0
  216. setta/static/frontend/assets/work-sans-latin-ext-600-normal-97a237d1.woff2 +0 -0
  217. setta/static/frontend/assets/work-sans-latin-ext-700-normal-103e112c.woff2 +0 -0
  218. setta/static/frontend/browserconfig.xml +9 -0
  219. setta/static/frontend/favicon-16x16.png +0 -0
  220. setta/static/frontend/favicon-32x32.png +0 -0
  221. setta/static/frontend/favicon.ico +0 -0
  222. setta/static/frontend/index.html +30 -0
  223. setta/static/frontend/manifest.json +25 -0
  224. setta/static/frontend/mstile-144x144.png +0 -0
  225. setta/static/frontend/mstile-150x150.png +0 -0
  226. setta/static/frontend/mstile-310x150.png +0 -0
  227. setta/static/frontend/mstile-310x310.png +0 -0
  228. setta/static/frontend/mstile-70x70.png +0 -0
  229. setta/static/frontend/robots.txt +3 -0
  230. setta/static/frontend/safari-pinned-tab.svg +18 -0
  231. setta/static/frontend/site.webmanifest +19 -0
  232. setta/static/seed/.DS_Store +0 -0
  233. setta/static/seed/examples/.DS_Store +0 -0
  234. setta/tasks/__init__.py +0 -0
  235. setta/tasks/fns/__init__.py +9 -0
  236. setta/tasks/fns/codeAreaAutocomplete.py +209 -0
  237. setta/tasks/fns/codeAreaFindTemplateVars.py +128 -0
  238. setta/tasks/fns/codeAreaInitializeCode.py +98 -0
  239. setta/tasks/fns/findEVRefs.py +236 -0
  240. setta/tasks/fns/parametersRequest.py +71 -0
  241. setta/tasks/fns/textFieldAutocomplete.py +210 -0
  242. setta/tasks/fns/textFieldInitializeCode.py +99 -0
  243. setta/tasks/fns/typeCheck.py +40 -0
  244. setta/tasks/fns/utils.py +134 -0
  245. setta/tasks/task_runner.py +29 -0
  246. setta/tasks/tasks.py +152 -0
  247. setta/tasks/utils.py +178 -0
  248. setta/terminals/__init__.py +0 -0
  249. setta/terminals/terminals.py +242 -0
  250. setta/terminals/utils.py +37 -0
  251. setta/utils/__init__.py +0 -0
  252. setta/utils/constants.py +148 -0
  253. setta/utils/generate_memorable_string.py +431 -0
  254. setta/utils/generate_new_filename.py +80 -0
  255. setta/utils/section_contents.py +133 -0
  256. setta/utils/utils.py +271 -0
  257. setta/utils/websocket_manager.py +91 -0
  258. setta-0.0.2.dev0.dist-info/LICENSE +201 -0
  259. setta-0.0.2.dev0.dist-info/METADATA +24 -0
  260. setta-0.0.2.dev0.dist-info/RECORD +263 -0
  261. {setta-0.0.1.dev0.dist-info → setta-0.0.2.dev0.dist-info}/WHEEL +1 -1
  262. setta-0.0.2.dev0.dist-info/entry_points.txt +2 -0
  263. setta-0.0.1.dev0.dist-info/METADATA +0 -18
  264. setta-0.0.1.dev0.dist-info/RECORD +0 -5
  265. {setta-0.0.1.dev0.dist-info → setta-0.0.2.dev0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,25 @@
1
+ from setta.code_gen.python.position_line_col import line_col_to_position_batch
2
+
3
+
4
+ def process_document_highlight_response(response, metadata):
5
+ content = []
6
+ # if it's not None, then it's a variable or import or something like that
7
+ if response["result"]:
8
+ # the response doesn't include uri for some reason,
9
+ # so we keep track of it manually
10
+ code = metadata["code"]
11
+
12
+ for x in response["result"]:
13
+ r = x["range"]
14
+ positions = line_col_to_position_batch(
15
+ code,
16
+ [
17
+ (r["start"]["line"], r["start"]["character"]),
18
+ (r["end"]["line"], r["end"]["character"]),
19
+ ],
20
+ )
21
+ content.append({"startPos": positions[0], "endPos": positions[1]})
22
+ return_id = metadata["return_id"]
23
+ num_messages = metadata["num_messages"]
24
+ content = {"positions": content, "numMessages": num_messages}
25
+ return content, return_id
@@ -0,0 +1,34 @@
1
+ from setta.code_gen.python.position_line_col import line_col_to_position_batch
2
+
3
+
4
+ def process_references_response(response, metadata):
5
+ content = []
6
+ if response["result"] and len(response["result"]) > 0:
7
+ code = metadata["code"]
8
+ line_cols = []
9
+ for x in response["result"]:
10
+ line_cols.append(
11
+ (
12
+ x["range"]["start"]["line"],
13
+ x["range"]["start"]["character"],
14
+ )
15
+ )
16
+ line_cols.append(
17
+ (x["range"]["end"]["line"], x["range"]["end"]["character"])
18
+ )
19
+ positions = line_col_to_position_batch(code, line_cols)
20
+ position_offset = metadata["position_offset"]
21
+ for idx in range(0, len(positions), 2):
22
+ startPos = positions[idx] - position_offset
23
+ endPos = positions[idx + 1] - position_offset
24
+ content.append(
25
+ {
26
+ "startPos": startPos,
27
+ "endPos": endPos,
28
+ }
29
+ )
30
+
31
+ return_id = metadata["return_id"]
32
+ num_messages = metadata["num_messages"]
33
+ content = {"positions": content, "numMessages": num_messages}
34
+ return content, return_id
@@ -0,0 +1,99 @@
1
+ import re
2
+
3
+ import docstring_parser
4
+
5
+
6
+ def process_signature_help_response(response):
7
+ content = None
8
+ if response["result"]:
9
+ content = parse_signature(response["result"]["signatures"][0])
10
+ return content
11
+
12
+
13
+ def parse_signature(signature):
14
+ docstring = process_docstring(signature)
15
+ param_info_list = wrapper_parse_signature(
16
+ signature, docstring, get_pyright_param_proposals
17
+ )
18
+ if len(param_info_list) == 0:
19
+ param_info_list = wrapper_parse_signature(
20
+ signature, docstring, get_docstring_parser_param_proposals
21
+ )
22
+ documentation = signature.get("documentation", {"value": ""})["value"]
23
+ return [documentation, param_info_list]
24
+
25
+
26
+ def process_docstring(signature):
27
+ if "documentation" in signature:
28
+ parsed = docstring_parser.parse(signature["documentation"]["value"])
29
+ return {
30
+ extract_variable_name(v.arg_name): {
31
+ "default": v.default,
32
+ "description": v.description,
33
+ }
34
+ for v in parsed.params
35
+ }
36
+ return {}
37
+
38
+
39
+ def wrapper_parse_signature(signature, docstring, get_proposed_params):
40
+ params = get_proposed_params(signature, docstring)
41
+ param_info_list = []
42
+ positional_only_indicator_idx = -1
43
+
44
+ for idx, (name, default, description) in enumerate(params):
45
+ if name == "/":
46
+ positional_only_indicator_idx = idx
47
+ continue
48
+ if name in [None, "", "*", "..."]:
49
+ continue
50
+
51
+ if not default:
52
+ default = ""
53
+
54
+ if not description:
55
+ description = docstring.get(name, {}).get("description", "")
56
+
57
+ # Append parsed information to list
58
+ param_info_list.append(
59
+ {
60
+ "name": name,
61
+ "defaultVal": default,
62
+ "description": description,
63
+ "positionalOnly": False,
64
+ }
65
+ )
66
+
67
+ for idx in range(0, positional_only_indicator_idx):
68
+ param_info_list[idx]["positionalOnly"] = True
69
+
70
+ return param_info_list
71
+
72
+
73
+ def get_docstring_parser_param_proposals(_, docstring):
74
+ return [(k, v["default"], v["description"]) for k, v in docstring.items()]
75
+
76
+
77
+ def get_pyright_param_proposals(signature, _):
78
+ parameters = signature["parameters"]
79
+ params = [(p["label"], p["documentation"]["value"]) for p in parameters]
80
+ proposals = []
81
+ for param, description in params:
82
+ # Extract parameter name and default value
83
+ if param.startswith("/"):
84
+ proposals.append((param, None, None))
85
+ continue
86
+ parts = param.split("=")
87
+ name = extract_variable_name(parts[0].strip())
88
+ default = parts[1].strip() if len(parts) > 1 else None
89
+ proposals.append((name, default, description))
90
+
91
+ return proposals
92
+
93
+
94
+ def extract_variable_name(code_string):
95
+ # Find potential variable names
96
+ potential_names = re.findall(r"\b[a-zA-Z_]\w*\b", code_string)
97
+
98
+ # Return the first valid identifier
99
+ return next((name for name in potential_names if name.isidentifier()), None)
setta/lsp/server.py ADDED
@@ -0,0 +1,150 @@
1
+ import asyncio
2
+ import logging
3
+ from collections import defaultdict
4
+ from pathlib import Path
5
+
6
+ logger = logging.getLogger(__name__)
7
+
8
+
9
+ class LanguageServer:
10
+ def __init__(self, workspace_folder, code_folder, settings, name):
11
+ # Create folders if they don't exist
12
+ workspace_folder.mkdir(parents=True, exist_ok=True)
13
+ code_folder.mkdir(parents=True, exist_ok=True)
14
+ self.workspace_folder = workspace_folder
15
+ self.code_folder = code_folder
16
+ self.init_properties()
17
+ self.server = None
18
+ if not isinstance(settings, dict):
19
+ logger.warning(
20
+ "warning: your language server settings is not an object, so it will have no effect"
21
+ )
22
+ self.settings = {}
23
+ else:
24
+ self.settings = settings
25
+ self.name = name
26
+
27
+ async def start_server(self):
28
+ logger.debug(f"Starting {self.name} language server")
29
+ self.init_properties()
30
+ self.server = await asyncio.create_subprocess_shell(
31
+ "basedpyright-langserver --stdio",
32
+ stdin=asyncio.subprocess.PIPE,
33
+ stdout=asyncio.subprocess.PIPE,
34
+ stderr=asyncio.subprocess.PIPE,
35
+ )
36
+
37
+ def init_properties(self):
38
+ self.cleanup_pending_requests()
39
+ self.pending_requests = {}
40
+ self.msg_id_to_metadata = defaultdict(dict)
41
+ self.code_metadata = {}
42
+ self.initialization_request_id = None
43
+ self.is_initialized = False
44
+ self.temp_files = {}
45
+
46
+ def cleanup_pending_requests(self):
47
+ if not hasattr(self, "pending_requests"):
48
+ return
49
+ # Cancel all pending futures with an appropriate error
50
+ for future in self.pending_requests.values():
51
+ if not future.done():
52
+ future.set_exception(
53
+ ConnectionResetError("Language server was restarted")
54
+ )
55
+ self.pending_requests.clear()
56
+
57
+ def kill_server(self):
58
+ try:
59
+ logger.debug(f"Stopping {self.name} language server")
60
+ self.server.terminate()
61
+ except ProcessLookupError:
62
+ pass
63
+ for path in self.temp_files.values():
64
+ if path.exists():
65
+ path.unlink()
66
+
67
+ @property
68
+ def stdin(self):
69
+ return self.server.stdin
70
+
71
+ @property
72
+ def stdout(self):
73
+ return self.server.stdout
74
+
75
+
76
+ class LanguageServerInteractor:
77
+ @property
78
+ def settings(self):
79
+ return self.server.settings
80
+
81
+ @property
82
+ def msg_id_to_metadata(self):
83
+ return self.server.msg_id_to_metadata
84
+
85
+ @property
86
+ def workspace_folder(self):
87
+ return self.server.workspace_folder
88
+
89
+ @property
90
+ def code_folder(self):
91
+ return self.server.code_folder
92
+
93
+ @property
94
+ def pending_requests(self):
95
+ return self.server.pending_requests
96
+
97
+ @property
98
+ def temp_files(self):
99
+ return self.server.temp_files
100
+
101
+ async def wait_for_response(self, id, timeout=None):
102
+ future = self.pending_requests.get(id)
103
+ if future:
104
+ try:
105
+ result = await asyncio.wait_for(future, timeout=timeout)
106
+ return result
107
+ except ConnectionResetError:
108
+ # Handle the error case
109
+ pass
110
+ finally:
111
+ self.pending_requests.pop(id, None)
112
+ return None
113
+
114
+ def project_code_folder(self, projectConfigName):
115
+ return self.code_folder / projectConfigName
116
+
117
+ def construct_code_id(self, projectConfigName, sectionName):
118
+ return str(Path(projectConfigName) / sectionName)
119
+
120
+ @property
121
+ def code_metadata(self):
122
+ return self.server.code_metadata
123
+
124
+ def get_new_version_number(
125
+ self,
126
+ uri,
127
+ code,
128
+ codeJson,
129
+ ref_template_var_positions,
130
+ needsDiagnostics,
131
+ projectConfigId,
132
+ codeSectionId,
133
+ ):
134
+ obj = {
135
+ "code": code,
136
+ "codeJson": codeJson,
137
+ "ref_template_var_positions": ref_template_var_positions,
138
+ "needsDiagnostics": needsDiagnostics,
139
+ "projectConfigId": projectConfigId,
140
+ "codeSectionId": codeSectionId,
141
+ }
142
+ if uri not in self.code_metadata:
143
+ obj["version"] = 0
144
+ else:
145
+ obj["version"] = self.code_metadata[uri]["version"] + 1
146
+ self.code_metadata[uri] = obj
147
+ return obj["version"]
148
+
149
+ def get_code_metadata(self, uri):
150
+ return self.code_metadata[uri.lower()]
setta/lsp/utils.py ADDED
@@ -0,0 +1,60 @@
1
+ from .file_watcher import LSPFileWatcher
2
+ from .reader import LanguageServerReader
3
+ from .server import LanguageServer
4
+ from .writer import LanguageServerWriter
5
+
6
+
7
+ def create_lsps(
8
+ workspace_folder,
9
+ code_folder,
10
+ settings,
11
+ ):
12
+ return {
13
+ "full": LanguageServer(
14
+ workspace_folder=workspace_folder,
15
+ code_folder=code_folder,
16
+ settings=settings,
17
+ name="full",
18
+ ),
19
+ "basic": LanguageServer(
20
+ workspace_folder=code_folder,
21
+ code_folder=code_folder,
22
+ settings={},
23
+ name="basic",
24
+ ),
25
+ }
26
+
27
+
28
+ def create_lsp_writers(lsps):
29
+ return {
30
+ k: LanguageServerWriter(v, use_virtual_files=k == "basic")
31
+ for k, v in lsps.items()
32
+ }
33
+
34
+
35
+ def create_lsp_readers(lsps, websocket_manager):
36
+ return {k: LanguageServerReader(v, websocket_manager) for k, v in lsps.items()}
37
+
38
+
39
+ def create_file_watcher(lsps, lsp_writers):
40
+ file_watcher = LSPFileWatcher(lsp_writers["full"].send_did_change_watched_files)
41
+ file_watcher.add_workspace_folder(lsps["full"].workspace_folder)
42
+ return file_watcher
43
+
44
+
45
+ async def start_lsps(lsps, lsp_readers, lsp_writers):
46
+ for k, v in lsps.items():
47
+ await v.start_server()
48
+ await lsp_readers[k].start_listener()
49
+ await lsp_writers[k].send_initialize_request()
50
+
51
+
52
+ async def kill_lsps(lsps, lsp_readers):
53
+ for k, v in lsps.items():
54
+ await lsp_readers[k].stop() # Wait for reader to finish
55
+ v.kill_server()
56
+
57
+
58
+ async def restart_lsps(lsps, lsp_readers, lsp_writers):
59
+ await kill_lsps(lsps, lsp_readers)
60
+ await start_lsps(lsps, lsp_readers, lsp_writers)
setta/lsp/writer.py ADDED
@@ -0,0 +1,306 @@
1
+ import asyncio
2
+ import json
3
+ import logging
4
+ import platform
5
+ import uuid
6
+
7
+ from setta.utils.utils import recursive_dict_merge
8
+
9
+ from .server import LanguageServerInteractor
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+
14
+ class LanguageServerWriter(LanguageServerInteractor):
15
+ def __init__(self, server, use_virtual_files):
16
+ self.server = server
17
+ self.use_virtual_files = use_virtual_files
18
+
19
+ async def send_request(self, method, params, id=None):
20
+ request_dict = {"jsonrpc": "2.0", "method": method, "params": params}
21
+ if id:
22
+ request_dict["id"] = id
23
+ self.msg_id_to_metadata[id]["method"] = method
24
+
25
+ request = json.dumps(request_dict).encode("utf-8")
26
+ content_length = len(request)
27
+ header = f"Content-Length: {content_length}\r\n\r\n".encode("utf-8")
28
+ self.server.stdin.write(header + request)
29
+ await self.server.stdin.drain()
30
+ logger.debug(f"Sent {method} with params: {params}")
31
+
32
+ async def send_initialize_request(self):
33
+ params = {
34
+ "capabilities": {
35
+ "workspace": {"didChangeWatchedFiles": {"dynamicRegistration": True}}
36
+ },
37
+ "workspaceFolders": [{"uri": self.get_workspace_uri()}],
38
+ }
39
+ request_id = str(uuid.uuid4())
40
+ self.server.initialization_request_id = request_id
41
+ await self.send_request("initialize", params=params, id=request_id)
42
+ await self.send_didChangeConfiguration() # pyright requires this step
43
+
44
+ async def send_document_open_request(
45
+ self,
46
+ code_id,
47
+ code,
48
+ codeJson=None,
49
+ ref_template_var_positions=None,
50
+ needsDiagnostics=False,
51
+ projectConfigId=None,
52
+ codeSectionId=None,
53
+ virtual=None,
54
+ ):
55
+ virtual = self.get_is_virtual(virtual)
56
+ uri = self.get_uri(code_id, virtual)
57
+ if uri not in self.code_metadata:
58
+ if not virtual:
59
+ self.create_or_update_temp_file(code_id, code)
60
+ params = {
61
+ "textDocument": {
62
+ "uri": uri,
63
+ "languageId": "python",
64
+ "version": self.get_new_version_number(
65
+ uri,
66
+ code,
67
+ codeJson,
68
+ ref_template_var_positions,
69
+ needsDiagnostics,
70
+ projectConfigId,
71
+ codeSectionId,
72
+ ),
73
+ "text": code,
74
+ }
75
+ }
76
+ logger.debug(f"send_document_open_request {uri}")
77
+ await self.send_request("textDocument/didOpen", params=params)
78
+ else:
79
+ logger.debug(f"document already open, updating it {uri}")
80
+ await self.send_document_update(
81
+ code_id=code_id,
82
+ code=code,
83
+ codeJson=codeJson,
84
+ ref_template_var_positions=ref_template_var_positions,
85
+ needsDiagnostics=needsDiagnostics,
86
+ projectConfigId=projectConfigId,
87
+ codeSectionId=codeSectionId,
88
+ virtual=virtual,
89
+ )
90
+
91
+ async def send_autocomplete_request(
92
+ self,
93
+ line,
94
+ character,
95
+ code_id,
96
+ request_id,
97
+ referencable_var_names,
98
+ generated_var_names,
99
+ cursor_offset,
100
+ otherData=None,
101
+ virtual=None,
102
+ ):
103
+ virtual = self.get_is_virtual(virtual)
104
+ uri = self.get_uri(code_id, virtual)
105
+ params = {
106
+ "textDocument": {"uri": uri},
107
+ "position": {"line": line, "character": character},
108
+ }
109
+ self.msg_id_to_metadata[request_id][
110
+ "referencable_var_names"
111
+ ] = referencable_var_names
112
+ self.msg_id_to_metadata[request_id]["generated_var_names"] = generated_var_names
113
+ self.msg_id_to_metadata[request_id]["cursor_offset"] = cursor_offset
114
+ self.msg_id_to_metadata[request_id]["otherData"] = otherData
115
+ self.msg_id_to_metadata[request_id]["code"] = self.get_code_metadata(uri)[
116
+ "code"
117
+ ]
118
+ await self.send_request(
119
+ "textDocument/completion",
120
+ params=params,
121
+ id=request_id,
122
+ )
123
+
124
+ async def send_signature_help_request(
125
+ self, line, character, code_id, request_id, otherData=None, virtual=None
126
+ ):
127
+ virtual = self.get_is_virtual(virtual)
128
+ uri = self.get_uri(code_id, virtual)
129
+ params = {
130
+ "textDocument": {"uri": uri},
131
+ "position": {"line": line, "character": character},
132
+ "context": {"triggerKind": 2, "triggerCharacter": "("},
133
+ }
134
+ self.msg_id_to_metadata[request_id]["otherData"] = otherData
135
+ await self.send_request(
136
+ "textDocument/signatureHelp",
137
+ params=params,
138
+ id=request_id,
139
+ )
140
+
141
+ async def send_document_highlight_request(
142
+ self,
143
+ line,
144
+ character,
145
+ code_id,
146
+ request_id,
147
+ return_id,
148
+ num_messages,
149
+ virtual=None,
150
+ ):
151
+ virtual = self.get_is_virtual(virtual)
152
+ uri = self.get_uri(code_id, virtual)
153
+ params = {
154
+ "textDocument": {"uri": uri},
155
+ "position": {"line": line, "character": character},
156
+ }
157
+ self.msg_id_to_metadata[request_id]["return_id"] = return_id
158
+ self.msg_id_to_metadata[request_id]["num_messages"] = num_messages
159
+ self.msg_id_to_metadata[request_id]["code"] = self.get_code_metadata(uri)[
160
+ "code"
161
+ ]
162
+ await self.send_request(
163
+ "textDocument/documentHighlight",
164
+ params=params,
165
+ id=request_id,
166
+ )
167
+
168
+ async def send_didChangeConfiguration(self):
169
+ # THIS FORMAT WORKS
170
+ # hardcoded_settings = {
171
+ # "basedpyright": {"analysis": {"exclude": ["setta_code"]}}
172
+ # }
173
+ hardcoded_settings = {}
174
+ settings = recursive_dict_merge(hardcoded_settings, self.settings)
175
+
176
+ await self.send_request(
177
+ "workspace/didChangeConfiguration",
178
+ params={"settings": settings},
179
+ )
180
+
181
+ async def send_document_update(
182
+ self,
183
+ code_id,
184
+ code,
185
+ codeJson,
186
+ ref_template_var_positions=None,
187
+ needsDiagnostics=False,
188
+ projectConfigId=None,
189
+ codeSectionId=None,
190
+ virtual=None,
191
+ ):
192
+ virtual = self.get_is_virtual(virtual)
193
+ if not virtual:
194
+ self.create_or_update_temp_file(code_id, code)
195
+ uri = self.get_uri(code_id, virtual)
196
+ params = {
197
+ "textDocument": {
198
+ "uri": uri,
199
+ "version": self.get_new_version_number(
200
+ uri,
201
+ code,
202
+ codeJson,
203
+ ref_template_var_positions,
204
+ needsDiagnostics,
205
+ projectConfigId,
206
+ codeSectionId,
207
+ ),
208
+ },
209
+ "contentChanges": [{"text": code}],
210
+ }
211
+ await self.send_request("textDocument/didChange", params=params)
212
+
213
+ async def send_reference_request(
214
+ self,
215
+ position_offset,
216
+ line,
217
+ character,
218
+ code_id,
219
+ request_id,
220
+ return_id,
221
+ num_messages,
222
+ virtual=None,
223
+ ):
224
+ virtual = self.get_is_virtual(virtual)
225
+ uri = self.get_uri(code_id, virtual)
226
+ params = {
227
+ "textDocument": {
228
+ "uri": uri,
229
+ },
230
+ "position": {"line": line, "character": character},
231
+ "context": {"includeDeclaration": False},
232
+ }
233
+ self.msg_id_to_metadata[request_id]["position_offset"] = position_offset
234
+ self.msg_id_to_metadata[request_id]["return_id"] = return_id
235
+ self.msg_id_to_metadata[request_id]["num_messages"] = num_messages
236
+ self.msg_id_to_metadata[request_id]["code"] = self.get_code_metadata(uri)[
237
+ "code"
238
+ ]
239
+ await self.send_request("textDocument/references", params=params, id=request_id)
240
+
241
+ async def send_definition_request(
242
+ self,
243
+ line,
244
+ character,
245
+ code_id,
246
+ request_id,
247
+ virtual=None,
248
+ ):
249
+ virtual = self.get_is_virtual(virtual)
250
+ uri = self.get_uri(code_id, virtual)
251
+ params = {
252
+ "textDocument": {"uri": uri},
253
+ "position": {"line": line, "character": character},
254
+ }
255
+ await self.send_request(
256
+ "textDocument/definition",
257
+ params=params,
258
+ id=request_id,
259
+ )
260
+
261
+ async def send_did_change_watched_files(self, changes):
262
+ params = {"changes": changes}
263
+ await self.send_request("workspace/didChangeWatchedFiles", params=params)
264
+
265
+ def create_asyncio_task(self, async_task, request_id, local=False):
266
+ if local:
267
+ self.pending_requests[request_id] = asyncio.Future()
268
+ asyncio.create_task(async_task)
269
+
270
+ def get_workspace_uri(self):
271
+ return f"file://{self.workspace_folder}".lower()
272
+
273
+ def get_base_uri(self, code_id):
274
+ return self.code_folder / f"{code_id}.py"
275
+
276
+ # https://github.com/microsoft/language-server-protocol/issues/1676
277
+ def get_uri(self, code_id, virtual):
278
+ base_uri = self.get_base_uri(code_id)
279
+ prefix = "untitled:" if virtual else "file://"
280
+ uri = f"{prefix}{base_uri}".lower()
281
+ if platform.system() == "Windows":
282
+ uri += "/" # need trailing slash on Windows for some reason
283
+ return uri
284
+
285
+ def get_is_virtual(self, virtual):
286
+ return virtual if virtual is not None else self.use_virtual_files
287
+
288
+ def create_temp_file(self, code_id, code):
289
+ """Create a temporary file for the given code and return its path."""
290
+ # Create all necessary parent directories
291
+ file_path = self.get_base_uri(code_id)
292
+ logger.debug(f"Creating temporary file {file_path}")
293
+ file_path.parent.mkdir(parents=True, exist_ok=True)
294
+
295
+ # Write the code to the file
296
+ file_path.write_text(code)
297
+
298
+ # Store the path for later cleanup
299
+ self.temp_files[code_id] = file_path
300
+ return file_path
301
+
302
+ def create_or_update_temp_file(self, code_id, code):
303
+ if code_id in self.temp_files:
304
+ self.temp_files[code_id].write_text(code)
305
+ else:
306
+ self.create_temp_file(code_id, code)
@@ -0,0 +1,11 @@
1
+ from .artifact import router as artifact_router
2
+ from .code_info import router as code_info_router
3
+ from .in_memory_fn_stdout_websocket import router as in_memory_fn_stdout_router
4
+ from .interactive import router as interactive_code_router
5
+ from .lsp import router as lsp_router
6
+ from .projects import router as projects_router
7
+ from .reference_renaming import router as reference_renaming_router
8
+ from .sections import router as sections_router
9
+ from .settings import router as settings_router
10
+ from .terminals import router as terminals_router
11
+ from .websocket import router as websocket_router