dara-core 1.16.14__py3-none-any.whl → 1.16.16__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.
@@ -76,6 +76,7 @@ class Configuration(BaseModel):
76
76
  components: List[ComponentTypeAnnotation]
77
77
  context_components: List[ComponentInstance]
78
78
  enable_devtools: bool
79
+ module_dependencies: Dict[str, str]
79
80
  live_reload: bool
80
81
  powered_by_causalens: bool
81
82
  pages: Dict[str, Page]
@@ -118,6 +119,10 @@ class Configuration(BaseModel):
118
119
  for comp in self.auth_config.component_config.model_dump().values():
119
120
  packages[comp['py_module']] = comp['js_module']
120
121
 
122
+ # Include explicit modules
123
+ for py_module, js_module in self.module_dependencies.items():
124
+ packages[py_module] = js_module
125
+
121
126
  return packages
122
127
 
123
128
 
@@ -137,6 +142,7 @@ class ConfigurationBuilder:
137
142
  registry_lookup: CustomRegistryLookup
138
143
  _actions: List[ActionDef]
139
144
  _components: List[ComponentTypeAnnotation]
145
+ _module_dependencies: Dict[str, str]
140
146
  _errors: List[str]
141
147
  enable_devtools: bool
142
148
  live_reload: bool
@@ -164,6 +170,7 @@ class ConfigurationBuilder:
164
170
  self.registry_lookup = {}
165
171
  self._actions = []
166
172
  self._components = []
173
+ self._module_dependencies = {}
167
174
  self._errors = []
168
175
  self.enable_devtools = False
169
176
  self.live_reload = False
@@ -266,6 +273,21 @@ class ConfigurationBuilder:
266
273
 
267
274
  return component_def
268
275
 
276
+ def add_module_dependency(self, py_module: str, js_module: str):
277
+ """
278
+ Explicitly add a module to the application. This is useful to ensure that a given module's assets are included in the build even
279
+ if no components from it are used explicitly in the application.
280
+
281
+ For example, when building a plugin that registers custom JS (e.g. in the form of a context component) that relies on the JS side of `@darajs/components`,
282
+ you could explicitly add the module in your plugin:
283
+
284
+ ```python
285
+ def my_plugin(config: ConfigurationBuilder):
286
+ config.add_module('dara.components', '@darajs/components')
287
+ ```
288
+ """
289
+ self._module_dependencies[py_module] = js_module
290
+
269
291
  def add_configuration(self, config: EndpointConfiguration):
270
292
  """
271
293
  Register an EndpointConfiguration instance with the application.
@@ -543,6 +565,7 @@ class ConfigurationBuilder:
543
565
  context_components=self.context_components,
544
566
  endpoint_configurations=self._endpoint_configurations,
545
567
  enable_devtools=self.enable_devtools,
568
+ module_dependencies=self._module_dependencies,
546
569
  live_reload=self.live_reload,
547
570
  powered_by_causalens=self.powered_by_causalens,
548
571
  package_tag_processors=self._package_tags_processors,
@@ -20,6 +20,8 @@ import sys
20
20
  from types import ModuleType
21
21
  from typing import Any, List, Optional, Set, Tuple, Type, Union
22
22
 
23
+ from typing_extensions import TypeGuard
24
+
23
25
  from dara.core.base_definitions import ActionDef, ActionImpl
24
26
  from dara.core.definitions import ComponentInstance, JsComponentDef, discover
25
27
  from dara.core.interactivity.any_variable import AnyVariable
@@ -31,6 +33,13 @@ def _is_component_subclass(obj: Any) -> bool:
31
33
  return inspect.isclass(obj) and issubclass(obj, ComponentInstance) and obj != ComponentInstance
32
34
 
33
35
 
36
+ def _is_component_instance(obj: Any) -> TypeGuard[ComponentInstance]:
37
+ try:
38
+ return isinstance(obj, ComponentInstance)
39
+ except Exception:
40
+ return False
41
+
42
+
34
43
  def _is_action_subclass(obj: Any) -> bool:
35
44
  return inspect.isclass(obj) and issubclass(obj, ActionImpl) and obj != ActionImpl
36
45
 
@@ -101,6 +110,8 @@ def run_discovery(
101
110
  # Look for subclasses of ComponentInstance or ActionImpl
102
111
  if _is_component_subclass(v):
103
112
  components.add(v)
113
+ elif _is_component_instance(v):
114
+ components.add(v.__class__)
104
115
  elif _is_action_subclass(v):
105
116
  actions.add(v)
106
117
  elif inspect.isfunction(v):
@@ -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 importlib
18
19
  import json
19
20
  import os
20
21
  import pathlib
@@ -419,6 +420,20 @@ def _py_version_to_js(package_name: str) -> str:
419
420
  return raw_version
420
421
 
421
422
 
423
+ def _get_module_file(module: str) -> str:
424
+ """
425
+ Get the file containing the given module
426
+
427
+ :param module: module name, e.g. 'dara.core'
428
+ """
429
+ try:
430
+ return cast(str, sys.modules[module].__file__)
431
+ except KeyError:
432
+ # module wasn't imported, try to load it explicitly
433
+ imported_module = importlib.import_module(module)
434
+ return cast(str, imported_module.__file__)
435
+
436
+
422
437
  def rebuild_js(build_cache: BuildCache, build_diff: BuildCacheDiff = BuildCacheDiff.full_diff()):
423
438
  """
