dara-core 1.17.6__py3-none-any.whl → 1.18.1__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.
- dara/core/__init__.py +2 -0
- dara/core/actions.py +1 -2
- dara/core/auth/basic.py +9 -9
- dara/core/auth/routes.py +5 -5
- dara/core/auth/utils.py +4 -4
- dara/core/base_definitions.py +15 -22
- dara/core/cli.py +8 -7
- dara/core/configuration.py +5 -2
- dara/core/css.py +1 -2
- dara/core/data_utils.py +2 -2
- dara/core/defaults.py +4 -7
- dara/core/definitions.py +6 -9
- dara/core/http.py +7 -3
- dara/core/interactivity/actions.py +28 -30
- dara/core/interactivity/any_data_variable.py +6 -5
- dara/core/interactivity/any_variable.py +4 -7
- dara/core/interactivity/data_variable.py +1 -1
- dara/core/interactivity/derived_data_variable.py +7 -6
- dara/core/interactivity/derived_variable.py +93 -33
- dara/core/interactivity/filtering.py +19 -27
- dara/core/interactivity/plain_variable.py +3 -2
- dara/core/interactivity/switch_variable.py +4 -4
- dara/core/internal/cache_store/base_impl.py +2 -1
- dara/core/internal/cache_store/cache_store.py +17 -5
- dara/core/internal/cache_store/keep_all.py +4 -1
- dara/core/internal/cache_store/lru.py +5 -1
- dara/core/internal/cache_store/ttl.py +4 -1
- dara/core/internal/cgroup.py +1 -1
- dara/core/internal/dependency_resolution.py +46 -10
- dara/core/internal/devtools.py +2 -2
- dara/core/internal/download.py +4 -3
- dara/core/internal/encoder_registry.py +7 -7
- dara/core/internal/execute_action.py +4 -10
- dara/core/internal/hashing.py +1 -3
- dara/core/internal/import_discovery.py +3 -4
- dara/core/internal/normalization.py +9 -13
- dara/core/internal/pandas_utils.py +3 -3
- dara/core/internal/pool/task_pool.py +16 -10
- dara/core/internal/pool/utils.py +5 -7
- dara/core/internal/pool/worker.py +3 -2
- dara/core/internal/port_utils.py +1 -1
- dara/core/internal/registries.py +9 -4
- dara/core/internal/registry.py +3 -1
- dara/core/internal/registry_lookup.py +7 -3
- dara/core/internal/routing.py +77 -44
- dara/core/internal/scheduler.py +13 -8
- dara/core/internal/settings.py +2 -2
- dara/core/internal/tasks.py +8 -14
- dara/core/internal/utils.py +11 -10
- dara/core/internal/websocket.py +18 -19
- dara/core/js_tooling/js_utils.py +23 -24
- dara/core/logging.py +3 -6
- dara/core/main.py +14 -11
- dara/core/metrics/cache.py +1 -1
- dara/core/metrics/utils.py +3 -3
- dara/core/persistence.py +1 -1
- dara/core/umd/dara.core.umd.js +146 -128
- dara/core/visual/components/__init__.py +2 -2
- dara/core/visual/components/fallback.py +3 -3
- dara/core/visual/css/__init__.py +30 -31
- dara/core/visual/dynamic_component.py +10 -11
- dara/core/visual/progress_updater.py +4 -3
- {dara_core-1.17.6.dist-info → dara_core-1.18.1.dist-info}/METADATA +11 -10
- dara_core-1.18.1.dist-info/RECORD +114 -0
- dara_core-1.17.6.dist-info/RECORD +0 -114
- {dara_core-1.17.6.dist-info → dara_core-1.18.1.dist-info}/LICENSE +0 -0
- {dara_core-1.17.6.dist-info → dara_core-1.18.1.dist-info}/WHEEL +0 -0
- {dara_core-1.17.6.dist-info → dara_core-1.18.1.dist-info}/entry_points.txt +0 -0
dara/core/js_tooling/js_utils.py
CHANGED
|
@@ -15,6 +15,7 @@ See the License for the specific language governing permissions and
|
|
|
15
15
|
limitations under the License.
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
|
+
import contextlib
|
|
18
19
|
import importlib
|
|
19
20
|
import json
|
|
20
21
|
import os
|
|
@@ -236,10 +237,8 @@ class BuildCache(BaseModel):
|
|
|
236
237
|
|
|
237
238
|
# Create a symlink from the custom js folder into the static files directory
|
|
238
239
|
new_path = os.path.abspath(os.path.join(self.static_files_dir, self.build_config.js_config.local_entry))
|
|
239
|
-
|
|
240
|
+
with contextlib.suppress(FileNotFoundError):
|
|
240
241
|
os.unlink(new_path)
|
|
241
|
-
except FileNotFoundError:
|
|
242
|
-
pass
|
|
243
242
|
os.symlink(absolute_path, new_path)
|
|
244
243
|
|
|
245
244
|
# Create a symlink for the node modules in the custom_js folder
|
|
@@ -247,10 +246,8 @@ class BuildCache(BaseModel):
|
|
|
247
246
|
new_node_modules_path = os.path.abspath(
|
|
248
247
|
os.path.join(os.getcwd(), self.build_config.js_config.local_entry, 'node_modules')
|
|
249
248
|
)
|
|
250
|
-
|
|
249
|
+
with contextlib.suppress(FileNotFoundError):
|
|
251
250
|
os.unlink(new_node_modules_path)
|
|
252
|
-
except FileNotFoundError:
|
|
253
|
-
pass
|
|
254
251
|
os.symlink(node_modules_path, new_node_modules_path)
|
|
255
252
|
|
|
256
253
|
def get_importers(self) -> Dict[str, str]:
|
|
@@ -274,7 +271,7 @@ class BuildCache(BaseModel):
|
|
|
274
271
|
"""
|
|
275
272
|
py_modules = set()
|
|
276
273
|
|
|
277
|
-
for module in self.package_map
|
|
274
|
+
for module in self.package_map:
|
|
278
275
|
py_modules.add(module)
|
|
279
276
|
|
|
280
277
|
if 'dara.core' in py_modules:
|
|
@@ -434,13 +431,16 @@ def _get_module_file(module: str) -> str:
|
|
|
434
431
|
return cast(str, imported_module.__file__)
|
|
435
432
|
|
|
436
433
|
|
|
437
|
-
def rebuild_js(build_cache: BuildCache, build_diff: BuildCacheDiff =
|
|
434
|
+
def rebuild_js(build_cache: BuildCache, build_diff: Union[BuildCacheDiff, None] = None):
|
|
438
435
|
"""
|
|
439
436
|
Generic 'rebuild' function which bundles/prepares assets depending on the build mode chosen
|
|
440
437
|
|
|
441
438
|
:param build_cache: current build configuration cache
|
|
442
439
|
:param build_diff: the difference between the current build cache and the previous build cache
|
|
443
440
|
"""
|
|
441
|
+
if build_diff is None:
|
|
442
|
+
build_diff = BuildCacheDiff.full_diff()
|
|
443
|
+
|
|
444
444
|
# If we are in docker mode, skip the JS build
|
|
445
445
|
if os.environ.get('DARA_DOCKER_MODE', 'FALSE') == 'TRUE':
|
|
446
446
|
dev_logger.debug('Docker mode, skipping JS build')
|
|
@@ -485,17 +485,16 @@ def bundle_js(build_cache: BuildCache, copy_js: bool = False):
|
|
|
485
485
|
:param copy_js: whether to copy JS instead of symlinking it
|
|
486
486
|
"""
|
|
487
487
|
# If custom JS is present, symlink it
|
|
488
|
-
if build_cache.build_config.js_config is not None:
|
|
489
|
-
if
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
build_cache.symlink_js()
|
|
488
|
+
if build_cache.build_config.js_config is not None and os.path.isdir(build_cache.build_config.js_config.local_entry):
|
|
489
|
+
if copy_js:
|
|
490
|
+
# Just move the directory to output
|
|
491
|
+
js_folder_name = os.path.basename(build_cache.build_config.js_config.local_entry)
|
|
492
|
+
shutil.copytree(
|
|
493
|
+
build_cache.build_config.js_config.local_entry,
|
|
494
|
+
os.path.join(build_cache.static_files_dir, js_folder_name),
|
|
495
|
+
)
|
|
496
|
+
else:
|
|
497
|
+
build_cache.symlink_js()
|
|
499
498
|
|
|
500
499
|
# Determine template paths
|
|
501
500
|
entry_template = os.path.join(pathlib.Path(__file__).parent.absolute(), 'templates/_entry.template.tsx')
|
|
@@ -544,16 +543,16 @@ def bundle_js(build_cache: BuildCache, copy_js: bool = False):
|
|
|
544
543
|
|
|
545
544
|
cwd = os.getcwd()
|
|
546
545
|
os.chdir(build_cache.static_files_dir)
|
|
547
|
-
exit_code = os.system(f'{package_manager} install')
|
|
546
|
+
exit_code = os.system(f'{package_manager} install') # nosec B605 # package_manager is validated
|
|
548
547
|
if exit_code > 0:
|
|
549
548
|
raise SystemError(
|
|
550
549
|
"Failed to install the JS dependencies - there's likely a connection issue or a broken package"
|
|
551
550
|
)
|
|
552
551
|
|
|
553
552
|
# Load entry template as a string
|
|
554
|
-
with open(entry_template,
|
|
553
|
+
with open(entry_template, encoding='utf-8') as f:
|
|
555
554
|
entry_template_str = f.read()
|
|
556
|
-
with open(vite_template,
|
|
555
|
+
with open(vite_template, encoding='utf-8') as f:
|
|
557
556
|
vite_template_str = f.read()
|
|
558
557
|
|
|
559
558
|
# Convert importers dict to a string for injection into the template
|
|
@@ -574,7 +573,7 @@ def bundle_js(build_cache: BuildCache, copy_js: bool = False):
|
|
|
574
573
|
dev_logger.warning('App is in DEV mode, running `dara dev` CLI command alongside this process is required')
|
|
575
574
|
else:
|
|
576
575
|
# Run build pointed at the generated entry file
|
|
577
|
-
exit_code = os.system(f'{package_manager} run build')
|
|
576
|
+
exit_code = os.system(f'{package_manager} run build') # nosec B605 # package_manager is validated
|
|
578
577
|
if exit_code > 0:
|
|
579
578
|
raise SystemError('Failed to build the JS part of the project')
|
|
580
579
|
|
|
@@ -640,7 +639,7 @@ def build_autojs_template(html_template: str, build_cache: BuildCache, config: C
|
|
|
640
639
|
"""
|
|
641
640
|
settings = get_settings()
|
|
642
641
|
entry_template = os.path.join(pathlib.Path(__file__).parent.absolute(), 'templates/_entry_autojs.template.tsx')
|
|
643
|
-
with open(entry_template,
|
|
642
|
+
with open(entry_template, encoding='utf-8') as f:
|
|
644
643
|
entry_template_str = f.read()
|
|
645
644
|
|
|
646
645
|
importers_dict = build_cache.get_importers()
|
dara/core/logging.py
CHANGED
|
@@ -135,6 +135,7 @@ class LoggingMiddleware(BaseHTTPMiddleware):
|
|
|
135
135
|
# This is required so that requesting the body content doesn't hang the request
|
|
136
136
|
if request.headers.get('Content-Type') == 'application/json' and content_length < one_mb:
|
|
137
137
|
old_recieve = request._receive
|
|
138
|
+
|
|
138
139
|
# Add the debug logging into a new receive call that wraps the old one. This is required to make
|
|
139
140
|
# streaming requests and responses work as streaming sends further messages to trigger
|
|
140
141
|
# sending/receiving further data
|
|
@@ -192,7 +193,7 @@ def _print_stacktrace():
|
|
|
192
193
|
trc = 'Traceback (most recent call last):\n'
|
|
193
194
|
stackstr = trc + ''.join(traceback.format_list(stack))
|
|
194
195
|
if exc is not None:
|
|
195
|
-
stackstr += ' ' + traceback.format_exc().lstrip(trc)
|
|
196
|
+
stackstr += ' ' + traceback.format_exc().lstrip(trc)
|
|
196
197
|
return stackstr
|
|
197
198
|
|
|
198
199
|
|
|
@@ -204,11 +205,7 @@ class DaraProdFormatter(logging.Formatter):
|
|
|
204
205
|
|
|
205
206
|
@staticmethod
|
|
206
207
|
def _get_payload(record: logging.LogRecord) -> Dict[str, JsonSerializable]:
|
|
207
|
-
timestamp = time.strftime(
|
|
208
|
-
'%Y-%m-%dT%H:%M:%S', time.localtime(record.created)
|
|
209
|
-
) + '.%s' % int( # pylint:disable=consider-using-f-string
|
|
210
|
-
record.msecs
|
|
211
|
-
)
|
|
208
|
+
timestamp = time.strftime('%Y-%m-%dT%H:%M:%S', time.localtime(record.created)) + '.%s' % int(record.msecs)
|
|
212
209
|
if isinstance(record.msg, dict):
|
|
213
210
|
payload: Dict[str, JsonSerializable] = {
|
|
214
211
|
'timestamp': timestamp,
|
dara/core/main.py
CHANGED
|
@@ -14,6 +14,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
14
14
|
See the License for the specific language governing permissions and
|
|
15
15
|
limitations under the License.
|
|
16
16
|
"""
|
|
17
|
+
|
|
17
18
|
import asyncio
|
|
18
19
|
import os
|
|
19
20
|
import sys
|
|
@@ -91,10 +92,11 @@ def _start_application(config: Configuration):
|
|
|
91
92
|
os.environ['VITE_MANIFEST_PATH'] = f'{config.static_files_dir}/manifest.json'
|
|
92
93
|
os.environ['VITE_STATIC_PATH'] = config.static_files_dir
|
|
93
94
|
import fastapi_vite_dara
|
|
95
|
+
import fastapi_vite_dara.config
|
|
94
96
|
|
|
95
97
|
if len(config.pages) > 0:
|
|
96
98
|
BASE_DIR = Path(__file__).parent
|
|
97
|
-
jinja_templates = Jinja2Templates(directory=str(
|
|
99
|
+
jinja_templates = Jinja2Templates(directory=str(Path(BASE_DIR, 'jinja')))
|
|
98
100
|
jinja_templates.env.globals['vite_hmr_client'] = fastapi_vite_dara.vite_hmr_client
|
|
99
101
|
jinja_templates.env.globals['vite_asset'] = fastapi_vite_dara.vite_asset
|
|
100
102
|
jinja_templates.env.globals['static_url'] = fastapi_vite_dara.config.settings.static_url
|
|
@@ -107,7 +109,7 @@ def _start_application(config: Configuration):
|
|
|
107
109
|
|
|
108
110
|
# Configure the default executor for threads run via the async loop
|
|
109
111
|
loop = asyncio.get_event_loop()
|
|
110
|
-
loop.set_default_executor(ThreadPoolExecutor(max_workers=int(os.environ.get('DARA_NUM_COMPONENT_THREADS', 8))))
|
|
112
|
+
loop.set_default_executor(ThreadPoolExecutor(max_workers=int(os.environ.get('DARA_NUM_COMPONENT_THREADS', '8'))))
|
|
111
113
|
|
|
112
114
|
is_production = os.environ.get('DARA_DOCKER_MODE') == 'TRUE'
|
|
113
115
|
|
|
@@ -169,7 +171,7 @@ def _start_application(config: Configuration):
|
|
|
169
171
|
worker_parameters={'task_module': config.task_module},
|
|
170
172
|
max_workers=max_workers,
|
|
171
173
|
)
|
|
172
|
-
await task_pool.start(60)
|
|
174
|
+
await task_pool.start(60) # timeout after 60s
|
|
173
175
|
utils_registry.set('TaskPool', task_pool)
|
|
174
176
|
dev_logger.info('Task pool initialized')
|
|
175
177
|
|
|
@@ -337,15 +339,15 @@ def _start_application(config: Configuration):
|
|
|
337
339
|
|
|
338
340
|
# Start metrics server in a daemon thread
|
|
339
341
|
if os.environ.get('DARA_DISABLE_METRICS') != 'TRUE' and os.environ.get('DARA_TEST_FLAG', None) is None:
|
|
340
|
-
port = int(os.environ.get('DARA_METRICS_PORT', 10000))
|
|
342
|
+
port = int(os.environ.get('DARA_METRICS_PORT', '10000'))
|
|
341
343
|
start_http_server(port)
|
|
342
344
|
|
|
343
345
|
# Start profiling server in a daemon thread if explicitly enabled (only works on linux)
|
|
344
346
|
if os.environ.get('DARA_PYPPROF_PORT', None) is not None:
|
|
345
|
-
profiling_port = int(os.environ.get('DARA_PYPPROF_PORT', 10001))
|
|
347
|
+
profiling_port = int(os.environ.get('DARA_PYPPROF_PORT', '10001'))
|
|
346
348
|
dev_logger.warning('Starting cpu/memory profiling server', extra={'port': profiling_port})
|
|
347
349
|
|
|
348
|
-
from pypprof.net_http import start_pprof_server
|
|
350
|
+
from pypprof.net_http import start_pprof_server # pyright: ignore[reportMissingImports]
|
|
349
351
|
|
|
350
352
|
start_pprof_server(port=profiling_port)
|
|
351
353
|
|
|
@@ -358,7 +360,7 @@ def _start_application(config: Configuration):
|
|
|
358
360
|
app.include_router(core_api_router, prefix='/api/core')
|
|
359
361
|
|
|
360
362
|
@app.get('/api/{rest_of_path:path}')
|
|
361
|
-
async def not_found():
|
|
363
|
+
async def not_found():
|
|
362
364
|
raise HTTPException(status_code=404, detail='API endpoint not found')
|
|
363
365
|
|
|
364
366
|
if len(config.pages) > 0:
|
|
@@ -369,22 +371,23 @@ def _start_application(config: Configuration):
|
|
|
369
371
|
# Auto-js mode - serve the built template with UMDs
|
|
370
372
|
if build_cache.build_config.mode == BuildMode.AUTO_JS:
|
|
371
373
|
# Load template
|
|
372
|
-
|
|
374
|
+
template_path = os.path.join(Path(BASE_DIR, 'jinja'), 'index_autojs.html') # type: ignore
|
|
375
|
+
with open(template_path, encoding='utf-8') as fp:
|
|
373
376
|
template = fp.read()
|
|
374
377
|
|
|
375
378
|
# Generate tags for the template
|
|
376
379
|
template = build_autojs_template(template, build_cache, config)
|
|
377
380
|
|
|
378
381
|
@app.get('/{full_path:path}', include_in_schema=False, response_class=HTMLResponse)
|
|
379
|
-
async def serve_app(request: Request): #
|
|
382
|
+
async def serve_app(request: Request): # pyright: ignore[reportRedeclaration]
|
|
380
383
|
return HTMLResponse(template)
|
|
381
384
|
|
|
382
385
|
else:
|
|
383
386
|
# Otherwise serve the Vite template
|
|
384
387
|
|
|
385
388
|
@app.get('/{full_path:path}', include_in_schema=False, response_class=_TemplateResponse)
|
|
386
|
-
async def serve_app(request: Request): #
|
|
387
|
-
return jinja_templates.TemplateResponse(request, 'index.html')
|
|
389
|
+
async def serve_app(request: Request): # pyright: ignore[reportRedeclaration]
|
|
390
|
+
return jinja_templates.TemplateResponse(request, 'index.html') # type: ignore
|
|
388
391
|
|
|
389
392
|
return app
|
|
390
393
|
|
dara/core/metrics/cache.py
CHANGED
|
@@ -47,7 +47,7 @@ def format_bytes(num: Union[int, float]) -> str:
|
|
|
47
47
|
# We only shrink the number if we HAVEN'T reached the last unit.
|
|
48
48
|
num /= unit_step
|
|
49
49
|
|
|
50
|
-
return f'{num:.2f} {unit}'
|
|
50
|
+
return f'{num:.2f} {unit}' # type: ignore
|
|
51
51
|
|
|
52
52
|
|
|
53
53
|
class CacheMetricsTracker(BaseModel):
|
dara/core/metrics/utils.py
CHANGED
|
@@ -51,11 +51,11 @@ def total_size(o: object):
|
|
|
51
51
|
|
|
52
52
|
try:
|
|
53
53
|
all_handlers = {tuple: iter, list: iter, dict: dict_handler, set: iter, BaseModel: pydantic_handler}
|
|
54
|
-
seen = set()
|
|
55
|
-
default_size = getsizeof(0)
|
|
54
|
+
seen = set() # track which object id's have already been seen
|
|
55
|
+
default_size = getsizeof(0) # estimate sizeof object without __sizeof__
|
|
56
56
|
|
|
57
57
|
def sizeof(o):
|
|
58
|
-
if id(o) in seen:
|
|
58
|
+
if id(o) in seen: # do not double count the same object
|
|
59
59
|
return 0
|
|
60
60
|
seen.add(id(o))
|
|
61
61
|
s = getsizeof(o, default_size)
|