setta 0.0.2__py3-none-any.whl → 0.0.3__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- 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)
|