18
18
import base64
19
19
import traceback
20
20
from urllib .parse import urlparse
21
- from typing import Any , Callable , Dict , Optional , Union , Sequence , Literal
21
+ from typing import Any , Callable , Dict , Optional , Union , Sequence , Literal , List
22
22
23
23
import flask
24
24
@@ -262,6 +262,12 @@ class Dash(ObsoleteChecker):
262
262
to sensitive files.
263
263
:type assets_ignore: string
264
264
265
+ :param assets_path_ignore: A list of regex, each regex as a string to pass to ``re.compile``, for
266
+ assets path to omit from immediate loading. The files in these ignored paths will still be
267
+ served if specifically requested. You cannot use this to prevent access
268
+ to sensitive files.
269
+ :type assets_path_ignore: list of strings
270
+
265
271
:param assets_external_path: an absolute URL from which to load assets.
266
272
Use with ``serve_locally=False``. assets_external_path is joined
267
273
with assets_url_path to determine the absolute url to the
@@ -408,6 +414,7 @@ def __init__( # pylint: disable=too-many-statements
408
414
use_pages : Optional [bool ] = None ,
409
415
assets_url_path : str = "assets" ,
410
416
assets_ignore : str = "" ,
417
+ assets_path_ignore : List [str ] = None ,
411
418
assets_external_path : Optional [str ] = None ,
412
419
eager_loading : bool = False ,
413
420
include_assets_files : bool = True ,
@@ -464,6 +471,7 @@ def __init__( # pylint: disable=too-many-statements
464
471
), # type: ignore
465
472
assets_url_path = assets_url_path ,
466
473
assets_ignore = assets_ignore ,
474
+ assets_path_ignore = assets_path_ignore ,
467
475
assets_external_path = get_combined_config (
468
476
"assets_external_path" , assets_external_path , ""
469
477
),
@@ -764,7 +772,6 @@ def layout(self, value: Any):
764
772
and not self .validation_layout
765
773
and not self .config .suppress_callback_exceptions
766
774
):
767
-
768
775
layout_value = self ._layout_value ()
769
776
_validate .validate_layout (value , layout_value )
770
777
self .validation_layout = layout_value
@@ -1505,11 +1512,18 @@ def _walk_assets_directory(self):
1505
1512
walk_dir = self .config .assets_folder
1506
1513
slash_splitter = re .compile (r"[\\/]+" )
1507
1514
ignore_str = self .config .assets_ignore
1515
+ ignore_path_list = self .config .assets_path_ignore
1508
1516
ignore_filter = re .compile (ignore_str ) if ignore_str else None
1517
+ ignore_path_filters = [
1518
+ re .compile (ignore_path )
1519
+ for ignore_path in (ignore_path_list or [])
1520
+ if ignore_path
1521
+ ]
1509
1522
1510
1523
for current , _ , files in sorted (os .walk (walk_dir )):
1511
1524
if current == walk_dir :
1512
1525
base = ""
1526
+ s = ""
1513
1527
else :
1514
1528
s = current .replace (walk_dir , "" ).lstrip ("\\ " ).lstrip ("/" )
1515
1529
splitted = slash_splitter .split (s )
@@ -1518,22 +1532,32 @@ def _walk_assets_directory(self):
1518
1532
else :
1519
1533
base = splitted [0 ]
1520
1534
1521
- if ignore_filter :
1522
- files_gen = (x for x in files if not ignore_filter .search (x ))
1535
+ # Check if any level of current path matches ignore path
1536
+ if s and any (
1537
+ ignore_path_filter .search (x )
1538
+ for ignore_path_filter in ignore_path_filters
1539
+ for x in s .split (os .path .sep )
1540
+ ):
1541
+ pass
1523
1542
else :
1524
- files_gen = files
1543
+ if ignore_filter :
1544
+ files_gen = (x for x in files if not ignore_filter .search (x ))
1545
+ else :
1546
+ files_gen = files
1525
1547
1526
- for f in sorted (files_gen ):
1527
- path = "/" .join ([base , f ]) if base else f
1548
+ for f in sorted (files_gen ):
1549
+ path = "/" .join ([base , f ]) if base else f
1528
1550
1529
- full = os .path .join (current , f )
1551
+ full = os .path .join (current , f )
1530
1552
1531
- if f .endswith ("js" ):
1532
- self .scripts .append_script (self ._add_assets_resource (path , full ))
1533
- elif f .endswith ("css" ):
1534
- self .css .append_css (self ._add_assets_resource (path , full )) # type: ignore[reportArgumentType]
1535
- elif f == "favicon.ico" :
1536
- self ._favicon = path
1553
+ if f .endswith ("js" ):
1554
+ self .scripts .append_script (
1555
+ self ._add_assets_resource (path , full )
1556
+ )
1557
+ elif f .endswith ("css" ):
1558
+ self .css .append_css (self ._add_assets_resource (path , full )) # type: ignore[reportArgumentType]
1559
+ elif f == "favicon.ico" :
1560
+ self ._favicon = path
1537
1561
1538
1562
@staticmethod
1539
1563
def _invalid_resources_handler (err ):
0 commit comments