revisit 0.0.5__tar.gz → 0.0.7__tar.gz
Sign up to get free protection for your applications and to get access to all the features.
- {revisit-0.0.5 → revisit-0.0.7}/PKG-INFO +15 -1
- {revisit-0.0.5 → revisit-0.0.7}/README.md +14 -0
- {revisit-0.0.5 → revisit-0.0.7}/pyproject.toml +1 -1
- {revisit-0.0.5 → revisit-0.0.7}/src/revisit/__init__.py +4 -0
- {revisit-0.0.5 → revisit-0.0.7}/src/revisit/revisit.py +101 -3
- {revisit-0.0.5 → revisit-0.0.7}/src/revisit/widget.py +4 -0
- {revisit-0.0.5 → revisit-0.0.7}/.gitignore +0 -0
- {revisit-0.0.5 → revisit-0.0.7}/src/revisit/models.py +0 -0
- {revisit-0.0.5 → revisit-0.0.7}/src/revisit/static/widget.css +0 -0
- {revisit-0.0.5 → revisit-0.0.7}/src/revisit/static/widget.js +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: revisit
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.7
|
4
4
|
Requires-Dist: anywidget
|
5
5
|
Requires-Dist: ipykernel>=6.29.5
|
6
6
|
Requires-Dist: pydantic>=2.10.5
|
@@ -58,3 +58,17 @@ yarn run dev
|
|
58
58
|
Open `example.ipynb` in JupyterLab, VS Code, or your favorite editor
|
59
59
|
to start developing. Changes made in `js/` will be reflected
|
60
60
|
in the notebook.
|
61
|
+
|
62
|
+
|
63
|
+
## CODE GEN
|
64
|
+
|
65
|
+
```bash
|
66
|
+
datamodel-codegen --input StudyConfigSchema.json --output models.py --custom-template-dir custom_templates --output-model-type pydantic_v2.BaseModel --additional-imports typing.TypedDict --input-file-type jsonschema --special-field-name-prefix we_are_going_to_replace_this && sed -i '' 's/we_are_going_to_replace_this_//g' src/revisit/models.py
|
67
|
+
```
|
68
|
+
|
69
|
+
## TESTS
|
70
|
+
|
71
|
+
```bash
|
72
|
+
cd revisit-py
|
73
|
+
python -m unittest tests.test_module_one
|
74
|
+
```
|
@@ -47,3 +47,17 @@ yarn run dev
|
|
47
47
|
Open `example.ipynb` in JupyterLab, VS Code, or your favorite editor
|
48
48
|
to start developing. Changes made in `js/` will be reflected
|
49
49
|
in the notebook.
|
50
|
+
|
51
|
+
|
52
|
+
## CODE GEN
|
53
|
+
|
54
|
+
```bash
|
55
|
+
datamodel-codegen --input StudyConfigSchema.json --output models.py --custom-template-dir custom_templates --output-model-type pydantic_v2.BaseModel --additional-imports typing.TypedDict --input-file-type jsonschema --special-field-name-prefix we_are_going_to_replace_this && sed -i '' 's/we_are_going_to_replace_this_//g' src/revisit/models.py
|
56
|
+
```
|
57
|
+
|
58
|
+
## TESTS
|
59
|
+
|
60
|
+
```bash
|
61
|
+
cd revisit-py
|
62
|
+
python -m unittest tests.test_module_one
|
63
|
+
```
|
@@ -7,6 +7,21 @@ from enum import Enum
|
|
7
7
|
import csv
|
8
8
|
from dataclasses import make_dataclass
|
9
9
|
import re
|
10
|
+
import os
|
11
|
+
import shutil
|
12
|
+
from . import widget as _widget
|
13
|
+
|
14
|
+
|
15
|
+
__all__ = [
|
16
|
+
"component",
|
17
|
+
"sequence",
|
18
|
+
"response",
|
19
|
+
"uiConfig",
|
20
|
+
"studyMetadata",
|
21
|
+
"studyConfig",
|
22
|
+
"data",
|
23
|
+
"widget"
|
24
|
+
]
|
10
25
|
|
11
26
|
|
12
27
|
class _JSONableBaseModel(BaseModel):
|
@@ -105,13 +120,24 @@ class _WrappedComponentBlock(_JSONableBaseModel):
|
|
105
120
|
|
106
121
|
def __add__(self, other):
|
107
122
|
"""Allows addition operator to append to sequence components list."""
|
108
|
-
if isinstance(other,
|
123
|
+
if isinstance(other, _WrappedComponent):
|
109
124
|
self.component_objects__.append(other)
|
110
125
|
self.root.components.append(other.component_name__)
|
111
126
|
return self
|
127
|
+
elif isinstance(other, _WrappedComponentBlock):
|
128
|
+
# Extend existing list of components with new set of components for tracking
|
129
|
+
self.component_objects__.extend(other.component_objects__)
|
130
|
+
|
131
|
+
# Add root object to components
|
132
|
+
self.root.components.append(other.root)
|
133
|
+
return self
|
112
134
|
return NotImplemented
|
113
135
|
|
114
|
-
def from_data(self, data_list
|
136
|
+
def from_data(self, data_list) -> DataIterator:
|
137
|
+
if not isinstance(data_list, list):
|
138
|
+
raise RevisitError(
|
139
|
+
message="'from_data' must take in a list of data rows. Use reVISit's 'data' method to parse a CSV file into a valid input."
|
140
|
+
)
|
115
141
|
return DataIterator(data_list, self)
|
116
142
|
|
117
143
|
|
@@ -356,6 +382,67 @@ def data(file_path: str) -> List[Any]:
|
|
356
382
|
return data_rows
|
357
383
|
|
358
384
|
|
385
|
+
def widget(study: _WrappedStudyConfig, revisitPath: str):
|
386
|
+
if not os.path.isdir(revisitPath):
|
387
|
+
raise RevisitError(message=f'"{revisitPath}" does not exist.')
|
388
|
+
|
389
|
+
extracted_paths = []
|
390
|
+
|
391
|
+
for component in study.root.components.values():
|
392
|
+
if hasattr(component.root, 'path'):
|
393
|
+
|
394
|
+
fileName = component.root.path.split('/')[-1]
|
395
|
+
|
396
|
+
if component.root.type == 'react-component':
|
397
|
+
dest = f"{revisitPath}/src/public/__revisit-widget/assets/{fileName}"
|
398
|
+
else:
|
399
|
+
dest = f"{revisitPath}/public/__revisit-widget/assets/{fileName}"
|
400
|
+
|
401
|
+
extracted_paths.append({
|
402
|
+
"src": component.root.path,
|
403
|
+
"dest": dest
|
404
|
+
})
|
405
|
+
|
406
|
+
newPath = f"__revisit-widget/assets/{fileName}"
|
407
|
+
component.root.path = newPath
|
408
|
+
|
409
|
+
uiConfig = study.root.uiConfig
|
410
|
+
if uiConfig.helpTextPath is not None:
|
411
|
+
|
412
|
+
fileName = uiConfig.helpTextPath.split('/')[-1]
|
413
|
+
dest = f"{revisitPath}/public/__revisit-widget/assets/{fileName}"
|
414
|
+
|
415
|
+
extracted_paths.append({
|
416
|
+
"src": uiConfig.helpTextPath,
|
417
|
+
"dest": dest
|
418
|
+
})
|
419
|
+
|
420
|
+
newPath = f"__revisit-widget/assets/{fileName}"
|
421
|
+
uiConfig.helpTextPath = newPath
|
422
|
+
|
423
|
+
if uiConfig.logoPath is not None:
|
424
|
+
|
425
|
+
fileName = uiConfig.logoPath.split('/')[-1]
|
426
|
+
|
427
|
+
dest = f"{revisitPath}/public/__revisit-widget/assets/{fileName}"
|
428
|
+
|
429
|
+
extracted_paths.append({
|
430
|
+
"src": uiConfig.logoPath,
|
431
|
+
"dest": dest
|
432
|
+
})
|
433
|
+
|
434
|
+
newPath = f"__revisit-widget/assets/{fileName}"
|
435
|
+
uiConfig.logoPath = newPath
|
436
|
+
|
437
|
+
# Copy all files
|
438
|
+
for item in extracted_paths:
|
439
|
+
_copy_file(item['src'], item['dest'])
|
440
|
+
|
441
|
+
w = _widget.Widget()
|
442
|
+
w.config = json.loads(study.__str__())
|
443
|
+
return w
|
444
|
+
|
445
|
+
|
359
446
|
# ------- PRIVATE FUNCTIONS ------------ #
|
360
447
|
|
361
448
|
def _validate_component(kwargs: dict):
|
@@ -486,7 +573,7 @@ def pretty_error(errors):
|
|
486
573
|
|
487
574
|
def _get_filtered_kwargs(class_type: Any, kwargs):
|
488
575
|
try:
|
489
|
-
possible_items = get_args(class_type.
|
576
|
+
possible_items = get_args(class_type.model_fields.get('root').annotation)
|
490
577
|
except AttributeError:
|
491
578
|
possible_items = [class_type]
|
492
579
|
|
@@ -519,3 +606,14 @@ def _extract_datum_value(text: str) -> str:
|
|
519
606
|
if match:
|
520
607
|
return match.group(1) # Return the captured part (i.e., 'thing')
|
521
608
|
return None # Return None if the pattern doesn't match
|
609
|
+
|
610
|
+
|
611
|
+
def _copy_file(src: str, dest: str):
|
612
|
+
# Check if file exists
|
613
|
+
if not os.path.exists(src):
|
614
|
+
raise RevisitError(message=f'File "{src}" not found.')
|
615
|
+
|
616
|
+
os.makedirs(os.path.dirname(dest), exist_ok=True)
|
617
|
+
|
618
|
+
print(f'Copying file from {src} to {dest}')
|
619
|
+
shutil.copyfile(src, dest)
|
@@ -47,3 +47,7 @@ class Widget(anywidget.AnyWidget):
|
|
47
47
|
self.internalWidget.value += 1
|
48
48
|
# internalWidget.value += 1
|
49
49
|
# print("{name} changed from {old} to {new}".format(**change))
|
50
|
+
|
51
|
+
# def set(self, study: rvt._WrappedStudyConfig):
|
52
|
+
# self.config = json.loads(study.__str__())
|
53
|
+
# return self
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|