revisit 0.0.3__py2.py3-none-any.whl → 0.0.4__py2.py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
revisit/__init__.py CHANGED
@@ -1,54 +1,8 @@
1
- import importlib.metadata
2
- import pathlib
3
- import anywidget
4
- import traitlets
1
+ # Import main functions from core.py
2
+ from . import revisit
5
3
 
6
- try:
7
- __version__ = importlib.metadata.version("revisit_notebook_widget")
8
- except importlib.metadata.PackageNotFoundError:
9
- __version__ = "unknown"
4
+ # Import the Widget class from widget.py
5
+ from .widget import Widget
10
6
 
11
-
12
-
13
- # class Widget2(anywidget.AnyWidget):
14
-
15
- class TestWidget(anywidget.AnyWidget):
16
- _esm = """
17
- function render({ model, el }) {
18
- let button = document.createElement("button");
19
- button.innerHTML = `count is ${model.get("value")}`;
20
- button.addEventListener("click", () => {
21
- model.set("value", model.get("value") + 1);
22
- model.save_changes();
23
- });
24
- model.on("change:value", () => {
25
- button.innerHTML = `count is ${model.get("value")}`;
26
- });
27
- el.classList.add("counter-widget");
28
- el.appendChild(button);
29
- }
30
- export default { render };
31
- """
32
- _css = """
33
- .counter-widget button { color: white; font-size: 1.75rem; background-color: #ea580c; padding: 0.5rem 1rem; border: none; border-radius: 0.25rem; }
34
- .counter-widget button:hover { background-color: #9a3412; }
35
- """
36
- value = traitlets.Int(0).tag(sync=True)
37
-
38
-
39
-
40
- class Widget(anywidget.AnyWidget):
41
- _esm = pathlib.Path(__file__).parent / "static" / "widget.js"
42
- _css = pathlib.Path(__file__).parent / "static" / "widget.css"
43
- # value = traitlets.Int(0).tag(sync=True)
44
- config = traitlets.Dict({}).tag(sync=True)
45
- sequence = traitlets.List([]).tag(sync=True)
46
- internalWidget = TestWidget()
47
-
48
- @traitlets.observe('sequence')
49
- def _sequence_changed(self, change):
50
- self.internalWidget.value += 1
51
- # internalWidget.value += 1
52
- # print("{name} changed from {old} to {new}".format(**change))
53
-
54
-
7
+ # Expose them in the package's namespace
8
+ __all__ = [*revisit.__all__, "Widget"]
revisit/widget.py ADDED
@@ -0,0 +1,49 @@
1
+ import importlib.metadata
2
+ import pathlib
3
+ import anywidget # type: ignore
4
+ import traitlets # type: ignore
5
+
6
+ try:
7
+ __version__ = importlib.metadata.version("revisit_notebook_widget")
8
+ except importlib.metadata.PackageNotFoundError:
9
+ __version__ = "unknown"
10
+
11
+
12
+ # class Widget2(anywidget.AnyWidget):
13
+ class TestWidget(anywidget.AnyWidget):
14
+ _esm = """
15
+ function render({ model, el }) {
16
+ let button = document.createElement("button");
17
+ button.innerHTML = `count is ${model.get("value")}`;
18
+ button.addEventListener("click", () => {
19
+ model.set("value", model.get("value") + 1);
20
+ model.save_changes();
21
+ });
22
+ model.on("change:value", () => {
23
+ button.innerHTML = `count is ${model.get("value")}`;
24
+ });
25
+ el.classList.add("counter-widget");
26
+ el.appendChild(button);
27
+ }
28
+ export default { render };
29
+ """
30
+ _css = """
31
+ .counter-widget button { color: white; font-size: 1.75rem; background-color: #ea580c; padding: 0.5rem 1rem; border: none; border-radius: 0.25rem; }
32
+ .counter-widget button:hover { background-color: #9a3412; }
33
+ """
34
+ value = traitlets.Int(0).tag(sync=True)
35
+
36
+
37
+ class Widget(anywidget.AnyWidget):
38
+ _esm = pathlib.Path(__file__).parent / "static" / "widget.js"
39
+ _css = pathlib.Path(__file__).parent / "static" / "widget.css"
40
+ # value = traitlets.Int(0).tag(sync=True)
41
+ config = traitlets.Dict({}).tag(sync=True)
42
+ sequence = traitlets.List([]).tag(sync=True)
43
+ internalWidget = TestWidget()
44
+
45
+ @traitlets.observe('sequence')
46
+ def _sequence_changed(self, change):
47
+ self.internalWidget.value += 1
48
+ # internalWidget.value += 1
49
+ # print("{name} changed from {old} to {new}".format(**change))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: revisit
3
- Version: 0.0.3
3
+ Version: 0.0.4
4
4
  Requires-Dist: anywidget
