From 7d745cae54ab5ecd458ae27852ed2a65128f9f55 Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Fri, 24 Jun 2022 01:16:59 -0700 Subject: [PATCH 1/4] get_component utility function --- src/django_idom/__init__.py | 4 ++-- src/django_idom/apps.py | 4 ++-- src/django_idom/config.py | 4 ++-- src/django_idom/templatetags/idom.py | 4 ++-- src/django_idom/utils.py | 27 +++++++++++++++++++-------- tests/test_app/tests/test_utils.py | 14 ++++++++++++++ 6 files changed, 41 insertions(+), 16 deletions(-) create mode 100644 tests/test_app/tests/test_utils.py diff --git a/src/django_idom/__init__.py b/src/django_idom/__init__.py index af2dec38..f936b88c 100644 --- a/src/django_idom/__init__.py +++ b/src/django_idom/__init__.py @@ -1,7 +1,7 @@ -from . import hooks +from . import hooks, utils from .websocket.consumer import IdomWebsocket from .websocket.paths import IDOM_WEBSOCKET_PATH __version__ = "1.0.0" -__all__ = ["IDOM_WEBSOCKET_PATH", "IdomWebsocket", "hooks"] +__all__ = ["IDOM_WEBSOCKET_PATH", "IdomWebsocket", "hooks", "utils"] diff --git a/src/django_idom/apps.py b/src/django_idom/apps.py index 6a963664..84aa1891 100644 --- a/src/django_idom/apps.py +++ b/src/django_idom/apps.py @@ -1,6 +1,6 @@ from django.apps import AppConfig -from django_idom.utils import ComponentPreloader +from django_idom.utils import _ComponentPreloader class DjangoIdomConfig(AppConfig): @@ -8,4 +8,4 @@ class DjangoIdomConfig(AppConfig): def ready(self): # Populate the IDOM component registry when Django is ready - ComponentPreloader().register_all() + _ComponentPreloader().register_all() diff --git a/src/django_idom/config.py b/src/django_idom/config.py index cb037ed1..7d8cd294 100644 --- a/src/django_idom/config.py +++ b/src/django_idom/config.py @@ -2,10 +2,10 @@ from django.conf import settings from django.core.cache import DEFAULT_CACHE_ALIAS, caches -from idom.core.types import ComponentConstructor +from idom.core.types import ComponentType -IDOM_REGISTERED_COMPONENTS: Dict[str, ComponentConstructor] = {} +IDOM_REGISTERED_COMPONENTS: Dict[str, ComponentType] = {} IDOM_WEBSOCKET_URL = getattr(settings, "IDOM_WEBSOCKET_URL", "idom/") IDOM_WS_MAX_RECONNECT_TIMEOUT = getattr( diff --git a/src/django_idom/templatetags/idom.py b/src/django_idom/templatetags/idom.py index 5707733d..9a2c43ac 100644 --- a/src/django_idom/templatetags/idom.py +++ b/src/django_idom/templatetags/idom.py @@ -6,7 +6,7 @@ from django.urls import reverse from django_idom.config import IDOM_WEBSOCKET_URL, IDOM_WS_MAX_RECONNECT_TIMEOUT -from django_idom.utils import _register_component +from django_idom.utils import register_component IDOM_WEB_MODULES_URL = reverse("idom:web_modules", args=["x"])[:-1][1:] @@ -15,7 +15,7 @@ @register.inclusion_tag("idom/component.html") def component(_component_id_, **kwargs): - _register_component(_component_id_) + register_component(_component_id_) class_ = kwargs.pop("class", "") json_kwargs = json.dumps(kwargs, separators=(",", ":")) diff --git a/src/django_idom/utils.py b/src/django_idom/utils.py index 81783013..fa826a81 100644 --- a/src/django_idom/utils.py +++ b/src/django_idom/utils.py @@ -4,10 +4,11 @@ import re from fnmatch import fnmatch from importlib import import_module -from typing import Set +from typing import Set, Union from django.template import engines from django.utils.encoding import smart_str +from idom.types import ComponentType from django_idom.config import IDOM_REGISTERED_COMPONENTS @@ -16,11 +17,21 @@ _logger = logging.getLogger(__name__) -def _register_component(full_component_name: str) -> None: - if full_component_name in IDOM_REGISTERED_COMPONENTS: +def get_component(dotted_path: str) -> Union[ComponentType, None]: + """Fetches a component given it's Python dotted path, if it exists.""" + try: + return IDOM_REGISTERED_COMPONENTS[dotted_path] + except KeyError: + _logger.debug("A component named %s was never registered!", dotted_path) + return None + + +def register_component(dotted_path: str) -> None: + """Registers a component given it's Python dotted path.""" + if dotted_path in IDOM_REGISTERED_COMPONENTS: return - module_name, component_name = full_component_name.rsplit(".", 1) + module_name, component_name = dotted_path.rsplit(".", 1) try: module = import_module(module_name) @@ -36,11 +47,11 @@ def _register_component(full_component_name: str) -> None: f"Module {module_name!r} has no component named {component_name!r}" ) from error - IDOM_REGISTERED_COMPONENTS[full_component_name] = component - _logger.debug("IDOM has registered component %s", full_component_name) + IDOM_REGISTERED_COMPONENTS[dotted_path] = component + _logger.debug("IDOM has registered component %s", dotted_path) -class ComponentPreloader: +class _ComponentPreloader: def register_all(self): """Registers all IDOM components found within Django templates.""" # Get all template folder paths @@ -123,7 +134,7 @@ def _register_components(self, components: Set) -> None: for component in components: try: _logger.info("IDOM preloader has detected component %s", component) - _register_component(component) + register_component(component) except Exception: _logger.error( "\033[91m" diff --git a/tests/test_app/tests/test_utils.py b/tests/test_app/tests/test_utils.py new file mode 100644 index 00000000..007a227f --- /dev/null +++ b/tests/test_app/tests/test_utils.py @@ -0,0 +1,14 @@ +from django.test import TestCase + +from django_idom.utils import get_component + + +class RegexTests(TestCase): + def test_get_component(self): + real_component = get_component("test_app.components.HelloWorld") + self.assertIsNotNone(real_component) + self.assertEqual(getattr(real_component, "__name__", None), "HelloWorld") + + fake_component = get_component("test_app.components.FakeComponent") + self.assertIsNone(fake_component) + From 1f43a57841f8b3a4ec3d0a80bf4fede81052f7cf Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Fri, 24 Jun 2022 01:28:56 -0700 Subject: [PATCH 2/4] fix tests --- requirements/test-env.txt | 2 +- tests/test_app/tests/test_utils.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/requirements/test-env.txt b/requirements/test-env.txt index 6f2e151e..61ee65ee 100644 --- a/requirements/test-env.txt +++ b/requirements/test-env.txt @@ -1,3 +1,3 @@ django -selenium +selenium <= 4.2.0 twisted diff --git a/tests/test_app/tests/test_utils.py b/tests/test_app/tests/test_utils.py index 007a227f..4f189c91 100644 --- a/tests/test_app/tests/test_utils.py +++ b/tests/test_app/tests/test_utils.py @@ -11,4 +11,3 @@ def test_get_component(self): fake_component = get_component("test_app.components.FakeComponent") self.assertIsNone(fake_component) - From 7103d2b488adcc6dabd7f2d53e5338ebe686f38f Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Fri, 24 Jun 2022 01:31:47 -0700 Subject: [PATCH 3/4] change debug level to info --- src/django_idom/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/django_idom/utils.py b/src/django_idom/utils.py index fa826a81..2c945bf2 100644 --- a/src/django_idom/utils.py +++ b/src/django_idom/utils.py @@ -22,7 +22,7 @@ def get_component(dotted_path: str) -> Union[ComponentType, None]: try: return IDOM_REGISTERED_COMPONENTS[dotted_path] except KeyError: - _logger.debug("A component named %s was never registered!", dotted_path) + _logger.info("A component named %s was never registered!", dotted_path) return None From bafafabe6e7eee583fb9e90f12837e2d51593f2d Mon Sep 17 00:00:00 2001 From: Archmonger <16909269+Archmonger@users.noreply.github.com> Date: Thu, 30 Jun 2022 10:33:35 -0700 Subject: [PATCH 4/4] initial draft of docs --- docs/features/utilities.md | 17 +++++++++++++++++ mkdocs.yml | 1 + src/django_idom/utils.py | 1 - 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 docs/features/utilities.md diff --git a/docs/features/utilities.md b/docs/features/utilities.md new file mode 100644 index 00000000..e4d5191f --- /dev/null +++ b/docs/features/utilities.md @@ -0,0 +1,17 @@ +## Get Component + +You can fetch any of your IDOM components from other files by using `get_component`. + +```python title="components.py" +from idom import component +from django_idom.utils import get_component + +@component +def MyComponent(): + hello_world = get_component("example_project.my_app.components.HelloWorld") + return hello_world(recipient="World") +``` + +??? question "Should I use this instead of `#!python import`?" + + TBD \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index 1cfff5ab..fbf664ab 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -11,6 +11,7 @@ nav: - Exclusive Features: - Hooks: features/hooks.md - Template Tag: features/templatetag.md + - Utilities: features/utilities.md - Contribute: - Code: contribute/django-idom.md - Docs: contribute/docs.md diff --git a/src/django_idom/utils.py b/src/django_idom/utils.py index 2c945bf2..fc82b0ab 100644 --- a/src/django_idom/utils.py +++ b/src/django_idom/utils.py @@ -23,7 +23,6 @@ def get_component(dotted_path: str) -> Union[ComponentType, None]: return IDOM_REGISTERED_COMPONENTS[dotted_path] except KeyError: _logger.info("A component named %s was never registered!", dotted_path) - return None def register_component(dotted_path: str) -> None: