Skip to content

Commit c43a583

Browse files
chgiesseChristian GiesselBSd3v
authored
Add global Request Adapter (#6)
* ∙ - remove contextvar from flask and quart only FastApi now relies on that ∙ - backend __init__ now holds the global request adapter and backend which get set on app initialisation ∙ request adapter and server can now be call from everywhere after the app initialised ∙ - added normal top level imports because the modules get matching loaded - but bad Import Error message when quart or equivilent are not installed ∙ - added _ as prefix to backends to avoid importing errors with their underlying ∙ - Can now move to remove unnecessary passing of the server object ∙ * Moved get_server_type to backends * ∙ moved async validation to validation ∙ replaced request.get_path with request.path ∙ * Moved custom backend check to _validation.py * Removed server injection of server methods - they use self.server now * removed use_async from dispatch server methods and use dash_app._use_async removed remaining set request process from flask * adding custom error handling per backend, tests and adjustments to the flow. Made endpoints for downloading the reqs * adjusments for formatting * adjustment to retest backend * Added Dash app as type to servers * adding missing reqs association * Addedd basic typing to servers * fixing minor linting issues * Fixed weird AI shit * Cleanup before heavy pull * Merged latest changes * f rebase * f rebase * Added Dash app as type to servers * Addedd basic typing to servers --------- Co-authored-by: Christian Giessel <[email protected]> Co-authored-by: BSd3v <[email protected]>
1 parent 465e45e commit c43a583

File tree

14 files changed

+831
-592
lines changed

14 files changed

+831
-592
lines changed

dash/_callback.py

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,8 @@
1+
from typing import Callable, Optional, Any, List, Tuple, Union
2+
from functools import wraps
13
import collections
24
import hashlib
3-
from functools import wraps
4-
5-
from typing import Callable, Optional, Any, List, Tuple, Union
6-
7-
85
import asyncio
9-
from dash.backend import get_request_adapter
106

117
from .dependencies import (
128
handle_callback_args,
@@ -39,10 +35,11 @@
3935
clean_property_name,
4036
)
4137

42-
from . import _validate
4338
from .background_callback.managers import BaseBackgroundCallbackManager
4439
from ._callback_context import context_value
4540
from ._no_update import NoUpdate
41+
from . import _validate
42+
from . import backends
4643

4744

4845
async def _async_invoke_callback(
@@ -176,7 +173,6 @@ def callback(
176173
Note that the endpoint will not appear in the list of registered
177174
callbacks in the Dash devtools.
178175
"""
179-
180176
background_spec = None
181177

182178
config_prevent_initial_callbacks = _kwargs.pop(
@@ -376,7 +372,8 @@ def _get_callback_manager(
376372
" and store results on redis.\n"
377373
)
378374

379-
old_job = get_request_adapter().get_args().getlist("oldJob")
375+
adapter = backends.request_adapter()
376+
old_job = adapter.args.getlist("oldJob") if hasattr(adapter.args, "getlist") else []
380377

381378
if old_job:
382379
for job in old_job:
@@ -390,21 +387,20 @@ def _setup_background_callback(
390387
):
391388
"""Set up the background callback and manage jobs."""
392389
callback_manager = _get_callback_manager(kwargs, background)
390+
if not callback_manager:
391+
return to_json({"error": "No background callback manager configured"})
393392

394393
progress_outputs = background.get("progress")
395394

396395
cache_ignore_triggered = background.get("cache_ignore_triggered", True)
397396

398397
cache_key = callback_manager.build_cache_key(
399398
func,
400-
# Inputs provided as dict is kwargs.
401399
func_args if func_args else func_kwargs,
402400
background.get("cache_args_to_ignore", []),
403401
None if cache_ignore_triggered else callback_ctx.get("triggered_inputs", []),
404402
)
405-
406403
job_fn = callback_manager.func_registry.get(background_key)
407-
408404
ctx_value = AttributeDict(**context_value.get())
409405
ctx_value.ignore_register_page = True
410406
ctx_value.pop("background_callback_manager")
@@ -436,7 +432,8 @@ def _setup_background_callback(
436432

437433
def _progress_background_callback(response, callback_manager, background):
438434
progress_outputs = background.get("progress")
439-
cache_key = get_request_adapter().get_args().get("cacheKey")
435+
adapter = backends.request_adapter()
436+
cache_key = adapter.args.get("cacheKey")
440437

441438
if progress_outputs:
442439
# Get the progress before the result as it would be erased after the results.
@@ -453,8 +450,9 @@ def _update_background_callback(
453450
"""Set up the background callback and manage jobs."""
454451
callback_manager = _get_callback_manager(kwargs, background)
455452

456-
cache_key = get_request_adapter().get_args().get("cacheKey")
457-
job_id = get_request_adapter().get_args().get("job")
453+
adapter = backends.request_adapter()
454+
cache_key = adapter.args.get("cacheKey") if adapter else None
455+
job_id = adapter.args.get("job") if adapter else None
458456

459457
_progress_background_callback(response, callback_manager, background)
460458

@@ -474,8 +472,9 @@ def _handle_rest_background_callback(
474472
multi,
475473
has_update=False,
476474
):
477-
cache_key = get_request_adapter().get_args().get("cacheKey")
478-
job_id = get_request_adapter().get_args().get("job")
475+
adapter = backends.request_adapter()
476+
cache_key = adapter.args.get("cacheKey") if adapter else None
477+
job_id = adapter.args.get("job") if adapter else None
479478
# Must get job_running after get_result since get_results terminates it.
480479
job_running = callback_manager.job_running(job_id)
481480
if not job_running and output_value is callback_manager.UNDEFINED:
@@ -688,10 +687,11 @@ def add_context(*args, **kwargs):
688687
)
689688

690689
response: dict = {"multi": True}
691-
jsonResponse = None
690+
jsonResponse: Optional[str] = None
692691
try:
693692
if background is not None:
694-
if not get_request_adapter().get_args().get("cacheKey"):
693+
adapter = backends.request_adapter()
694+
if not (adapter and adapter.args.get("cacheKey")):
695695
return _setup_background_callback(
696696
kwargs,
697697
background,
@@ -762,7 +762,8 @@ async def async_add_context(*args, **kwargs):
762762

763763
try:
764764
if background is not None:
765-
if not get_request_adapter().get_args().get("cacheKey"):
765+
adapter = backends.request_adapter()
766+
if not (adapter and adapter.args.get("cacheKey")):
766767
return _setup_background_callback(
767768
kwargs,
768769
background,

dash/_pages.py

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -318,18 +318,22 @@ def register_page(
318318
)
319319
page.update(
320320
supplied_title=title,
321-
title=title
322-
if title is not None
323-
else CONFIG.title
324-
if CONFIG.title != "Dash"
325-
else page["name"],
321+
title=(
322+
title
323+
if title is not None
324+
else CONFIG.title
325+
if CONFIG.title != "Dash"
326+
else page["name"]
327+
),
326328
)
327329
page.update(
328-
description=description
329-
if description
330-
else CONFIG.description
331-
if CONFIG.description
332-
else "",
330+
description=(
331+
description
332+
if description
333+
else CONFIG.description
334+
if CONFIG.description
335+
else ""
336+
),
333337
order=order,
334338
supplied_order=order,
335339
supplied_layout=layout,
@@ -390,15 +394,13 @@ def _path_to_page(path_id):
390394

391395

392396
def _page_meta_tags(app, request):
393-
request_path = request.get_path()
397+
request_path = request.path
394398
start_page, path_variables = _path_to_page(request_path.strip("/"))
395399

396400
image = start_page.get("image", "")
397401
if image:
398402
image = app.get_asset_url(image)
399-
assets_image_url = (
400-
"".join([request.get_root(), image.lstrip("/")]) if image else None
401-
)
403+
assets_image_url = "".join([request.root, image.lstrip("/")]) if image else None
402404
supplied_image_url = start_page.get("image_url")
403405
image_url = supplied_image_url if supplied_image_url else assets_image_url
404406

@@ -413,7 +415,7 @@ def _page_meta_tags(app, request):
413415
return [
414416
{"name": "description", "content": description},
415417
{"property": "twitter:card", "content": "summary_large_image"},
416-
{"property": "twitter:url", "content": request.get_url()},
418+
{"property": "twitter:url", "content": request.url},
417419
{"property": "twitter:title", "content": title},
418420
{"property": "twitter:description", "content": description},
419421
{"property": "twitter:image", "content": image_url or ""},

dash/_validate.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from ._grouping import grouping_len, map_grouping
99
from ._no_update import NoUpdate
1010
from .development.base_component import Component
11+
from . import backends
1112
from . import exceptions
1213
from ._utils import (
1314
patch_collections_abc,
@@ -585,3 +586,41 @@ def _valid(out):
585586
return
586587

587588
_valid(output)
589+
590+
591+
def check_async(use_async):
592+
if use_async is None:
593+
try:
594+
import asgiref # pylint: disable=unused-import, import-outside-toplevel # noqa
595+
596+
use_async = True
597+
except ImportError:
598+
pass
599+
elif use_async:
600+
try:
601+
import asgiref # pylint: disable=unused-import, import-outside-toplevel # noqa
602+
except ImportError as exc:
603+
raise Exception(
604+
"You are trying to use dash[async] without having installed the requirements please install via: `pip install dash[async]`"
605+
) from exc
606+
607+
608+
def check_backend(backend, inferred_backend):
609+
if backend is not None:
610+
if isinstance(backend, type):
611+
# get_backend returns the backend class for a string
612+
# So we compare the class names
613+
expected_backend_cls, _ = backends.get_backend(inferred_backend)
614+
if (
615+
backend.__module__ != expected_backend_cls.__module__
616+
or backend.__name__ != expected_backend_cls.__name__
617+
):
618+
raise ValueError(
619+
f"Conflict between provided backend '{backend.__name__}' and server type '{inferred_backend}'."
620+
)
621+
elif not isinstance(backend, str):
622+
raise ValueError("Invalid backend argument")
623+
elif backend.lower() != inferred_backend:
624+
raise ValueError(
625+
f"Conflict between provided backend '{backend}' and server type '{inferred_backend}'."
626+
)

dash/backend/__init__.py

Lines changed: 0 additions & 15 deletions
This file was deleted.

dash/backend/base_server.py

Lines changed: 0 additions & 58 deletions
This file was deleted.

dash/backend/registry.py

Lines changed: 0 additions & 29 deletions
This file was deleted.

0 commit comments

Comments
 (0)