5
5
  Requires-Dist: ipykernel>=6.29.5
6
6
  Requires-Dist: pydantic>=2.10.5
@@ -0,0 +1,9 @@
1
+ revisit/__init__.py,sha256=HlkO6ZGRm7gql0cU-oQvXTbcXGBdc0ck3yvuzu7_JX8,209
2
+ revisit/models.py,sha256=c-Hsd6XqeIP-hybH6MUovHG65XXueRhaMEVJZW1ViX0,120701
3
+ revisit/revisit.py,sha256=ChFtPmdXR8WPtSoUz9-NfvOcLVutSIJWUoWYxdhTE6o,19167
4
+ revisit/widget.py,sha256=ih0XhRjkih8vpeDr1SO8l8zMydZHLSXxVaFzvA8up_8,1722
5
+ revisit/static/widget.css,sha256=TLu5F6k0CvowQtmApPswG-JZUXYszo7a10dVWKnZsIg,647
6
+ revisit/static/widget.js,sha256=MlZ2jHlh_ADsUKMC5nZaSAmW73-4y2B57NcS3E5Jh3Q,187153
7
+ revisit-0.0.4.dist-info/METADATA,sha256=uzoyn8KDCUHZpGeHNgIRDC5i1so4Wr6qyfLO1H8tk9A,1261
8
+ revisit-0.0.4.dist-info/WHEEL,sha256=tkmg4JIqwd9H8mL30xA7crRmoStyCtGp0VWshokd1Jc,105
9
+ revisit-0.0.4.dist-info/RECORD,,
@@ -1,521 +0,0 @@
1
- from __future__ import annotations
2
- import json
3
- from . import models as rvt_models
4
- from pydantic import BaseModel, ValidationError # type: ignore
5
- from typing import List, Literal, get_origin, Optional, get_args, Any, Unpack, overload, get_type_hints
6
- from enum import Enum
7
- import csv
8
- from dataclasses import make_dataclass
9
- import re
10
-
11
-
12
- class _JSONableBaseModel(BaseModel):
13
- def __str__(self):
14
- return json.dumps(
15
- json.loads(
16
- self.root.model_dump_json(
17
- exclude_none=True, by_alias=True
18
- )),
19
- indent=4
20
- )
21
-
22
-
23
- # Private
24
- class _WrappedResponse(_JSONableBaseModel):
25
- root: rvt_models.Response
26
-
27
- def model_post_init(self, __context: Any) -> None:
28
- # Sets the root to be the instantiation of the individual response type instead
29
- # of the union response type
30
- self.root = self.root.root
31
-
32
- def set(self, overwrite=True, **kwargs) -> _WrappedResponse:
33
- for key, value in kwargs.items():
34
- # Disallow changing type
35
- if key == 'type':
36
- if getattr(self.root, key) != value:
37
- raise RevisitError(message=f"Cannot change type from {getattr(self.root, key)} to {value}")
38
- elif key != 'base':
39
- if overwrite is True or (overwrite is False and getattr(self.root, key) is None):
40
- setattr(self.root, key, value)
41
-
42
- # Re-validates the model. Returns the new model.
43
- self.root = _validate_response(self.root.__dict__)
44
- return self
45
-
46
-
47
- # Private
48
- class _WrappedComponent(_JSONableBaseModel):
49
- component_name__: str
50
- base__: Optional[_WrappedComponent] = None
51
- context__: Optional[dict] = None
52
- root: rvt_models.IndividualComponent
53
-
54
- def model_post_init(self, __context: Any) -> None:
55
- # Sets the root to be the instantiation of the individual response type instead
56
- # of the union response type
57
- self.root = self.root.root
58
-
59
- def responses(self, responses: List[_WrappedResponse]) -> _WrappedComponent:
60
- for item in responses:
61
- if not isinstance(item, _WrappedResponse):
62
- raise ValueError(f'Expecting type Response got {type(item)}')
63
- self.root.response = responses
64
- return self
65
-
66
- def get_response(self, id: str) -> _WrappedResponse | None:
67
- for response in self.root.response:
68
- if response.root.id == id:
69
- return response
70
- return None
71
-
72
- def edit_response(self, id: str, **kwargs) -> _WrappedComponent:
73
- for response in self.root.response:
74
- if response.root.id == id:
75
- response.set(**kwargs)
76
- return self
77
-
78
- raise ValueError('No response with given ID found.')
79
-
80
- def response_context(self, **kwargs):
81
- self.context__ = kwargs
82
-
83
- for type, data in self.context__.items():
84
- for response in self.root.response:
85
- if response.root.type == type or type == 'all':
86
- response.set(
87
- overwrite=False,
88
- **data
89
- )
90
-
91
- return self
92
-
93
-
94
- class _WrappedStudyMetadata(_JSONableBaseModel):
95
- root: rvt_models.StudyMetadata
96
-
97
-
98
- class _WrappedUIConfig(_JSONableBaseModel):
99
- root: rvt_models.UIConfig
100
-
101
-
102
- class _WrappedComponentBlock(_JSONableBaseModel):
103
- root: rvt_models.ComponentBlock
104
- component_objects__: List[_WrappedComponent]
105
-
106
- def __add__(self, other):
107
- """Allows addition operator to append to sequence components list."""
108
- if isinstance(other, _WrappedComponentBlock) or isinstance(other, _WrappedComponent):
109
- self.component_objects__.append(other)
110
- self.root.components.append(other.component_name__)
111
- return self
112
- return NotImplemented
113
-
114
- def from_data(self, data_list: list):
115
- return DataIterator(data_list, self)
116
-
117
-
118
- class _WrappedStudyConfig(_JSONableBaseModel):
119
- root: rvt_models.StudyConfig
120
-
121
-
122
- class _StudyConfigType(rvt_models.StudyConfigType):
123
- components: List[_WrappedComponent]
124
-
125
-
126
- class DataIterator:
127
- def __init__(self, data_list: List, parent_class: _WrappedComponentBlock):
128
- self.data = data_list
129
- self.parent_class = parent_class
130
-
131
- def component(self, **kwargs):
132
- for datum in self.data:
133
- current_dict = {}
134
- for key, value in kwargs.items():
135
- if key == 'parameters':
136
- param_dict = {}
137
- for param_key, param_value in value.items():
138
- if type(param_value) is str:
139
- param_datum_value = _extract_datum_value(param_value)
140
- if param_datum_value is not None:
141
- param_dict[param_key] = getattr(datum, param_datum_value)
142
- else:
143
- param_dict[param_key] = value
144
- else:
145
- param_dict[param_key] = value
146
- current_dict[key] = param_dict
147
- else:
148
- if type(value) is str:
149
- datum_value = _extract_datum_value(value)
150
- if datum_value is not None:
151
- if key == 'component_name__':
152
- current_dict[key] = str(getattr(datum, datum_value))
153
- else:
154
- current_dict[key] = getattr(datum, datum_value)
155
- else:
156
- current_dict[key] = value
157
- else:
158
- current_dict[key] = value
159
- curr_component = component(**current_dict)
160
- self.parent_class = self.parent_class + curr_component
161
- # Return the parent class calling iterator when component is finished.
162
- return self.parent_class
163
-
164
-
165
- # # -----------------------------------
166
- # # Factory Functions
167
- # # -----------------------------------
168
-
169
- # Component factory function
170
- # Allows additional items to be sent over to our Component model while keeping restrictions
171
- # for the model that is auto-generated.
172
-
173
- @overload
174
- def component(**kwargs: Unpack[rvt_models.MarkdownComponentType]) -> _WrappedComponent: ...
175
- @overload
176
- def component(**kwargs: Unpack[rvt_models.ReactComponentType]) -> _WrappedComponent: ...
177
- @overload
178
- def component(**kwargs: Unpack[rvt_models.ImageComponentType]) -> _WrappedComponent: ...
179
- @overload
180
- def component(**kwargs: Unpack[rvt_models.WebsiteComponentType]) -> _WrappedComponent: ...
181
- @overload
182
- def component(**kwargs: Unpack[rvt_models.QuestionnaireComponentType]) -> _WrappedComponent: ...
183
- @overload
184
- def component(**kwargs: Any) -> _WrappedComponent: ...
185
-
186
-
187
- def component(**kwargs) -> _WrappedComponent:
188
- # Inherit base
189
- base_component = kwargs.get('base__', None)
190
- if base_component:
191
- base_fields = vars(base_component.root)
192
- for key, value in base_fields.items():
193
- if key not in kwargs:
194
- kwargs[key] = value
195
- # Get kwargs to pass to individual component
196
- filter_kwargs = _get_filtered_kwargs(rvt_models.IndividualComponent, kwargs)
197
- # Grab response list
198
- response = filter_kwargs.get('response')
199
-
200
- # Sets default response list
201
- valid_response = []
202
- # If response present
203
- if response is not None:
204
- for r in response:
205
-
206
- # Prevent dict input
207
- if isinstance(r, dict):
208
- raise RevisitError(message='Cannot pass a dictionary directly into "Response" list.')
209
-
210
- response_type_hint = get_type_hints(rvt_models.Response).get('root')
211
- response_types = get_args(response_type_hint)
212
-
213
- # If wrapped, get root
214
- if isinstance(r, _WrappedResponse):
215
- valid_response.append(r.root)
216
-
217
- # If not wrapped but is valid response, append to list
218
- elif r.__class__ in response_types:
219
- valid_response.append(r)
220
-
221
- # If other unknown type, raise error
222
- else:
223
- raise RevisitError(message=f'Invalid type {type(r)} for "Response" class.')
224
-
225
- filter_kwargs['response'] = valid_response
226
-
227
- # Validate component
228
- _validate_component(filter_kwargs)
229
- base_model = rvt_models.IndividualComponent(**filter_kwargs)
230
-
231
- try:
232
- return _WrappedComponent(**kwargs, root=base_model)
233
- except ValidationError as e:
234
- raise RevisitError(e.errors())
235
-
236
-
237
- # Response factory function
238
- @overload
239
- def response(**kwargs: Unpack[rvt_models.NumericalResponseType]) -> _WrappedResponse: ...
240
- @overload
241
- def response(**kwargs: Unpack[rvt_models.ShortTextResponseType]) -> _WrappedResponse: ...
242
- @overload
243
- def response(**kwargs: Unpack[rvt_models.LongTextResponseType]) -> _WrappedResponse: ...
244
- @overload
245
- def response(**kwargs: Unpack[rvt_models.LikertResponseType]) -> _WrappedResponse: ...
246
- @overload
247
- def response(**kwargs: Unpack[rvt_models.DropdownResponseType]) -> _WrappedResponse: ...
248
- @overload
249
- def response(**kwargs: Unpack[rvt_models.SliderResponseType]) -> _WrappedResponse: ...
250
- @overload
251
- def response(**kwargs: Unpack[rvt_models.RadioResponseType]) -> _WrappedResponse: ...
252
- @overload
253
- def response(**kwargs: Unpack[rvt_models.CheckboxResponseType]) -> _WrappedResponse: ...
254
- @overload
255
- def response(**kwargs: Unpack[rvt_models.IFrameResponseType]) -> _WrappedResponse: ...
256
- @overload
257
- def response(**kwargs: Unpack[rvt_models.MatrixResponseType]) -> _WrappedResponse: ...
258
- @overload
259
- def response(**kwargs: Any) -> _WrappedResponse: ...
260
-
261
-
262
- def response(**kwargs) -> _WrappedResponse:
263
- filter_kwargs = _get_filtered_kwargs(rvt_models.Response, kwargs)
264
- _validate_response(filter_kwargs)
265
- base_model = rvt_models.Response(**filter_kwargs)
266
- # We've validated the response for a particular type. Now, how do we validate the wrapped component correctly?
267
- try:
268
- return _WrappedResponse(**kwargs, root=base_model)
269
- except ValidationError as e:
270
- raise RevisitError(e.errors())
271
-
272
-
273
- def studyMetadata(**kwargs: Unpack[rvt_models.StudyMetadataType]):
274
- filter_kwargs = _get_filtered_kwargs(rvt_models.StudyMetadata, kwargs)
275
- base_model = rvt_models.StudyMetadata(**filter_kwargs)
276
- return _WrappedStudyMetadata(**kwargs, root=base_model)
277
-
278
-
279
- def uiConfig(**kwargs: Unpack[rvt_models.UIConfigType]):
280
- filter_kwargs = _get_filtered_kwargs(rvt_models.UIConfig, kwargs)
281
- base_model = rvt_models.UIConfig(**filter_kwargs)
282
- return _WrappedUIConfig(**kwargs, root=base_model)
283
-
284
-
285
- def sequence(**kwargs: Unpack[rvt_models.ComponentBlockType]):
286
- filter_kwargs = _get_filtered_kwargs(rvt_models.ComponentBlock, kwargs)
287
- valid_component_names = []
288
- valid_components = []
289
- components = filter_kwargs.get('components')
290
- if components is not None:
291
- for c in components:
292
-
293
- # Prevent dict input
294
- if isinstance(c, dict):
295
- raise RevisitError(message='Cannot pass a dictionary directly into "Component" list.')
296
-
297
- # If wrapped, get root
298
- if isinstance(c, _WrappedComponent):
299
- valid_component_names.append(c.component_name__)
300
- valid_components.append(c)
301
-
302
- # If other unknown type, raise error
303
- else:
304
- raise RevisitError(message=f'Invalid type {type(c)} for "Component" class.')
305
-
306
- filter_kwargs['components'] = valid_component_names
307
- base_model = rvt_models.ComponentBlock(**filter_kwargs)
308
- return _WrappedComponentBlock(**kwargs, root=base_model, component_objects__=valid_components)
309
-
310
-
311
- @overload
312
- def studyConfig(**kwargs: Unpack[_StudyConfigType]) -> _WrappedStudyConfig: ...
313
- @overload
314
- def studyConfig(**kwargs: Any) -> _WrappedStudyConfig: ...
315
-
316
-
317
- def studyConfig(**kwargs: Unpack[_StudyConfigType]) -> _WrappedStudyConfig:
318
- filter_kwargs = _get_filtered_kwargs(rvt_models.StudyConfig, kwargs)
319
-
320
- root_list = ['studyMetadata', 'uiConfig', 'sequence']
321
- un_rooted_kwargs = {x: (y.root if x in root_list and hasattr(y, 'root') else y) for x, y in filter_kwargs.items()}
322
-
323
- study_sequence = filter_kwargs['sequence']
324
-
325
- # Merges components from the components list given and the components that are stored in the sequence
326
- un_rooted_kwargs['components'] = {
327
- comp.component_name__: comp.root for comp in un_rooted_kwargs.get('components', [])
328
- } | {
329
- comp.component_name__: comp.root for comp in study_sequence.component_objects__
330
- }
331
-
332
- base_model = rvt_models.StudyConfig(**un_rooted_kwargs)
333
- return _WrappedStudyConfig(**kwargs, root=base_model)
334
-
335
-
336
- # Function to parse the CSV and dynamically create data classes
337
- def data(file_path: str) -> List[Any]:
338
- # Read the first row to get the headers
339
- with open(file_path, mode='r') as csvfile:
340
- csv_reader = csv.DictReader(csvfile)
341
- headers = csv_reader.fieldnames
342
- if not headers:
343
- raise RevisitError(message="No headers found in CSV file.")
344
-
345
- # Create a data class with attributes based on the headers
346
- DataRow = make_dataclass("DataRow", [(header, Any) for header in headers])
347
-
348
- # Parse each row into an instance of the dynamically created data class
349
- data_rows = []
350
- for row in csv_reader:
351
- # Convert the row values to the appropriate types (e.g., int, float, bool)
352
- data = {key: _convert_value(value) for key, value in row.items()}
353
- data_row = DataRow(**data)
354
- data_rows.append(data_row)
355
-
356
- return data_rows
357
-
358
-
359
- # ------- PRIVATE FUNCTIONS ------------ #
360
-
361
- def _validate_component(kwargs: dict):
362
- component_mapping = _generate_possible_component_types()[1]
363
- if 'type' not in kwargs:
364
- raise RevisitError(message='"Type" is required on Component.')
365
- elif component_mapping.get(kwargs['type']) is None:
366
- raise RevisitError(message=f'Unexpected component type: {kwargs['type']}')
367
-
368
- try:
369
- return rvt_models.IndividualComponent.model_validate(kwargs).root
370
- except ValidationError as e:
371
- temp_errors = []
372
-
373
- for entry in e.errors():
374
- if entry['loc'][0] == component_mapping[kwargs['type']]:
375
- temp_errors.append(entry)
376
-
377
- if len(temp_errors) > 0:
378
- raise RevisitError(temp_errors)
379
- else:
380
- raise RevisitError(
381
- message='Unexpected error occurred during Component instantiation.'
382
- )
383
-
384
-
385
- # Call validate response when creating response component.
386
- def _validate_response(kwargs: dict):
387
- response_mapping = _generate_possible_response_types()[1]
388
- if 'type' not in kwargs:
389
- raise RevisitError(message='"Type" is required on Response.')
390
- else:
391
-
392
- type_value = kwargs.get('type')
393
-
394
- # Handles enum class type
395
- if isinstance(kwargs.get('type'), Enum):
396
- type_value = type_value.value
397
-
398
- if response_mapping.get(type_value) is None:
399
- raise RevisitError(message=f'Unexpected type: {type_value}')
400
-
401
- try:
402
- return rvt_models.Response.model_validate(kwargs).root
403
- except ValidationError as e:
404
- temp_errors = []
405
- for entry in e.errors():
406
- if entry['loc'][0] == response_mapping[type_value]:
407
- temp_errors.append(entry)
408
-
409
- if len(temp_errors) > 0:
410
- raise RevisitError(temp_errors)
411
- else:
412
- raise RevisitError(
413
- message='Unexpected error occurred during Response instantiation'
414
- )
415
-
416
-
417
- def _generate_possible_response_types():
418
- return _generate_possible_types(rvt_models.Response)
419
-
420
-
421
- def _generate_possible_component_types():
422
- return _generate_possible_types(rvt_models.IndividualComponent)
423
-
424
-
425
- # Generates mappings between the response class name and the
426
- # type string literal. Creates the reversed mapping as well.
427
- def _generate_possible_types(orig_cls):
428
- response_type_hint = get_type_hints(orig_cls).get('root')
429
- response_types = get_args(response_type_hint)
430
- type_hints = {}
431
- type_hints_reversed = {}
432
- for cls in response_types:
433
- curr_type = get_type_hints(cls).get('type')
434
- curr_origin = get_origin(get_type_hints(cls).get('type'))
435
- if curr_origin is Literal:
436
- type_hints[cls.__name__] = set([get_args(curr_type)[0]])
437
- type_hints_reversed[get_args(curr_type)[0]] = cls.__name__
438
- elif isinstance(curr_type, type) and issubclass(curr_type, Enum):
439
- enum_list = [member.value for member in curr_type]
440
- type_hints[cls.__name__] = set(enum_list)
441
- for item in enum_list:
442
- type_hints_reversed[item] = cls.__name__
443
-
444
- return (type_hints, type_hints_reversed)
445
-
446
-
447
- # Custom exception
448
- class RevisitError(Exception):
449
- def __init__(self, errors=None, message=None):
450
- # Case 1: Validation Errors From Pydantic
451
- # Case 2: Standard Error Message
452
- super().__init__('There was an error.')
453
- if message is None:
454
- pretty_message_list = pretty_error(errors)
455
- self.message = \
456
- f'There was an error. \n' \
457
- f'----------------------------------------------------' \
458
- f'\n\n' \
459
- f'{'\n\n'.join(pretty_message_list)}' \
460
- f'\n'
461
- else:
462
- self.message = \
463
- f'There was an error. \n' \
464
- f'----------------------------------------------------' \
465
- f'\n\n' \
466
- f'{message}' \
467
- f'\n'
468
-
469
- def __str__(self):
470
- return self.message
471
-
472
-
473
- def pretty_error(errors):
474
- custom_messages = {
475
- 'missing': 'Field is missing'
476
- }
477
- new_error_messages = []
478
- for error in errors:
479
- custom_message = custom_messages.get(error['type'])
480
- if custom_message:
481
- new_error_messages.append(f'Location: {error['loc']}\nError: Field "{error['loc'][-1]}" is required.')
482
- else:
483
- new_error_messages.append(f'Location: {error['loc']}\nError: {error['msg']}')
484
- return new_error_messages
485
-
486
-
487
- def _get_filtered_kwargs(class_type: Any, kwargs):
488
- try:
489
- possible_items = get_args(class_type.__fields__.get('root').annotation)
490
- except AttributeError:
491
- possible_items = [class_type]
492
-
493
- valid_fields = set()
494
- for model in possible_items:
495
- valid_fields.update(model.model_fields.keys())
496
-
497
- return {key: value for key, value in kwargs.items() if key in valid_fields}
498
-
499
-
500
- def _convert_value(value: str) -> Any:
501
- """Helper function to convert string values to appropriate data types."""
502
- value = value.strip()
503
- if value.lower() == "true":
504
- return True
505
- elif value.lower() == "false":
506
- return False
507
- try:
508
- if '.' in value:
509
- return float(value)
510
- else:
511
- return int(value)
512
- except ValueError:
513
- return value # Return as string if it cannot be converted
514
-
515
-
516
- def _extract_datum_value(text: str) -> str:
517
- # Use regex to match 'datum:thing' and capture 'thing'
518
- match = re.match(r'^datum:(\w+)$', text)
519
- if match:
520
- return match.group(1) # Return the captured part (i.e., 'thing')
521
- return None # Return None if the pattern doesn't match
@@ -1,9 +0,0 @@
1
- revisit/__init__.py,sha256=cDMK5FstjH7vrZQZabUmcZwpB3-hTZMHatVUu2gdKr0,1702
2
- revisit/revisit/__init__.py,sha256=7rhJeSoVZkNSNXUVHRIFQxkuxDUn_dtcjXnC2DQLtuk,19174
3
- revisit/revisit/models.py,sha256=c-Hsd6XqeIP-hybH6MUovHG65XXueRhaMEVJZW1ViX0,120701
4
- revisit/revisit/revisit.py,sha256=ChFtPmdXR8WPtSoUz9-NfvOcLVutSIJWUoWYxdhTE6o,19167
5
- revisit/static/widget.css,sha256=TLu5F6k0CvowQtmApPswG-JZUXYszo7a10dVWKnZsIg,647
6
- revisit/static/widget.js,sha256=MlZ2jHlh_ADsUKMC5nZaSAmW73-4y2B57NcS3E5Jh3Q,187153
7
- revisit-0.0.3.dist-info/METADATA,sha256=FF8AyslwC22_3OXEjXA1ZfE4yjzM1PsRbxx-zn6UHHo,1261
8
- revisit-0.0.3.dist-info/WHEEL,sha256=tkmg4JIqwd9H8mL30xA7crRmoStyCtGp0VWshokd1Jc,105
9
- revisit-0.0.3.dist-info/RECORD,,
File without changes
File without changes