dara-core 1.17.5__py3-none-any.whl → 1.18.0__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.
Files changed (68) hide show
  1. dara/core/__init__.py +2 -0
  2. dara/core/actions.py +1 -2
  3. dara/core/auth/basic.py +9 -9
  4. dara/core/auth/routes.py +5 -5
  5. dara/core/auth/utils.py +4 -4
  6. dara/core/base_definitions.py +15 -22
  7. dara/core/cli.py +8 -7
  8. dara/core/configuration.py +5 -2
  9. dara/core/css.py +1 -2
  10. dara/core/data_utils.py +2 -2
  11. dara/core/defaults.py +4 -7
  12. dara/core/definitions.py +6 -9
  13. dara/core/http.py +7 -3
  14. dara/core/interactivity/actions.py +28 -30
  15. dara/core/interactivity/any_data_variable.py +6 -5
  16. dara/core/interactivity/any_variable.py +4 -7
  17. dara/core/interactivity/data_variable.py +1 -1
  18. dara/core/interactivity/derived_data_variable.py +7 -6
  19. dara/core/interactivity/derived_variable.py +93 -33
  20. dara/core/interactivity/filtering.py +19 -27
  21. dara/core/interactivity/plain_variable.py +3 -2
  22. dara/core/interactivity/switch_variable.py +4 -4
  23. dara/core/internal/cache_store/base_impl.py +2 -1
  24. dara/core/internal/cache_store/cache_store.py +17 -5
  25. dara/core/internal/cache_store/keep_all.py +4 -1
  26. dara/core/internal/cache_store/lru.py +5 -1
  27. dara/core/internal/cache_store/ttl.py +4 -1
  28. dara/core/internal/cgroup.py +1 -1
  29. dara/core/internal/dependency_resolution.py +46 -10
  30. dara/core/internal/devtools.py +2 -2
  31. dara/core/internal/download.py +4 -3
  32. dara/core/internal/encoder_registry.py +7 -7
  33. dara/core/internal/execute_action.py +4 -10
  34. dara/core/internal/hashing.py +1 -3
  35. dara/core/internal/import_discovery.py +3 -4
  36. dara/core/internal/normalization.py +9 -13
  37. dara/core/internal/pandas_utils.py +3 -3
  38. dara/core/internal/pool/task_pool.py +16 -10
  39. dara/core/internal/pool/utils.py +5 -7
  40. dara/core/internal/pool/worker.py +3 -2
  41. dara/core/internal/port_utils.py +1 -1
  42. dara/core/internal/registries.py +9 -4
  43. dara/core/internal/registry.py +3 -1
  44. dara/core/internal/registry_lookup.py +7 -3
  45. dara/core/internal/routing.py +77 -44
  46. dara/core/internal/scheduler.py +13 -8
  47. dara/core/internal/settings.py +2 -2
  48. dara/core/internal/tasks.py +8 -14
  49. dara/core/internal/utils.py +11 -10
  50. dara/core/internal/websocket.py +18 -19
  51. dara/core/js_tooling/js_utils.py +23 -24
  52. dara/core/logging.py +3 -6
  53. dara/core/main.py +14 -11
  54. dara/core/metrics/cache.py +1 -1
  55. dara/core/metrics/utils.py +3 -3
  56. dara/core/persistence.py +1 -1
  57. dara/core/umd/dara.core.umd.js +149 -128
  58. dara/core/visual/components/__init__.py +2 -2
  59. dara/core/visual/components/fallback.py +3 -3
  60. dara/core/visual/css/__init__.py +30 -31
  61. dara/core/visual/dynamic_component.py +10 -11
  62. dara/core/visual/progress_updater.py +4 -3
  63. {dara_core-1.17.5.dist-info → dara_core-1.18.0.dist-info}/METADATA +10 -10
  64. dara_core-1.18.0.dist-info/RECORD +114 -0
  65. dara_core-1.17.5.dist-info/RECORD +0 -114
  66. {dara_core-1.17.5.dist-info → dara_core-1.18.0.dist-info}/LICENSE +0 -0
  67. {dara_core-1.17.5.dist-info → dara_core-1.18.0.dist-info}/WHEEL +0 -0
  68. {dara_core-1.17.5.dist-info → dara_core-1.18.0.dist-info}/entry_points.txt +0 -0
@@ -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
- try:
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
- try:
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.keys():
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 = BuildCacheDiff.full_diff()):
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 os.path.isdir(build_cache.build_config.js_config.local_entry):
490
- if copy_js:
491
- # Just move the directory to output
492
- js_folder_name = os.path.basename(build_cache.build_config.js_config.local_entry)
493
- shutil.copytree(
494
- build_cache.build_config.js_config.local_entry,
495
- os.path.join(build_cache.static_files_dir, js_folder_name),
496
- )
497
- else:
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') # nosec B605 # package_manager is validated
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, 'r', encoding='utf-8') as f:
553
+ with open(entry_template, encoding='utf-8') as f:
555
554
  entry_template_str = f.read()
556
- with open(vite_template, 'r', encoding='utf-8') as f:
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') # nosec B605 # package_manager is validated
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, 'r', encoding='utf-8') as f:
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) # pylint:disable=bad-str-strip-call
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((Path(BASE_DIR, 'jinja'))))
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) # timeout after 60s
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(): # pylint: disable=unused-variable
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
- with open(os.path.join(Path(BASE_DIR, 'jinja'), 'index_autojs.html'), 'r', encoding='utf-8') as fp:
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): # pylint: disable=unused-variable
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): # pylint: disable=unused-variable
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
 
@@ -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):
@@ -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() # track which object id's have already been seen
55
- default_size = getsizeof(0) # estimate sizeof object without __sizeof__
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: # do not double count the same object
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)
dara/core/persistence.py CHANGED
@@ -1,10 +1,10 @@
1
1
  import abc
2
2
  import json
3
3
  import os
4
+ from collections.abc import Awaitable
4
5
  from typing import (
5
6
  TYPE_CHECKING,
6
7
  Any,
7
- Awaitable,
8
8
  Callable,
9
9
  Dict,
10
10
  List,