|
2 | 2 |
|
3 | 3 | import contextlib |
4 | 4 | import inspect |
5 | | -import json |
6 | 5 | import logging |
7 | 6 | import os |
8 | 7 | import re |
9 | | -import textwrap |
10 | 8 | from asyncio import iscoroutinefunction |
11 | 9 | from concurrent.futures import ThreadPoolExecutor |
12 | | -from copy import deepcopy |
13 | 10 | from fnmatch import fnmatch |
14 | 11 | from functools import wraps |
15 | 12 | from importlib import import_module |
16 | | -from pathlib import Path |
17 | | -from typing import TYPE_CHECKING, Any, Callable |
| 13 | +from typing import TYPE_CHECKING, Any, Awaitable, Callable |
18 | 14 | from uuid import UUID, uuid4 |
19 | 15 |
|
20 | 16 | import dill |
21 | | -import jsonpointer |
22 | | -import orjson |
23 | | -import reactpy |
24 | 17 | from asgiref.sync import async_to_sync |
25 | 18 | from channels.db import database_sync_to_async |
26 | 19 | from django.db.models import ManyToManyField, ManyToOneRel, prefetch_related_objects |
27 | 20 | from django.db.models.base import Model |
28 | 21 | from django.db.models.query import QuerySet |
29 | 22 | from django.http import HttpRequest, HttpResponse |
30 | 23 | from django.template import engines |
31 | | -from django.templatetags.static import static |
32 | 24 | from django.utils.encoding import smart_str |
33 | 25 | from reactpy import vdom_to_html |
34 | 26 | from reactpy.backend.types import Connection, Location |
|
41 | 33 | InvalidHostError, |
42 | 34 | ViewDoesNotExistError, |
43 | 35 | ) |
| 36 | +from reactpy_django.types import FuncParams, Inferred |
44 | 37 |
|
45 | 38 | if TYPE_CHECKING: |
46 | 39 | from collections.abc import Awaitable, Mapping, Sequence |
|
65 | 58 | + rf"({_OFFLINE_KWARG_PATTERN}|{_GENERIC_KWARG_PATTERN})*?" |
66 | 59 | + r"\s*%}" |
67 | 60 | ) |
68 | | -PYSCRIPT_COMPONENT_TEMPLATE = (Path(__file__).parent / "pyscript" / "component_template.py").read_text(encoding="utf-8") |
69 | | -PYSCRIPT_LAYOUT_HANDLER = (Path(__file__).parent / "pyscript" / "layout_handler.py").read_text(encoding="utf-8") |
70 | | -PYSCRIPT_DEFAULT_CONFIG: dict[str, Any] = {} |
71 | 61 | FILE_ASYNC_ITERATOR_THREAD = ThreadPoolExecutor(max_workers=1, thread_name_prefix="ReactPy-Django-FileAsyncIterator") |
72 | 62 |
|
73 | 63 |
|
@@ -441,72 +431,6 @@ def vdom_or_component_to_string( |
441 | 431 | raise ValueError(msg) |
442 | 432 |
|
443 | 433 |
|
444 | | -def render_pyscript_template(file_paths: Sequence[str], uuid: str, root: str): |
445 | | - """Inserts the user's code into the PyScript template using pattern matching.""" |
446 | | - from django.core.cache import caches |
447 | | - |
448 | | - from reactpy_django.config import REACTPY_CACHE |
449 | | - |
450 | | - # Create a valid PyScript executor by replacing the template values |
451 | | - executor = PYSCRIPT_COMPONENT_TEMPLATE.replace("UUID", uuid) |
452 | | - executor = executor.replace("return root()", f"return {root}()") |
453 | | - |
454 | | - # Fetch the user's PyScript code |
455 | | - all_file_contents: list[str] = [] |
456 | | - for file_path in file_paths: |
457 | | - # Try to get user code from cache |
458 | | - cache_key = create_cache_key("pyscript", file_path) |
459 | | - last_modified_time = os.stat(file_path).st_mtime |
460 | | - file_contents: str = caches[REACTPY_CACHE].get(cache_key, version=int(last_modified_time)) |
461 | | - if file_contents: |
462 | | - all_file_contents.append(file_contents) |
463 | | - |
464 | | - # If not cached, read from file system |
465 | | - else: |
466 | | - file_contents = Path(file_path).read_text(encoding="utf-8").strip() |
467 | | - all_file_contents.append(file_contents) |
468 | | - caches[REACTPY_CACHE].set(cache_key, file_contents, version=int(last_modified_time)) |
469 | | - |
470 | | - # Prepare the PyScript code block |
471 | | - user_code = "\n".join(all_file_contents) # Combine all user code |
472 | | - user_code = user_code.replace("\t", " ") # Normalize the text |
473 | | - user_code = textwrap.indent(user_code, " ") # Add indentation to match template |
474 | | - |
475 | | - # Insert the user code into the PyScript template |
476 | | - return executor.replace(" def root(): ...", user_code) |
477 | | - |
478 | | - |
479 | | -def extend_pyscript_config(extra_py: Sequence, extra_js: dict | str, config: dict | str) -> str: |
480 | | - """Extends ReactPy's default PyScript config with user provided values.""" |
481 | | - # Lazily set up the initial config in to wait for Django's static file system |
482 | | - if not PYSCRIPT_DEFAULT_CONFIG: |
483 | | - PYSCRIPT_DEFAULT_CONFIG.update({ |
484 | | - "packages": [ |
485 | | - f"reactpy=={reactpy.__version__}", |
486 | | - f"jsonpointer=={jsonpointer.__version__}", |
487 | | - "ssl", |
488 | | - ], |
489 | | - "js_modules": {"main": {static("reactpy_django/morphdom/morphdom-esm.js"): "morphdom"}}, |
490 | | - }) |
491 | | - |
492 | | - # Extend the Python dependency list |
493 | | - pyscript_config = deepcopy(PYSCRIPT_DEFAULT_CONFIG) |
494 | | - pyscript_config["packages"].extend(extra_py) |
495 | | - |
496 | | - # Extend the JavaScript dependency list |
497 | | - if extra_js and isinstance(extra_js, str): |
498 | | - pyscript_config["js_modules"]["main"].update(json.loads(extra_js)) |
499 | | - elif extra_js and isinstance(extra_js, dict): |
500 | | - pyscript_config["js_modules"]["main"].update(extra_py) |
501 | | - |
502 | | - # Update the config |
503 | | - if config and isinstance(config, str): |
504 | | - pyscript_config.update(json.loads(config)) |
505 | | - elif config and isinstance(config, dict): |
506 | | - pyscript_config.update(config) |
507 | | - return orjson.dumps(pyscript_config).decode("utf-8") |
508 | | - |
509 | | - |
510 | 434 | def save_component_params(args, kwargs, uuid) -> None: |
511 | 435 | """Saves the component parameters to the database. |
512 | 436 | This is used within our template tag in order to propogate |
|
0 commit comments