diffract-core 0.2.1__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.
- diffract/__init__.py +52 -0
- diffract/configs/fast_speed_without_disk.ini +48 -0
- diffract/configs/hybrid.ini +74 -0
- diffract/configs/sqlite.ini +62 -0
- diffract/containers.py +405 -0
- diffract/core/__init__.py +23 -0
- diffract/core/cache/__init__.py +24 -0
- diffract/core/cache/containers.py +93 -0
- diffract/core/cache/interface.py +117 -0
- diffract/core/cache/redis_manager.py +464 -0
- diffract/core/cache/simple_manager.py +478 -0
- diffract/core/compute/__init__.py +46 -0
- diffract/core/compute/config.py +48 -0
- diffract/core/compute/containers.py +81 -0
- diffract/core/compute/decorator.py +125 -0
- diffract/core/compute/exceptions.py +31 -0
- diffract/core/compute/execution/__init__.py +14 -0
- diffract/core/compute/execution/_types.py +70 -0
- diffract/core/compute/execution/aggregation.py +74 -0
- diffract/core/compute/execution/aggregation_runner.py +362 -0
- diffract/core/compute/execution/enums.py +38 -0
- diffract/core/compute/execution/executor.py +125 -0
- diffract/core/compute/execution/parameter_runner.py +125 -0
- diffract/core/compute/execution/restrictions.py +61 -0
- diffract/core/compute/execution/strategy.py +118 -0
- diffract/core/compute/execution/utils.py +112 -0
- diffract/core/compute/extensions/__init__.py +0 -0
- diffract/core/compute/extensions/power_law.py +1051 -0
- diffract/core/compute/extensions/rmt.py +150 -0
- diffract/core/compute/extensions/utils.py +36 -0
- diffract/core/compute/field_signature.py +183 -0
- diffract/core/compute/kernels/__init__.py +48 -0
- diffract/core/compute/kernels/alignment.py +106 -0
- diffract/core/compute/kernels/heavy_tailed.py +394 -0
- diffract/core/compute/kernels/marchenko_pastur.py +99 -0
- diffract/core/compute/kernels/mat_decomposition.py +101 -0
- diffract/core/compute/kernels/mat_properties.py +53 -0
- diffract/core/compute/kernels/model_quality.py +27 -0
- diffract/core/compute/kernels/norms.py +88 -0
- diffract/core/compute/kernels/ranks.py +35 -0
- diffract/core/compute/kernels/tracy_widom.py +36 -0
- diffract/core/compute/metadata.py +67 -0
- diffract/core/compute/registry.py +485 -0
- diffract/core/constants.py +147 -0
- diffract/core/data/__init__.py +32 -0
- diffract/core/data/interface.py +304 -0
- diffract/core/data/metadata/__init__.py +15 -0
- diffract/core/data/metadata/containers.py +60 -0
- diffract/core/data/metadata/interface.py +208 -0
- diffract/core/data/metadata/sqlite_index.py +604 -0
- diffract/core/data/nn/__init__.py +43 -0
- diffract/core/data/nn/aggregates/__init__.py +35 -0
- diffract/core/data/nn/aggregates/metadata.py +96 -0
- diffract/core/data/nn/aggregates/proxy.py +57 -0
- diffract/core/data/nn/aggregates/repository.py +87 -0
- diffract/core/data/nn/aggregates/view.py +307 -0
- diffract/core/data/nn/containers.py +86 -0
- diffract/core/data/nn/extractors/__init__.py +49 -0
- diffract/core/data/nn/extractors/base.py +300 -0
- diffract/core/data/nn/extractors/factory.py +234 -0
- diffract/core/data/nn/extractors/flax.py +112 -0
- diffract/core/data/nn/extractors/handlers/__init__.py +39 -0
- diffract/core/data/nn/extractors/handlers/base.py +110 -0
- diffract/core/data/nn/extractors/handlers/flax_handlers.py +71 -0
- diffract/core/data/nn/extractors/handlers/numpy_handlers.py +63 -0
- diffract/core/data/nn/extractors/handlers/onnx_handlers.py +67 -0
- diffract/core/data/nn/extractors/handlers/tensorflow_handlers.py +82 -0
- diffract/core/data/nn/extractors/handlers/torch_handlers.py +124 -0
- diffract/core/data/nn/extractors/interface.py +56 -0
- diffract/core/data/nn/extractors/numpy.py +94 -0
- diffract/core/data/nn/extractors/onnx.py +108 -0
- diffract/core/data/nn/extractors/tensorflow.py +99 -0
- diffract/core/data/nn/extractors/torch.py +204 -0
- diffract/core/data/nn/params/__init__.py +27 -0
- diffract/core/data/nn/params/interface.py +402 -0
- diffract/core/data/nn/params/metadata.py +110 -0
- diffract/core/data/nn/params/proxy.py +93 -0
- diffract/core/data/nn/params/repository.py +45 -0
- diffract/core/data/nn/params/schema.py +82 -0
- diffract/core/data/nn/params/view.py +393 -0
- diffract/core/data/proxy.py +246 -0
- diffract/core/data/repository.py +227 -0
- diffract/core/data/utils.py +33 -0
- diffract/core/data/view.py +389 -0
- diffract/core/export/__init__.py +27 -0
- diffract/core/export/containers.py +47 -0
- diffract/core/export/exporters.py +191 -0
- diffract/core/export/formatters/__init__.py +23 -0
- diffract/core/export/formatters/base.py +68 -0
- diffract/core/export/formatters/dict_formatter.py +38 -0
- diffract/core/export/formatters/json_formatter.py +58 -0
- diffract/core/export/formatters/list_formatter.py +41 -0
- diffract/core/export/formatters/pandas_formatter.py +86 -0
- diffract/core/export/formatters/polars_formatter.py +86 -0
- diffract/core/export/formatters/registry.py +84 -0
- diffract/core/export/interface.py +105 -0
- diffract/core/parallel/__init__.py +21 -0
- diffract/core/parallel/containers.py +57 -0
- diffract/core/parallel/execution.py +91 -0
- diffract/core/parallel/runtime.py +91 -0
- diffract/core/storage/__init__.py +35 -0
- diffract/core/storage/base_manager.py +330 -0
- diffract/core/storage/containers.py +122 -0
- diffract/core/storage/hdf5_manager.py +856 -0
- diffract/core/storage/hybrid_manager.py +218 -0
- diffract/core/storage/interface.py +222 -0
- diffract/core/storage/metadata.py +89 -0
- diffract/core/storage/ram_manager.py +159 -0
- diffract/core/storage/sqlite_manager.py +1062 -0
- diffract/core/storage/zarr_manager.py +992 -0
- diffract/core/utils/__init__.py +45 -0
- diffract/core/utils/build.py +46 -0
- diffract/core/utils/exceptions.py +11 -0
- diffract/core/utils/hashing.py +90 -0
- diffract/core/utils/imports.py +292 -0
- diffract/core/utils/math.py +15 -0
- diffract/py.typed +0 -0
- diffract/session/__init__.py +24 -0
- diffract/session/errors.py +17 -0
- diffract/session/field_cache.py +216 -0
- diffract/session/namespaces/__init__.py +15 -0
- diffract/session/namespaces/compute/__init__.py +219 -0
- diffract/session/namespaces/models/__init__.py +282 -0
- diffract/session/namespaces/models/parameters/__init__.py +133 -0
- diffract/session/namespaces/models/parameters/meta_patcher.py +167 -0
- diffract/session/namespaces/results/__init__.py +378 -0
- diffract/session/namespaces/results/eraser.py +129 -0
- diffract/session/namespaces/results/injester.py +249 -0
- diffract/session/namespaces/utils/__init__.py +141 -0
- diffract/session/namespaces/utils/merger.py +295 -0
- diffract/session/namespaces/viz/__init__.py +91 -0
- diffract/session/namespaces/viz/_utils.py +14 -0
- diffract/session/namespaces/viz/box.py +207 -0
- diffract/session/namespaces/viz/grid.py +160 -0
- diffract/session/namespaces/viz/heatmap.py +164 -0
- diffract/session/namespaces/viz/scatter.py +202 -0
- diffract/session/namespaces/viz/sparkline.py +270 -0
- diffract/session/namespaces/viz/violin.py +212 -0
- diffract/session/session.py +260 -0
- diffract/session/utils.py +81 -0
- diffract/viz/__init__.py +42 -0
- diffract/viz/data/__init__.py +34 -0
- diffract/viz/data/detection.py +57 -0
- diffract/viz/data/extraction.py +117 -0
- diffract/viz/data/filtering.py +57 -0
- diffract/viz/data/ordering.py +129 -0
- diffract/viz/data/provider.py +99 -0
- diffract/viz/data/types.py +98 -0
- diffract/viz/plots/__init__.py +37 -0
- diffract/viz/plots/base/__init__.py +20 -0
- diffract/viz/plots/base/axis.py +219 -0
- diffract/viz/plots/base/coloraxis.py +133 -0
- diffract/viz/plots/base/configurator.py +18 -0
- diffract/viz/plots/base/jitter.py +368 -0
- diffract/viz/plots/base/line.py +197 -0
- diffract/viz/plots/base/marker.py +278 -0
- diffract/viz/plots/base/overlay.py +14 -0
- diffract/viz/plots/base/plot.py +110 -0
- diffract/viz/plots/base/update.py +50 -0
- diffract/viz/plots/boxplot.py +283 -0
- diffract/viz/plots/cluster.py +374 -0
- diffract/viz/plots/heatmap.py +168 -0
- diffract/viz/plots/scatter.py +233 -0
- diffract/viz/plots/sparkline.py +405 -0
- diffract/viz/plots/subplots/__init__.py +32 -0
- diffract/viz/plots/subplots/coloraxis.py +339 -0
- diffract/viz/plots/subplots/factory.py +713 -0
- diffract/viz/plots/subplots/grid.py +214 -0
- diffract/viz/plots/subplots/layout.py +370 -0
- diffract/viz/plots/subplots/spec.py +39 -0
- diffract/viz/plots/violin.py +298 -0
- diffract/viz/renderer.py +513 -0
- diffract/viz/styling/__init__.py +78 -0
- diffract/viz/styling/palettes/__init__.py +20 -0
- diffract/viz/styling/palettes/bundle.py +16 -0
- diffract/viz/styling/palettes/color.py +83 -0
- diffract/viz/styling/palettes/dashes.py +27 -0
- diffract/viz/styling/palettes/symbols.py +42 -0
- diffract/viz/styling/resolvers/__init__.py +11 -0
- diffract/viz/styling/resolvers/categorical.py +68 -0
- diffract/viz/styling/resolvers/color.py +77 -0
- diffract/viz/styling/resolvers/numeric.py +108 -0
- diffract/viz/styling/sources.py +27 -0
- diffract/viz/styling/theme/__init__.py +29 -0
- diffract/viz/styling/theme/applier.py +114 -0
- diffract/viz/styling/theme/components.py +66 -0
- diffract/viz/styling/theme/presets.py +58 -0
- diffract/viz/styling/theme/theme.py +36 -0
- diffract_core-0.2.1.dist-info/METADATA +530 -0
- diffract_core-0.2.1.dist-info/RECORD +193 -0
- diffract_core-0.2.1.dist-info/WHEEL +4 -0
- diffract_core-0.2.1.dist-info/licenses/LICENSE +201 -0
- diffract_core-0.2.1.dist-info/licenses/NOTICE +2 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import math
|
|
2
|
+
from sys import float_info
|
|
3
|
+
from typing import Any, cast
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
from numpy.typing import NDArray
|
|
7
|
+
|
|
8
|
+
from diffract.core.compute.decorator import kernel
|
|
9
|
+
from diffract.core.compute.execution.enums import KernelApplyLevel
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@kernel(name="pl_alpha_norm", require_fields=("esd", "pl_alpha"))
|
|
13
|
+
@kernel(name="tpl_alpha_norm", require_fields=("esd", "tpl_alpha"))
|
|
14
|
+
def alpha_norm(esd: NDArray[np.floating[Any]], alpha: float) -> float:
|
|
15
|
+
"""Compute alpha norm: sum(esd^alpha)."""
|
|
16
|
+
return cast("float", np.sum(esd**alpha).item())
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@kernel(
|
|
20
|
+
name="model_pl_alpha_norm",
|
|
21
|
+
require_fields=("pl_alpha_norm",),
|
|
22
|
+
apply_level=KernelApplyLevel.IN_MODEL,
|
|
23
|
+
)
|
|
24
|
+
@kernel(
|
|
25
|
+
name="model_tpl_alpha_norm",
|
|
26
|
+
require_fields=("tpl_alpha_norm",),
|
|
27
|
+
apply_level=KernelApplyLevel.IN_MODEL,
|
|
28
|
+
)
|
|
29
|
+
def model_alpha_norm(alpha_norm: tuple[float, ...]) -> float:
|
|
30
|
+
"""Compute mean log10 alpha norm across model parameters."""
|
|
31
|
+
alpha_norm_arr: NDArray[np.floating[Any]] = np.array(alpha_norm)
|
|
32
|
+
log_alpha_norm = np.where(
|
|
33
|
+
alpha_norm_arr == 0, float_info.min_10_exp, np.log10(alpha_norm_arr)
|
|
34
|
+
)
|
|
35
|
+
return cast("float", np.mean(log_alpha_norm).item())
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@kernel
|
|
39
|
+
def frob_norm(weights_svals: NDArray[np.floating[Any]]) -> float:
|
|
40
|
+
"""Compute Frobenius norm from singular values."""
|
|
41
|
+
return math.sqrt(cast("float", np.sum(weights_svals**2).item()))
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
@kernel
|
|
45
|
+
def l1_norm(weights_svals: NDArray[np.floating[Any]]) -> float:
|
|
46
|
+
"""Compute L1 norm (sum of singular values)."""
|
|
47
|
+
return cast("float", weights_svals.sum().item())
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@kernel
|
|
51
|
+
def l2_norm(max_weights_sval: float) -> float:
|
|
52
|
+
"""Compute L2 (spectral) norm (maximum singular value)."""
|
|
53
|
+
return max_weights_sval
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@kernel(apply_level=KernelApplyLevel.IN_MODEL)
|
|
57
|
+
def log_norm(frob_norm: tuple[float, ...]) -> float:
|
|
58
|
+
"""Compute mean squared log Frobenius norm across model parameters."""
|
|
59
|
+
frob_norm_arr: NDArray[np.floating[Any]] = np.array(frob_norm)
|
|
60
|
+
return cast("float", np.mean(np.log(frob_norm_arr) ** 2).item())
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@kernel(apply_level=KernelApplyLevel.IN_MODEL)
|
|
64
|
+
def log_spectral_norm(l2_norm: tuple[float, ...]) -> float:
|
|
65
|
+
"""Compute mean squared log spectral norm across model parameters."""
|
|
66
|
+
l2_norm_arr: NDArray[np.floating[Any]] = np.array(l2_norm)
|
|
67
|
+
return cast("float", np.mean(np.log(l2_norm_arr) ** 2).item())
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@kernel(apply_level=KernelApplyLevel.IN_MODEL)
|
|
71
|
+
def param_norm(frob_norm: tuple[float, ...]) -> float:
|
|
72
|
+
"""Compute sum of squared Frobenius norms across model parameters."""
|
|
73
|
+
frob_norm_arr: NDArray[np.floating[Any]] = np.array(frob_norm)
|
|
74
|
+
return cast("float", np.sum(frob_norm_arr**2).item())
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
@kernel(apply_level=KernelApplyLevel.IN_MODEL)
|
|
78
|
+
def prod_frob_norm(frob_norm: tuple[float, ...]) -> float:
|
|
79
|
+
"""Compute product of Frobenius norms across model parameters."""
|
|
80
|
+
frob_norm_arr: NDArray[np.floating[Any]] = np.array(frob_norm)
|
|
81
|
+
return cast("float", np.prod(frob_norm_arr).item())
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
@kernel(apply_level=KernelApplyLevel.IN_MODEL)
|
|
85
|
+
def prod_spectral_norm(l2_norm: tuple[float, ...]) -> float:
|
|
86
|
+
"""Compute product of spectral norms across model parameters."""
|
|
87
|
+
l2_norm_arr: NDArray[np.floating[Any]] = np.array(l2_norm)
|
|
88
|
+
return cast("float", np.prod(l2_norm_arr).item())
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import math
|
|
2
|
+
from typing import Any, cast
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
from numpy.typing import NDArray
|
|
6
|
+
|
|
7
|
+
from diffract.core.compute.decorator import kernel
|
|
8
|
+
|
|
9
|
+
EPS = 1e-16
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@kernel
|
|
13
|
+
def effective_rank(weights_svals: NDArray[np.floating[Any]]) -> float:
|
|
14
|
+
"""Compute effective rank from singular values using entropy."""
|
|
15
|
+
probabilities = weights_svals / cast("float", weights_svals.sum().item() + EPS)
|
|
16
|
+
entropy = cast("float", -np.sum(probabilities * np.log(probabilities + EPS)).item())
|
|
17
|
+
return math.exp(entropy)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@kernel
|
|
21
|
+
def hard_rank(esd: NDArray[np.floating[Any]], *, threshold: float = 1e-5) -> int:
|
|
22
|
+
"""Count eigenvalues above threshold."""
|
|
23
|
+
return cast("int", np.sum((esd > threshold).astype(int)).item())
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@kernel
|
|
27
|
+
def mp_soft_rank(mp_esd_max: float, esd_max: float) -> float:
|
|
28
|
+
"""Compute soft rank from MP bulk maximum relative to ESD maximum."""
|
|
29
|
+
return mp_esd_max / (esd_max + EPS)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@kernel
|
|
33
|
+
def stable_rank(frob_norm: float, l2_norm: float) -> float:
|
|
34
|
+
"""Compute stable rank (Frobenius norm / spectral norm)^2."""
|
|
35
|
+
return (frob_norm / (l2_norm + EPS)) ** 2
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import math
|
|
2
|
+
from typing import Any, cast
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
from numpy.typing import NDArray
|
|
6
|
+
|
|
7
|
+
from diffract.core.compute.decorator import kernel
|
|
8
|
+
from diffract.core.compute.extensions.rmt import tracy_widom_ppf
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@kernel
|
|
12
|
+
def tw_esd_bound(
|
|
13
|
+
greater_dim: int,
|
|
14
|
+
lower_dim: int,
|
|
15
|
+
mp_bulk_std: float,
|
|
16
|
+
*,
|
|
17
|
+
p_value_threshold: float = 0.005,
|
|
18
|
+
) -> float:
|
|
19
|
+
"""Compute Tracy-Widom bound for ESD spike detection."""
|
|
20
|
+
g_dim, l_dim = greater_dim, lower_dim
|
|
21
|
+
|
|
22
|
+
loc = math.sqrt(g_dim - 1) + math.sqrt(l_dim)
|
|
23
|
+
inv_loc = 1 / math.sqrt(g_dim - 1) + 1 / math.sqrt(l_dim)
|
|
24
|
+
scale = (mp_bulk_std**2) / g_dim
|
|
25
|
+
|
|
26
|
+
mu: float = scale * (loc**2)
|
|
27
|
+
sigma: float = scale * (loc) * (inv_loc ** (1 / 3))
|
|
28
|
+
pure_twd_bound = tracy_widom_ppf(1 - p_value_threshold)
|
|
29
|
+
|
|
30
|
+
return pure_twd_bound * sigma + mu
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@kernel
|
|
34
|
+
def tw_num_spikes(esd: NDArray[np.floating[Any]], tw_esd_bound: float) -> int:
|
|
35
|
+
"""Count number of spikes above Tracy-Widom bound."""
|
|
36
|
+
return cast("int", np.sum((esd > tw_esd_bound).astype(int)).item())
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""Kernel metadata and information structures."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from typing import TYPE_CHECKING, Any
|
|
7
|
+
|
|
8
|
+
from .config import KernelConfig
|
|
9
|
+
from .execution import KernelApplyLevel, KernelExecutionProtocol, KernelRestrictions
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from collections.abc import Callable
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass(frozen=True)
|
|
16
|
+
class KernelInfo:
|
|
17
|
+
"""Optional human-readable kernel documentation fields.
|
|
18
|
+
|
|
19
|
+
Contains optional metadata for kernel documentation and introspection.
|
|
20
|
+
Used to provide additional context about kernel purpose and usage.
|
|
21
|
+
|
|
22
|
+
Attributes:
|
|
23
|
+
summary: Brief description of kernel functionality.
|
|
24
|
+
notes: Additional implementation notes or usage guidelines.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
summary: str | None = None
|
|
28
|
+
notes: str | None = None
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@dataclass
|
|
32
|
+
class KernelMetadata:
|
|
33
|
+
"""Complete metadata container for registered kernels.
|
|
34
|
+
|
|
35
|
+
Stores all information required for kernel registration, execution,
|
|
36
|
+
and dependency resolution within the kernel registry system.
|
|
37
|
+
|
|
38
|
+
Attributes:
|
|
39
|
+
name: Unique kernel identifier.
|
|
40
|
+
require_fields: Tuple of field names required as input.
|
|
41
|
+
produce_fields: Tuple of field names produced as output.
|
|
42
|
+
implementation: Callable implementing the kernel logic.
|
|
43
|
+
apply_level: Level at which kernel is applied (parameter/model/cross-model).
|
|
44
|
+
execution_protocol: Execution strategy (sequential/parallel).
|
|
45
|
+
restrictions: Optional execution restrictions.
|
|
46
|
+
config: Configuration parameters with defaults.
|
|
47
|
+
info: Optional documentation metadata.
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
name: str
|
|
51
|
+
require_fields: tuple[str, ...]
|
|
52
|
+
produce_fields: tuple[str, ...]
|
|
53
|
+
implementation: Callable[..., Any]
|
|
54
|
+
apply_level: KernelApplyLevel
|
|
55
|
+
execution_protocol: KernelExecutionProtocol | None
|
|
56
|
+
restrictions: KernelRestrictions | None
|
|
57
|
+
config: KernelConfig
|
|
58
|
+
info: KernelInfo
|
|
59
|
+
|
|
60
|
+
def __repr__(self) -> str: # pragma: no cover - debug helper
|
|
61
|
+
"""Return string representation for debugging and logging."""
|
|
62
|
+
conf = ", ".join(f"{k}={v}" for k, v in self.config.as_dict().items())
|
|
63
|
+
restrictions = f",{self.restrictions}" if self.restrictions else ""
|
|
64
|
+
return (
|
|
65
|
+
f"{self.name} ({', '.join(self.require_fields)}; {conf}): "
|
|
66
|
+
f"{self.apply_level}{restrictions}"
|
|
67
|
+
)
|