setta 0.0.2__py3-none-any.whl → 0.0.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- setta/__init__.py +1 -1
- setta/cli/__init__.py +1 -1
- setta/cli/logger.py +1 -3
- setta/code_gen/create_runnable_scripts.py +87 -34
- setta/code_gen/export_selected.py +1 -5
- setta/code_gen/find_placeholders.py +13 -2
- setta/database/backup.py +1 -2
- setta/database/db/artifacts/save.py +20 -4
- setta/database/db/projects/save.py +1 -1
- setta/database/db/sections/load.py +5 -2
- setta/database/db/sections/save.py +2 -2
- setta/database/db_objs.py +6 -0
- setta/database/export_db/export_raw.py +3 -3
- setta/database/export_db/utils.py +2 -3
- setta/database/settings_file.py +3 -3
- setta/lsp/file_watcher.py +24 -23
- setta/lsp/server.py +1 -1
- setta/lsp/writer.py +2 -2
- setta/routers/interactive.py +38 -20
- setta/server.py +3 -4
- setta/start.py +4 -3
- setta/static/constants/constants.json +4 -0
- setta/static/constants/db_init.sql +2 -1
- setta/static/constants/defaultValues.json +2 -1
- setta/static/constants/settingsProject.json +31 -31
- setta/static/frontend/assets/index-03be034e.css +32 -0
- setta/static/frontend/assets/{index-ee99dc72.js → index-59443547.js} +171 -171
- setta/static/frontend/index.html +2 -2
- setta/tasks/tasks.py +166 -98
- setta/tasks/utils.py +108 -21
- setta/terminals/terminals.py +7 -6
- setta/utils/constants.py +5 -2
- setta/utils/websocket_manager.py +8 -3
- setta-0.0.3.dist-info/METADATA +146 -0
- {setta-0.0.2.dist-info → setta-0.0.3.dist-info}/RECORD +39 -40
- setta/database/db_path.py +0 -8
- setta/static/frontend/assets/index-1d4b4ecf.css +0 -32
- setta-0.0.2.dist-info/METADATA +0 -24
- {setta-0.0.2.dist-info → setta-0.0.3.dist-info}/LICENSE +0 -0
- {setta-0.0.2.dist-info → setta-0.0.3.dist-info}/WHEEL +0 -0
- {setta-0.0.2.dist-info → setta-0.0.3.dist-info}/entry_points.txt +0 -0
- {setta-0.0.2.dist-info → setta-0.0.3.dist-info}/top_level.txt +0 -0
setta/__init__.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = "0.0.
|
1
|
+
__version__ = "0.0.3"
|
setta/cli/__init__.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
from .logger import Setta
|
1
|
+
from .logger import Setta, SettaImg, SettaList
|
setta/cli/logger.py
CHANGED
@@ -26,9 +26,7 @@ class Setta:
|
|
26
26
|
if root_path:
|
27
27
|
self.root_path = Path(root_path)
|
28
28
|
else:
|
29
|
-
self.root_path = Path(
|
30
|
-
os.environ.get(CODE_FOLDER_ENV_VARIABLE, os.path.relpath(os.getcwd()))
|
31
|
-
)
|
29
|
+
self.root_path = Path(os.environ.get(CODE_FOLDER_ENV_VARIABLE, "."))
|
32
30
|
|
33
31
|
self.name_path_type_to_id = {}
|
34
32
|
|
@@ -1,15 +1,15 @@
|
|
1
1
|
import copy
|
2
|
-
import os
|
3
2
|
from datetime import datetime
|
4
3
|
from pathlib import Path
|
5
4
|
|
6
5
|
from setta.code_gen.export_selected import (
|
7
6
|
export_selected,
|
8
7
|
get_gen_code_template_var,
|
8
|
+
get_section_name,
|
9
9
|
get_section_type,
|
10
10
|
get_selected_section_variant,
|
11
11
|
)
|
12
|
-
from setta.code_gen.find_placeholders import
|
12
|
+
from setta.code_gen.find_placeholders import parse_template_var, tp
|
13
13
|
from setta.code_gen.python.generate_code import (
|
14
14
|
convert_var_names_to_readable_form,
|
15
15
|
generate_code,
|
@@ -23,6 +23,7 @@ from setta.code_gen.utils import process_refs
|
|
23
23
|
from setta.utils.constants import (
|
24
24
|
CODE_FOLDER,
|
25
25
|
CODE_FOLDER_ENV_VARIABLE,
|
26
|
+
CWD,
|
26
27
|
USER_SETTINGS,
|
27
28
|
C,
|
28
29
|
)
|
@@ -56,13 +57,13 @@ async def runCode(message, lsp_writers):
|
|
56
57
|
id_to_relpath = {}
|
57
58
|
for sid in to_write:
|
58
59
|
curr_code = code_dict[sid]
|
59
|
-
|
60
|
+
rel_path_str = write_code_to_file(
|
60
61
|
folder_path,
|
61
62
|
curr_code["sanitized_full_name"],
|
62
63
|
curr_code["code"],
|
63
64
|
curr_code["codeLanguage"],
|
64
65
|
)
|
65
|
-
id_to_relpath[sid] =
|
66
|
+
id_to_relpath[sid] = rel_path_str
|
66
67
|
|
67
68
|
# Only run code that isn't referenced by other code
|
68
69
|
run_order = [
|
@@ -71,8 +72,8 @@ async def runCode(message, lsp_writers):
|
|
71
72
|
|
72
73
|
# create a wrapper script if there are multiple files to run
|
73
74
|
if len(run_order) > 1:
|
74
|
-
|
75
|
-
command = codeCallStr(
|
75
|
+
rel_path_str = create_wrapper_bash_script(folder_path, run_order, code_dict)
|
76
|
+
command = codeCallStr(rel_path_str, "bash")
|
76
77
|
else:
|
77
78
|
sid = run_order[0]
|
78
79
|
command = codeCallStr(id_to_relpath[sid], code_dict[sid]["codeLanguage"])
|
@@ -280,17 +281,41 @@ def get_template_var_replacement_value_fn(
|
|
280
281
|
chars_before_template_var,
|
281
282
|
)
|
282
283
|
else:
|
283
|
-
|
284
|
-
|
285
|
-
|
284
|
+
return process_non_hardcoded_template_var(
|
285
|
+
keyword,
|
286
|
+
template_var,
|
287
|
+
exporter_obj,
|
288
|
+
section_dependencies,
|
289
|
+
folder_path,
|
290
|
+
)
|
291
|
+
|
286
292
|
elif codeLanguage == "bash":
|
287
|
-
|
288
|
-
|
289
|
-
|
293
|
+
return process_non_hardcoded_template_var(
|
294
|
+
keyword, template_var, exporter_obj, section_dependencies, folder_path
|
295
|
+
)
|
290
296
|
|
291
297
|
return get_template_var_replacement_value
|
292
298
|
|
293
299
|
|
300
|
+
def process_non_hardcoded_template_var(
|
301
|
+
keyword, template_var, exporter_obj, section_dependencies, folder_path
|
302
|
+
):
|
303
|
+
keyword, keyword_type = parse_template_var(keyword)
|
304
|
+
if keyword_type == C.TEMPLATE_VAR_IMPORT_PATH_SUFFIX:
|
305
|
+
section_dependencies.append(template_var["sectionId"])
|
306
|
+
return construct_module_path(folder_path, keyword)
|
307
|
+
elif keyword_type == C.TEMPLATE_VAR_VERSION_SUFFIX:
|
308
|
+
version_name = get_selected_section_variant(
|
309
|
+
exporter_obj.p, template_var["sectionId"]
|
310
|
+
)["name"]
|
311
|
+
section_name = get_section_name(exporter_obj.p, template_var["sectionId"])
|
312
|
+
return f'"{section_name}@{version_name}"'
|
313
|
+
elif keyword_type == C.TEMPLATE_VAR_FILE_PATH_SUFFIX:
|
314
|
+
section_dependencies.append(template_var["sectionId"])
|
315
|
+
keyword = sanitize_section_path_full_name(keyword)
|
316
|
+
return f'"{codePathStr(folder_path, keyword, "python")}"'
|
317
|
+
|
318
|
+
|
294
319
|
def get_absolute_decl_position_from_rel_position(
|
295
320
|
template_var, var_name_to_decl_rel_position_dict
|
296
321
|
):
|
@@ -337,7 +362,7 @@ def preprocess_template_vars(code, evRefs, templateVars, cursor_position):
|
|
337
362
|
|
338
363
|
|
339
364
|
def convert_folder_path_to_module_path(folder_path):
|
340
|
-
return
|
365
|
+
return folder_path.relative_to(CWD).as_posix().replace("/", ".").replace("\\", ".")
|
341
366
|
|
342
367
|
|
343
368
|
def languageToExtension(x):
|
@@ -351,7 +376,7 @@ def languageToCall(x):
|
|
351
376
|
def codePathStr(folder_path, filename, codeLanguage):
|
352
377
|
extension = languageToExtension(codeLanguage)
|
353
378
|
output = folder_path / f"{filename}{extension}"
|
354
|
-
return
|
379
|
+
return output.relative_to(CWD).as_posix()
|
355
380
|
|
356
381
|
|
357
382
|
def codeCallStr(filepath, codeLanguage):
|
@@ -377,8 +402,46 @@ def prune_and_topological_sort(code_dict, to_keep):
|
|
377
402
|
return topological_sort(section_dependencies), section_dependencies
|
378
403
|
|
379
404
|
|
405
|
+
# TODO: eliminate redundancy between this and prune_and_topological_sort
|
406
|
+
def prune_and_find_top_nodes(code_dict, to_keep):
|
407
|
+
section_dependencies = {k: v["section_dependencies"] for k, v in code_dict.items()}
|
408
|
+
section_dependencies = prune_dict(section_dependencies, to_keep)
|
409
|
+
return find_top_nodes(section_dependencies), section_dependencies
|
410
|
+
|
411
|
+
|
412
|
+
def get_import_order_for_top_node(top_node, dependency_dict):
|
413
|
+
# Build a subgraph consisting of top_node and all its descendants.
|
414
|
+
subgraph = get_subgraph(top_node, dependency_dict)
|
415
|
+
# Get a topologically sorted list where each dependency comes before the node that depends on it.
|
416
|
+
sorted_nodes = topological_sort(subgraph)
|
417
|
+
# Because you plan to import starting from the end of the list and work backwards,
|
418
|
+
# reverse the topological order so that the deepest dependency is imported first.
|
419
|
+
import_order = sorted_nodes[::-1]
|
420
|
+
return import_order
|
421
|
+
|
422
|
+
|
423
|
+
def find_top_nodes(dependency_dict):
|
424
|
+
all_nodes = set(dependency_dict.keys())
|
425
|
+
all_deps = {dep for deps in dependency_dict.values() for dep in deps}
|
426
|
+
return all_nodes - all_deps
|
427
|
+
|
428
|
+
|
429
|
+
def get_subgraph(top_node, dependency_dict):
|
430
|
+
visited = set()
|
431
|
+
|
432
|
+
def dfs(node):
|
433
|
+
if node not in visited:
|
434
|
+
visited.add(node)
|
435
|
+
for dep in dependency_dict.get(node, []):
|
436
|
+
dfs(dep)
|
437
|
+
|
438
|
+
dfs(top_node)
|
439
|
+
return {node: dependency_dict.get(node, []) for node in visited}
|
440
|
+
|
441
|
+
|
442
|
+
# TODO: is this function actually necessary anymore?
|
380
443
|
def topological_sort(objects):
|
381
|
-
graph = {
|
444
|
+
graph = {node: refs for node, refs in objects.items()}
|
382
445
|
visiting, visited = set(), set()
|
383
446
|
order = []
|
384
447
|
|
@@ -387,16 +450,15 @@ def topological_sort(objects):
|
|
387
450
|
raise ValueError("Circular reference detected")
|
388
451
|
if node not in visited:
|
389
452
|
visiting.add(node)
|
390
|
-
for
|
391
|
-
dfs(
|
453
|
+
for neighbor in graph.get(node, []):
|
454
|
+
dfs(neighbor)
|
392
455
|
visiting.remove(node)
|
393
456
|
visited.add(node)
|
394
457
|
order.append(node)
|
395
458
|
|
396
|
-
for
|
397
|
-
if
|
398
|
-
dfs(
|
399
|
-
|
459
|
+
for node in graph.keys():
|
460
|
+
if node not in visited:
|
461
|
+
dfs(node)
|
400
462
|
return order[::-1]
|
401
463
|
|
402
464
|
|
@@ -407,28 +469,19 @@ def create_timestamped_folder(base_dir, prefix=""):
|
|
407
469
|
folder_name = f"_{prefix}{timestamp}"
|
408
470
|
# Full path for the new folder
|
409
471
|
folder_path = Path(base_dir) / folder_name
|
410
|
-
|
411
|
-
if not os.path.exists(folder_path):
|
412
|
-
try:
|
413
|
-
os.makedirs(folder_path)
|
414
|
-
except FileExistsError:
|
415
|
-
pass
|
416
|
-
|
472
|
+
folder_path.mkdir(parents=True, exist_ok=True)
|
417
473
|
return folder_path
|
418
474
|
|
419
475
|
|
420
476
|
def write_code_to_file(folder_path, filename, code, codeLanguage):
|
421
477
|
extension = languageToExtension(codeLanguage)
|
422
478
|
filepath = write_string_to_file(folder_path, f"{filename}{extension}", code)
|
423
|
-
return
|
479
|
+
return filepath.relative_to(CWD).as_posix()
|
424
480
|
|
425
481
|
|
426
482
|
def write_string_to_file(folder, filename, content):
|
427
|
-
|
428
|
-
file_path
|
429
|
-
# Write the content to the file
|
430
|
-
with open(file_path, "w") as file:
|
431
|
-
file.write(content)
|
483
|
+
file_path = Path(folder) / filename
|
484
|
+
file_path.write_text(content)
|
432
485
|
return file_path
|
433
486
|
|
434
487
|
|
@@ -11,10 +11,6 @@ from .find_placeholders import tp
|
|
11
11
|
from .utils import process_refs
|
12
12
|
|
13
13
|
|
14
|
-
def get_args_var_name(var_name):
|
15
|
-
return f"{C.ARGS_PREFIX}{var_name}"
|
16
|
-
|
17
|
-
|
18
14
|
def get_section_type(p, id):
|
19
15
|
ui_type_id = p["sections"][id]["uiTypeId"]
|
20
16
|
ui_type = p["uiTypes"].get(ui_type_id) or BASE_UI_TYPES[ui_type_id]
|
@@ -144,7 +140,7 @@ def no_entered_value(value):
|
|
144
140
|
|
145
141
|
|
146
142
|
def get_var_name(var_name_mapping):
|
147
|
-
return f"
|
143
|
+
return f"{C.ARGS_PREFIX}x{len(var_name_mapping)}"
|
148
144
|
|
149
145
|
|
150
146
|
def get_for_section_id(p, section_id):
|
@@ -9,5 +9,16 @@ def remove_tp(x):
|
|
9
9
|
return x.lstrip(C.TEMPLATE_PREFIX)
|
10
10
|
|
11
11
|
|
12
|
-
def
|
13
|
-
|
12
|
+
def parse_template_var(template_str: str) -> tuple[str, str | None]:
|
13
|
+
suffixes = [
|
14
|
+
f"{tp(C.TEMPLATE_VAR_IMPORT_PATH_SUFFIX)}",
|
15
|
+
f"{tp(C.TEMPLATE_VAR_VERSION_SUFFIX)}",
|
16
|
+
f"{tp(C.TEMPLATE_VAR_FILE_PATH_SUFFIX)}",
|
17
|
+
]
|
18
|
+
|
19
|
+
for suffix in suffixes:
|
20
|
+
if template_str.endswith(suffix):
|
21
|
+
base_str = remove_tp(template_str[: -len(suffix)])
|
22
|
+
return base_str, remove_tp(suffix)
|
23
|
+
|
24
|
+
return template_str, None
|
setta/database/backup.py
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
import logging
|
2
|
-
import os
|
3
2
|
import shutil
|
4
3
|
import time
|
5
4
|
from datetime import datetime
|
@@ -54,7 +53,7 @@ def create_backup(db_path):
|
|
54
53
|
ensure_backup_dir_exists()
|
55
54
|
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
56
55
|
backup_filename = f"backup_{timestamp}.db"
|
57
|
-
backup_path =
|
56
|
+
backup_path = DB_BACKUP_FOLDER / backup_filename
|
58
57
|
logger.debug(f"creating backup: {backup_path}")
|
59
58
|
|
60
59
|
shutil.copy2(db_path, backup_path)
|
@@ -35,23 +35,28 @@ def save_artifacts(db, artifacts):
|
|
35
35
|
db.executemany(query, query_params)
|
36
36
|
|
37
37
|
|
38
|
-
def save_artifact_groups(db, artifact_groups):
|
38
|
+
def save_artifact_groups(db, artifact_groups, sections):
|
39
39
|
query = """
|
40
|
-
INSERT INTO ArtifactGroupId (id, name, data)
|
41
|
-
VALUES (:id, :name, :data)
|
40
|
+
INSERT INTO ArtifactGroupId (id, name, data, "order")
|
41
|
+
VALUES (:id, :name, :data, :order)
|
42
42
|
ON CONFLICT (id)
|
43
43
|
DO UPDATE SET
|
44
44
|
name = :name,
|
45
|
-
data = :data
|
45
|
+
data = :data,
|
46
|
+
"order" = :order
|
46
47
|
"""
|
47
48
|
query_params = []
|
48
49
|
for k, group in artifact_groups.items():
|
50
|
+
order = get_artifact_group_idx(k, sections)
|
51
|
+
if order is None:
|
52
|
+
continue
|
49
53
|
data_keys = group.keys() - {"name", "artifactTransforms"}
|
50
54
|
query_params.append(
|
51
55
|
{
|
52
56
|
"id": k,
|
53
57
|
"name": group["name"],
|
54
58
|
"data": json.dumps(filter_dict(group, data_keys)),
|
59
|
+
"order": order,
|
55
60
|
}
|
56
61
|
)
|
57
62
|
db.executemany(query, query_params)
|
@@ -83,3 +88,14 @@ def save_artifact_groups(db, artifact_groups):
|
|
83
88
|
)
|
84
89
|
|
85
90
|
db.executemany(query, query_params)
|
91
|
+
|
92
|
+
|
93
|
+
def get_artifact_group_idx(artifact_group_id, sections):
|
94
|
+
for section in sections.values():
|
95
|
+
try:
|
96
|
+
if "artifactGroupIds" in section:
|
97
|
+
idx = section["artifactGroupIds"].index(artifact_group_id)
|
98
|
+
return idx
|
99
|
+
except ValueError:
|
100
|
+
continue
|
101
|
+
return None
|
@@ -25,7 +25,7 @@ def save_project_details(db, p):
|
|
25
25
|
save_json_source_data(p)
|
26
26
|
remove_json_source_data(p)
|
27
27
|
save_artifacts(db, p["artifacts"])
|
28
|
-
save_artifact_groups(db, p["artifactGroups"])
|
28
|
+
save_artifact_groups(db, p["artifactGroups"], p["sections"])
|
29
29
|
save_code_info(db, p["codeInfo"])
|
30
30
|
save_code_info_col(db, p["codeInfoCols"])
|
31
31
|
save_ui_types(db, p["uiTypes"])
|
@@ -57,8 +57,11 @@ def load_sections(db, ids):
|
|
57
57
|
SELECT
|
58
58
|
originSectionId,
|
59
59
|
GROUP_CONCAT(id) AS artifactGroupIds
|
60
|
-
FROM
|
61
|
-
|
60
|
+
FROM (
|
61
|
+
SELECT id, originSectionId
|
62
|
+
FROM ArtifactGroupId
|
63
|
+
ORDER BY "order"
|
64
|
+
)
|
62
65
|
GROUP BY
|
63
66
|
originSectionId
|
64
67
|
) AS A ON S.id = A.originSectionId
|
@@ -110,14 +110,14 @@ def save_sections(db, sections, section_variants):
|
|
110
110
|
query = """
|
111
111
|
UPDATE ArtifactGroupId
|
112
112
|
SET originSectionId = :sectionId
|
113
|
-
WHERE id = :
|
113
|
+
WHERE id = :artifactGroupId
|
114
114
|
"""
|
115
115
|
for s in sections.values():
|
116
116
|
for a in s["artifactGroupIds"]:
|
117
117
|
query_params.append(
|
118
118
|
{
|
119
119
|
"sectionId": s["id"],
|
120
|
-
"
|
120
|
+
"artifactGroupId": a,
|
121
121
|
}
|
122
122
|
)
|
123
123
|
db.executemany(query, query_params)
|
setta/database/db_objs.py
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
import queue
|
2
2
|
import sqlite3
|
3
3
|
|
4
|
+
from setta.utils.constants import SETTA_FILES_FOLDER
|
5
|
+
|
4
6
|
|
5
7
|
class DB:
|
6
8
|
def __init__(self, path):
|
@@ -100,3 +102,7 @@ class DBQueue:
|
|
100
102
|
def __exit__(self, *args, **kwargs):
|
101
103
|
self.curr.__exit__(*args, **kwargs)
|
102
104
|
self.put_back_curr()
|
105
|
+
|
106
|
+
|
107
|
+
def get_default_db_path():
|
108
|
+
return SETTA_FILES_FOLDER / "setta.db"
|
@@ -1,9 +1,9 @@
|
|
1
1
|
import logging
|
2
|
-
import os
|
3
|
-
from pathlib import Path
|
4
2
|
|
5
3
|
import yaml
|
6
4
|
|
5
|
+
from setta.utils.constants import SETTA_FILES_FOLDER
|
6
|
+
|
7
7
|
logger = logging.getLogger(__name__)
|
8
8
|
|
9
9
|
|
@@ -26,7 +26,7 @@ def export_raw(db, filename):
|
|
26
26
|
yaml.add_representer(str, literal_presenter)
|
27
27
|
|
28
28
|
# For YAML export, PyYAML is used; ensure it's installed
|
29
|
-
filepath =
|
29
|
+
filepath = SETTA_FILES_FOLDER / f"{filename}_export.yaml"
|
30
30
|
logger.debug(f"saving raw db to {filepath}")
|
31
31
|
with open(filepath, "w") as file:
|
32
32
|
yaml.dump(database_export, file, allow_unicode=True, sort_keys=False)
|
@@ -1,16 +1,15 @@
|
|
1
|
-
import os
|
2
1
|
from collections import defaultdict
|
3
|
-
from pathlib import Path
|
4
2
|
|
5
3
|
import yaml
|
6
4
|
from yaml.representer import Representer
|
7
5
|
|
8
6
|
from setta.database.db.projects.load import load_full_project
|
7
|
+
from setta.utils.constants import SETTA_FILES_FOLDER
|
9
8
|
|
10
9
|
|
11
10
|
def get_configs_and_root_folder(db, filename):
|
12
11
|
# export defaultdict the same way as dict
|
13
12
|
yaml.add_representer(defaultdict, Representer.represent_dict)
|
14
13
|
configs = load_full_project(db)
|
15
|
-
root_folder =
|
14
|
+
root_folder = SETTA_FILES_FOLDER / f"{filename}_export"
|
16
15
|
return configs, root_folder
|
setta/database/settings_file.py
CHANGED
@@ -11,7 +11,7 @@ from setta.database.db.sections.jsonSource import (
|
|
11
11
|
remove_json_source_data,
|
12
12
|
save_json_source_data,
|
13
13
|
)
|
14
|
-
from setta.utils.constants import CONSTANTS_FOLDER, USER_SETTINGS
|
14
|
+
from setta.utils.constants import CONSTANTS_FOLDER, SETTA_FILES_FOLDER, USER_SETTINGS
|
15
15
|
from setta.utils.utils import get_absolute_path, save_json_to_file
|
16
16
|
|
17
17
|
logger = logging.getLogger(__name__)
|
@@ -63,8 +63,8 @@ class MetaSettingsFile:
|
|
63
63
|
self.path_seed_meta_settings = get_absolute_path(
|
64
64
|
__file__, CONSTANTS_FOLDER / "settingsProject.json"
|
65
65
|
)
|
66
|
-
self.path_default_settings = "setta-settings.json"
|
67
|
-
self.path_meta_settings = "setta-meta-settings.json"
|
66
|
+
self.path_default_settings = SETTA_FILES_FOLDER / "setta-settings.json"
|
67
|
+
self.path_meta_settings = SETTA_FILES_FOLDER / "setta-meta-settings.json"
|
68
68
|
self.load_seed_files()
|
69
69
|
|
70
70
|
def get_settings_paths(self):
|
setta/lsp/file_watcher.py
CHANGED
@@ -75,17 +75,34 @@ class LSPEventHandler(FileSystemEventHandler):
|
|
75
75
|
self.callback = callback
|
76
76
|
self.loop = loop
|
77
77
|
|
78
|
-
def
|
78
|
+
def on_created(self, event: FileSystemEvent):
|
79
79
|
if event.is_directory:
|
80
80
|
return
|
81
|
+
changes = [{"uri": self._path_to_uri(event.src_path), "type": 1}]
|
82
|
+
self._send_changes(changes)
|
81
83
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
84
|
+
def on_modified(self, event: FileSystemEvent):
|
85
|
+
if event.is_directory:
|
86
|
+
return
|
87
|
+
changes = [{"uri": self._path_to_uri(event.src_path), "type": 2}]
|
88
|
+
self._send_changes(changes)
|
89
|
+
|
90
|
+
def on_deleted(self, event: FileSystemEvent):
|
91
|
+
if event.is_directory:
|
92
|
+
return
|
93
|
+
changes = [{"uri": self._path_to_uri(event.src_path), "type": 3}]
|
94
|
+
self._send_changes(changes)
|
88
95
|
|
96
|
+
def on_moved(self, event: FileSystemEvent):
|
97
|
+
if event.is_directory:
|
98
|
+
return
|
99
|
+
# Treat move as deletion of the old path and creation of the new path.
|
100
|
+
changes_del = [{"uri": self._path_to_uri(event.src_path), "type": 3}]
|
101
|
+
changes_cre = [{"uri": self._path_to_uri(event.dest_path), "type": 1}]
|
102
|
+
self._send_changes(changes_del)
|
103
|
+
self._send_changes(changes_cre)
|
104
|
+
|
105
|
+
def _send_changes(self, changes):
|
89
106
|
if asyncio.iscoroutinefunction(self.callback):
|
90
107
|
self.loop.call_soon_threadsafe(
|
91
108
|
lambda: self.loop.create_task(self.callback(changes))
|
@@ -94,20 +111,4 @@ class LSPEventHandler(FileSystemEventHandler):
|
|
94
111
|
self.callback(changes)
|
95
112
|
|
96
113
|
def _path_to_uri(self, path: str) -> str:
|
97
|
-
"""Convert file path to URI format."""
|
98
114
|
return Path(path).as_uri()
|
99
|
-
|
100
|
-
def _get_change_type(self, event: FileSystemEvent) -> int:
|
101
|
-
"""
|
102
|
-
Convert watchdog event type to LSP change type.
|
103
|
-
1: Created
|
104
|
-
2: Changed
|
105
|
-
3: Deleted
|
106
|
-
"""
|
107
|
-
if event.event_type == "created":
|
108
|
-
return 1
|
109
|
-
elif event.event_type == "modified":
|
110
|
-
return 2
|
111
|
-
elif event.event_type == "deleted":
|
112
|
-
return 3
|
113
|
-
return 2 # Default to changed
|
setta/lsp/server.py
CHANGED
setta/lsp/writer.py
CHANGED
@@ -268,7 +268,7 @@ class LanguageServerWriter(LanguageServerInteractor):
|
|
268
268
|
asyncio.create_task(async_task)
|
269
269
|
|
270
270
|
def get_workspace_uri(self):
|
271
|
-
return f"file://{self.workspace_folder}"
|
271
|
+
return f"file://{self.workspace_folder}"
|
272
272
|
|
273
273
|
def get_base_uri(self, code_id):
|
274
274
|
return self.code_folder / f"{code_id}.py"
|
@@ -277,7 +277,7 @@ class LanguageServerWriter(LanguageServerInteractor):
|
|
277
277
|
def get_uri(self, code_id, virtual):
|
278
278
|
base_uri = self.get_base_uri(code_id)
|
279
279
|
prefix = "untitled:" if virtual else "file://"
|
280
|
-
uri = f"{prefix}{base_uri}"
|
280
|
+
uri = f"{prefix}{base_uri}"
|
281
281
|
if platform.system() == "Windows":
|
282
282
|
uri += "/" # need trailing slash on Windows for some reason
|
283
283
|
return uri
|
setta/routers/interactive.py
CHANGED
@@ -4,7 +4,8 @@ from pydantic import BaseModel
|
|
4
4
|
|
5
5
|
from setta.code_gen.create_runnable_scripts import (
|
6
6
|
generate_final_code_for_sections,
|
7
|
-
|
7
|
+
get_import_order_for_top_node,
|
8
|
+
prune_and_find_top_nodes,
|
8
9
|
sanitize_section_path_full_name,
|
9
10
|
)
|
10
11
|
from setta.code_gen.export_selected import (
|
@@ -13,6 +14,7 @@ from setta.code_gen.export_selected import (
|
|
13
14
|
get_section_code,
|
14
15
|
get_section_type,
|
15
16
|
)
|
17
|
+
from setta.code_gen.find_placeholders import parse_template_var
|
16
18
|
from setta.tasks.fns.utils import replace_template_vars_with_random_names
|
17
19
|
from setta.utils.constants import C
|
18
20
|
from setta.utils.utils import multireplace
|
@@ -23,7 +25,7 @@ router = APIRouter()
|
|
23
25
|
|
24
26
|
|
25
27
|
class UpdateInteractiveCodeRequest(BaseModel):
|
26
|
-
|
28
|
+
projects: list
|
27
29
|
|
28
30
|
|
29
31
|
class FormatCodeRequest(BaseModel):
|
@@ -37,7 +39,18 @@ async def route_update_interactive_code(
|
|
37
39
|
tasks=Depends(get_tasks),
|
38
40
|
lsp_writers=Depends(get_lsp_writers),
|
39
41
|
):
|
40
|
-
|
42
|
+
idx = 0
|
43
|
+
content = []
|
44
|
+
for p in x.projects:
|
45
|
+
initialContent = await update_interactive_code(p, tasks, lsp_writers, idx)
|
46
|
+
content.extend(initialContent)
|
47
|
+
idx += 1
|
48
|
+
|
49
|
+
inMemorySubprocessInfo = tasks.getInMemorySubprocessInfo()
|
50
|
+
return {"inMemorySubprocessInfo": inMemorySubprocessInfo, "content": content}
|
51
|
+
|
52
|
+
|
53
|
+
async def update_interactive_code(p, tasks, lsp_writers, idx):
|
41
54
|
exporter_obj = export_selected(
|
42
55
|
p, always_export_args_objs=False, force_include_template_var=True
|
43
56
|
)
|
@@ -46,11 +59,11 @@ async def route_update_interactive_code(
|
|
46
59
|
template_var_replacement_values = {}
|
47
60
|
for variant in p["sectionVariants"].values():
|
48
61
|
for t in variant["templateVars"]:
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
62
|
+
_, keyword_type = parse_template_var(t["keyword"])
|
63
|
+
if t["sectionId"] and keyword_type == C.TEMPLATE_VAR_IMPORT_PATH_SUFFIX:
|
64
|
+
template_var_replacement_values[
|
65
|
+
t["keyword"]
|
66
|
+
] = create_in_memory_module_name(p, t["sectionId"])
|
54
67
|
|
55
68
|
code_dict = await generate_final_code_for_sections(
|
56
69
|
p,
|
@@ -62,24 +75,29 @@ async def route_update_interactive_code(
|
|
62
75
|
template_var_replacement_values=template_var_replacement_values,
|
63
76
|
)
|
64
77
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
78
|
+
top_node_ids, section_dependencies = prune_and_find_top_nodes(
|
79
|
+
code_dict, p["runCodeBlocks"]
|
80
|
+
)
|
81
|
+
code_graph = []
|
82
|
+
project_config_id = p["projectConfig"]["id"]
|
83
|
+
for section_id in top_node_ids:
|
84
|
+
code_graph.append(
|
72
85
|
{
|
73
|
-
"
|
74
|
-
"
|
86
|
+
"subprocess_key": f"{project_config_id}-{section_id}-{idx}",
|
87
|
+
"code": code_dict[section_id]["code"],
|
88
|
+
"imports": get_import_order_for_top_node(
|
89
|
+
section_id, section_dependencies
|
90
|
+
),
|
91
|
+
"module_name": create_in_memory_module_name(p, section_id),
|
75
92
|
}
|
76
93
|
)
|
77
94
|
|
78
|
-
|
79
|
-
|
95
|
+
initialContent = await tasks.add_custom_fns(
|
96
|
+
code_graph,
|
80
97
|
to_cache=exporter_obj_in_memory,
|
81
98
|
)
|
82
|
-
|
99
|
+
|
100
|
+
return initialContent
|
83
101
|
|
84
102
|
|
85
103
|
@router.post(C.ROUTE_FORMAT_CODE)
|