424
439
  Generic 'rebuild' function which bundles/prepares assets depending on the build mode chosen
@@ -576,7 +591,7 @@ def prepare_autojs_assets(build_cache: BuildCache):
576
591
  :param config: the main app configuration
577
592
  """
578
593
  # copy over dara.core js/css into static dir
579
- core_path = os.path.dirname(cast(str, sys.modules['dara.core'].__file__))
594
+ core_path = os.path.dirname(_get_module_file('dara.core'))
580
595
  core_js_path = os.path.join(core_path, 'umd', 'dara.core.umd.js')
581
596
  core_css_path = os.path.join(core_path, 'umd', 'style.css')
582
597
  statics = os.path.join(pathlib.Path(__file__).parent.absolute(), 'statics')
@@ -599,7 +614,7 @@ def prepare_autojs_assets(build_cache: BuildCache):
599
614
  # Copy over js/css for all modules
600
615
  for module_name in py_modules:
601
616
  # Get path to the module
602
- module_path = os.path.dirname(cast(str, sys.modules[module_name].__file__))
617
+ module_path = os.path.dirname(_get_module_file(module_name))
603
618
 
604
619
  # Build paths to the JS and CSS assets for the given module
605
620
  # Note: this assumes assets structure of module/umd folder with the module.umd.js and style.css file
dara/core/logging.py CHANGED
@@ -254,13 +254,14 @@ class DaraDevFormatter(logging.Formatter):
254
254
  'INFO': (Back.GREEN, Fore.GREEN),
255
255
  'WARNING': (Back.YELLOW, Fore.YELLOW),
256
256
  }
257
+ default_color = (Back.GREEN, Fore.GREEN)
257
258
 
258
259
  def format(self, record: logging.LogRecord):
260
+ colors = self.level_to_color_map.get(record.levelname, self.default_color)
259
261
  if isinstance(record.msg, dict):
260
262
  payload = {**record.msg}
261
263
  fmt_time = self.formatTime(record, self.datefmt)
262
264
  spacer = ' ' * 4
263
- colors = self.level_to_color_map[record.levelname]
264
265
  base_msg = self.base_message_template % (
265
266
  fmt_time,
266
267
  colors[0],
@@ -303,7 +304,6 @@ class DaraDevFormatter(logging.Formatter):
303
304
  description = self.extra_template % (spacer, f'Description: {payload["description"]}')
304
305
  return base_msg + '\r\n' + file_details + description + content + '\r\n' + self.message_end
305
306
 
306
- colors = self.level_to_color_map[record.levelname]
307
307
  return self.base_message_template % (
308
308
  self.formatTime(record, self.datefmt),
309
309
  colors[0],