Reformat lines that became too long. And enforce 119 line length.

This commit is contained in:
Emil Stenström 2024-02-11 22:50:15 +01:00 committed by Emil Stenström
parent ef6a082238
commit 48fe8171b4
25 changed files with 314 additions and 733 deletions

View file

@ -11,4 +11,4 @@ repos:
rev: 7.0.0
hooks:
- id: flake8
additional_dependencies: [flake8-pyproject]

View file

@ -4,10 +4,7 @@ from django.template import Context, Template
from django.test import override_settings
from django_components import component
from django_components.middleware import (
CSS_DEPENDENCY_PLACEHOLDER,
JS_DEPENDENCY_PLACEHOLDER,
)
from django_components.middleware import CSS_DEPENDENCY_PLACEHOLDER, JS_DEPENDENCY_PLACEHOLDER
from tests.django_test_setup import * # NOQA
from tests.testutils import Django30CompatibleSimpleTestCase as SimpleTestCase
from tests.testutils import create_and_process_template_response
@ -75,9 +72,7 @@ class RenderBenchmarks(SimpleTestCase):
component.registry.clear()
component.registry.register("test_component", SlottedComponent)
component.registry.register("inner_component", SimpleComponent)
component.registry.register(
"breadcrumb_component", BreadcrumbComponent
)
component.registry.register("breadcrumb_component", BreadcrumbComponent)
@staticmethod
def timed_loop(func, iterations=1000):
@ -91,22 +86,28 @@ class RenderBenchmarks(SimpleTestCase):
def test_render_time_for_small_component(self):
template = Template(
"{% load component_tags %}{% component_block 'test_component' %}"
"{% slot \"header\" %}{% component_block 'inner_component' variable='foo' %}{% endslot %}{% endcomponent_block %}"
"{% endcomponent_block %}",
name="root",
"""
{% load component_tags %}
{% component_block 'test_component' %}
{% slot "header" %}
{% component_block 'inner_component' variable='foo' %}{% endcomponent_block %}
{% endslot %}
{% endcomponent_block %}
"""
)
print(
f"{self.timed_loop(lambda: template.render(Context({})))} ms per iteration"
)
print(f"{self.timed_loop(lambda: template.render(Context({})))} ms per iteration")
def test_middleware_time_with_dependency_for_small_page(self):
template = Template(
"{% load component_tags %}{% component_dependencies %}"
"{% component_block 'test_component' %}{% slot \"header\" %}"
"{% component_block 'inner_component' variable='foo' %}{% endslot %}{% endcomponent_block %}{% endcomponent_block %}",
name="root",
"""
{% load component_tags %}{% component_dependencies %}
{% component_block 'test_component' %}
{% slot "header" %}
{% component_block 'inner_component' variable='foo' %}{% endcomponent_block %}
{% endslot %}
{% endcomponent_block %}
"""
)
# Sanity tests
response_content = create_and_process_template_response(template)
@ -116,15 +117,9 @@ class RenderBenchmarks(SimpleTestCase):
self.assertIn("script.js", response_content)
without_middleware = self.timed_loop(
lambda: create_and_process_template_response(
template, use_middleware=False
)
)
with_middleware = self.timed_loop(
lambda: create_and_process_template_response(
template, use_middleware=True
)
lambda: create_and_process_template_response(template, use_middleware=False)
)
with_middleware = self.timed_loop(lambda: create_and_process_template_response(template, use_middleware=True))
print("Small page middleware test")
self.report_results(with_middleware, without_middleware)
@ -140,14 +135,10 @@ class RenderBenchmarks(SimpleTestCase):
self.assertIn("test.js", response_content)
without_middleware = self.timed_loop(
lambda: create_and_process_template_response(
template, {}, use_middleware=False
)
lambda: create_and_process_template_response(template, {}, use_middleware=False)
)
with_middleware = self.timed_loop(
lambda: create_and_process_template_response(
template, {}, use_middleware=True
)
lambda: create_and_process_template_response(template, {}, use_middleware=True)
)
print("Large page middleware test")
@ -156,15 +147,9 @@ class RenderBenchmarks(SimpleTestCase):
@staticmethod
def report_results(with_middleware, without_middleware):
print(f"Middleware active\t\t{with_middleware:.3f} ms per iteration")
print(
f"Middleware inactive\t{without_middleware:.3f} ms per iteration"
)
print(f"Middleware inactive\t{without_middleware:.3f} ms per iteration")
time_difference = with_middleware - without_middleware
if without_middleware > with_middleware:
print(
f"Decrease of {-100 * time_difference / with_middleware:.2f}%"
)
print(f"Decrease of {-100 * time_difference / with_middleware:.2f}%")
else:
print(
f"Increase of {100 * time_difference / without_middleware:.2f}%"
)
print(f"Increase of {100 * time_difference / without_middleware:.2f}%")

View file

@ -26,9 +26,7 @@ class AppSettings:
@property
def CONTEXT_BEHAVIOR(self):
raw_value = self.settings.setdefault(
"context_behavior", ContextBehavior.GLOBAL.value
)
raw_value = self.settings.setdefault("context_behavior", ContextBehavior.GLOBAL.value)
return self._validate_context_behavior(raw_value)
def _validate_context_behavior(self, raw_value):
@ -36,9 +34,7 @@ class AppSettings:
return ContextBehavior(raw_value)
except ValueError:
valid_values = [behavior.value for behavior in ContextBehavior]
raise ValueError(
f"Invalid context behavior: {raw_value}. Valid options are {valid_values}"
)
raise ValueError(f"Invalid context behavior: {raw_value}. Valid options are {valid_values}")
app_settings = AppSettings()

View file

@ -80,9 +80,7 @@ class Component(View, metaclass=SimplifiedInterfaceMediaDefiningClass):
self,
registered_name: Optional[str] = None,
outer_context: Optional[Context] = None,
fill_content: Union[
DefaultFillContent, Iterable[NamedFillContent]
] = (),
fill_content: Union[DefaultFillContent, Iterable[NamedFillContent]] = (),
):
self.registered_name: Optional[str] = registered_name
self.outer_context: Context = outer_context or Context()
@ -152,14 +150,10 @@ class Component(View, metaclass=SimplifiedInterfaceMediaDefiningClass):
if slots_data:
self._fill_slots(slots_data, escape_slots_content)
updated_filled_slots_context: FilledSlotsContext = (
self._process_template_and_update_filled_slot_context(
context, template
)
updated_filled_slots_context: FilledSlotsContext = self._process_template_and_update_filled_slot_context(
context, template
)
with context.update(
{FILLED_SLOTS_CONTENT_CONTEXT_KEY: updated_filled_slots_context}
):
with context.update({FILLED_SLOTS_CONTENT_CONTEXT_KEY: updated_filled_slots_context}):
return template.render(context)
def render_to_response(
@ -201,19 +195,14 @@ class Component(View, metaclass=SimplifiedInterfaceMediaDefiningClass):
named_fills_content = {}
else:
default_fill_content = None
named_fills_content = {
name: (nodelist, alias)
for name, nodelist, alias in self.fill_content
}
named_fills_content = {name: (nodelist, alias) for name, nodelist, alias in self.fill_content}
# If value is `None`, then slot is unfilled.
slot_name2fill_content: Dict[SlotName, Optional[FillContent]] = {}
default_slot_encountered: bool = False
required_slot_names: Set[str] = set()
for node in template.nodelist.get_nodes_by_type(
(SlotNode, IfSlotFilledConditionBranchNode) # type: ignore
):
for node in template.nodelist.get_nodes_by_type((SlotNode, IfSlotFilledConditionBranchNode)): # type: ignore
if isinstance(node, SlotNode):
# Give slot node knowledge of its parent template.
node.template = template
@ -225,9 +214,7 @@ class Component(View, metaclass=SimplifiedInterfaceMediaDefiningClass):
f"To fix, check template '{template.name}' "
f"of component '{self.registered_name}'."
)
content_data: Optional[FillContent] = (
None # `None` -> unfilled
)
content_data: Optional[FillContent] = None # `None` -> unfilled
if node.is_required:
required_slot_names.add(node.name)
if node.is_default:
@ -245,9 +232,7 @@ class Component(View, metaclass=SimplifiedInterfaceMediaDefiningClass):
elif isinstance(node, IfSlotFilledConditionBranchNode):
node.template = template
else:
raise RuntimeError(
f"Node of {type(node).__name__} does not require linking."
)
raise RuntimeError(f"Node of {type(node).__name__} does not require linking.")
# Check: Only component templates that include a 'default' slot
# can be invoked with implicit filling.
@ -258,12 +243,8 @@ class Component(View, metaclass=SimplifiedInterfaceMediaDefiningClass):
f"even though none of its slots is marked as 'default'."
)
unfilled_slots: Set[str] = set(
k for k, v in slot_name2fill_content.items() if v is None
)
unmatched_fills: Set[str] = (
named_fills_content.keys() - slot_name2fill_content.keys()
)
unfilled_slots: Set[str] = set(k for k, v in slot_name2fill_content.items() if v is None)
unmatched_fills: Set[str] = named_fills_content.keys() - slot_name2fill_content.keys()
# Check that 'required' slots are filled.
for slot_name in unfilled_slots:
@ -286,9 +267,7 @@ class Component(View, metaclass=SimplifiedInterfaceMediaDefiningClass):
# Higher values make matching stricter. This is probably preferable, as it
# reduces false positives.
for fill_name in unmatched_fills:
fuzzy_slot_name_matches = difflib.get_close_matches(
fill_name, unfilled_slots, n=1, cutoff=0.7
)
fuzzy_slot_name_matches = difflib.get_close_matches(fill_name, unfilled_slots, n=1, cutoff=0.7)
msg = (
f"Component '{self.registered_name}' passed fill "
f"that refers to undefined slot: '{fill_name}'."
@ -305,9 +284,7 @@ class Component(View, metaclass=SimplifiedInterfaceMediaDefiningClass):
if content_data # Slots whose content is None (i.e. unfilled) are dropped.
}
try:
prev_context: FilledSlotsContext = context[
FILLED_SLOTS_CONTENT_CONTEXT_KEY
]
prev_context: FilledSlotsContext = context[FILLED_SLOTS_CONTENT_CONTEXT_KEY]
return prev_context.new_child(filled_slots_map)
except KeyError:
return ChainMap(filled_slots_map)

View file

@ -12,13 +12,8 @@ class ComponentRegistry(object):
def register(self, name=None, component=None):
existing_component = self._registry.get(name)
if (
existing_component
and existing_component.class_hash != component.class_hash
):
raise AlreadyRegistered(
'The component "%s" has already been registered' % name
)
if existing_component and existing_component.class_hash != component.class_hash:
raise AlreadyRegistered('The component "%s" has already been registered' % name)
self._registry[name] = component
def unregister(self, name):

View file

@ -9,9 +9,7 @@ class Command(BaseCommand):
help = "Creates a new component"
def add_arguments(self, parser):
parser.add_argument(
"name", type=str, help="The name of the component to create"
)
parser.add_argument("name", type=str, help="The name of the component to create")
parser.add_argument(
"--path",
type=str,
@ -71,9 +69,7 @@ class Command(BaseCommand):
elif base_dir:
component_path = os.path.join(base_dir, "components", name)
else:
raise CommandError(
"You must specify a path or set BASE_DIR in your django settings"
)
raise CommandError("You must specify a path or set BASE_DIR in your django settings")
if os.path.exists(component_path):
if force:
@ -84,11 +80,7 @@ class Command(BaseCommand):
)
)
else:
self.stdout.write(
self.style.WARNING(
f'The component "{name}" already exists. Overwriting...'
)
)
self.stdout.write(self.style.WARNING(f'The component "{name}" already exists. Overwriting...'))
else:
raise CommandError(
f'The component "{name}" already exists at {component_path}. Use --force to overwrite.'
@ -107,9 +99,7 @@ class Command(BaseCommand):
)
f.write(script_content.strip())
with open(
os.path.join(component_path, css_filename), "w"
) as f:
with open(os.path.join(component_path, css_filename), "w") as f:
style_content = dedent(
f"""
.component-{name} {{
@ -119,9 +109,7 @@ class Command(BaseCommand):
)
f.write(style_content.strip())
with open(
os.path.join(component_path, template_filename), "w"
) as f:
with open(os.path.join(component_path, template_filename), "w") as f:
template_content = dedent(
f"""
<div class="component-{name}">
@ -133,9 +121,7 @@ class Command(BaseCommand):
)
f.write(template_content.strip())
with open(
os.path.join(component_path, f"{name}.py"), "w"
) as f:
with open(os.path.join(component_path, f"{name}.py"), "w") as f:
py_content = dedent(
f"""
from django_components import component
@ -157,16 +143,8 @@ class Command(BaseCommand):
f.write(py_content.strip())
if verbose:
self.stdout.write(
self.style.SUCCESS(
f"Successfully created {name} component at {component_path}"
)
)
self.stdout.write(self.style.SUCCESS(f"Successfully created {name} component at {component_path}"))
else:
self.stdout.write(
self.style.SUCCESS(
f"Successfully created {name} component"
)
)
self.stdout.write(self.style.SUCCESS(f"Successfully created {name} component"))
else:
raise CommandError("You must specify a component name")

View file

@ -11,9 +11,7 @@ CSS_DEPENDENCY_PLACEHOLDER = '<link name="CSS_PLACEHOLDER">'
JS_DEPENDENCY_PLACEHOLDER = '<script name="JS_PLACEHOLDER"></script>'
SCRIPT_TAG_REGEX = re.compile("<script")
COMPONENT_COMMENT_REGEX = re.compile(
rb"<!-- _RENDERED (?P<name>[\w\-/]+?) -->"
)
COMPONENT_COMMENT_REGEX = re.compile(rb"<!-- _RENDERED (?P<name>[\w\-/]+?) -->")
PLACEHOLDER_REGEX = re.compile(
rb"<!-- _RENDERED (?P<name>[\w\-/]+?) -->"
rb'|<link name="CSS_PLACEHOLDER">'
@ -32,9 +30,7 @@ class ComponentDependencyMiddleware:
def __call__(self, request):
response = self.get_response(request)
if (
getattr(settings, "COMPONENTS", {}).get(
"RENDER_DEPENDENCIES", False
)
getattr(settings, "COMPONENTS", {}).get("RENDER_DEPENDENCIES", False)
and not isinstance(response, StreamingHttpResponse)
and response.get("Content-Type", "").startswith("text/html")
):
@ -43,23 +39,12 @@ class ComponentDependencyMiddleware:
def process_response_content(content):
component_names_seen = {
match.group("name")
for match in COMPONENT_COMMENT_REGEX.finditer(content)
}
all_components = [
registry.get(name.decode("utf-8"))("") for name in component_names_seen
]
component_names_seen = {match.group("name") for match in COMPONENT_COMMENT_REGEX.finditer(content)}
all_components = [registry.get(name.decode("utf-8"))("") for name in component_names_seen]
all_media = join_media(all_components)
js_dependencies = b"".join(
media.encode("utf-8") for media in all_media.render_js()
)
css_dependencies = b"".join(
media.encode("utf-8") for media in all_media.render_css()
)
return PLACEHOLDER_REGEX.sub(
DependencyReplacer(css_dependencies, js_dependencies), content
)
js_dependencies = b"".join(media.encode("utf-8") for media in all_media.render_js())
css_dependencies = b"".join(media.encode("utf-8") for media in all_media.render_css())
return PLACEHOLDER_REGEX.sub(DependencyReplacer(css_dependencies, js_dependencies), content)
def add_module_attribute_to_scripts(scripts):

View file

@ -12,9 +12,7 @@ class SaferStaticFilesConfig(StaticFilesConfig):
by the static file server.
"""
default = (
True # Ensure that _this_ app is registered, as opposed to parent cls.
)
default = True # Ensure that _this_ app is registered, as opposed to parent cls.
ignore_patterns = StaticFilesConfig.ignore_patterns + [
"*.py",
"*.html",

View file

@ -9,13 +9,7 @@ else:
import django.template
from django.conf import settings
from django.template import Context, Template
from django.template.base import (
FilterExpression,
Node,
NodeList,
TextNode,
TokenType,
)
from django.template.base import FilterExpression, Node, NodeList, TextNode, TokenType
from django.template.defaulttags import CommentNode
from django.template.exceptions import TemplateSyntaxError
from django.template.library import parse_bits
@ -24,10 +18,7 @@ from django.utils.safestring import mark_safe
from django_components.app_settings import app_settings
from django_components.component_registry import ComponentRegistry
from django_components.component_registry import registry as component_registry
from django_components.middleware import (
CSS_DEPENDENCY_PLACEHOLDER,
JS_DEPENDENCY_PLACEHOLDER,
)
from django_components.middleware import CSS_DEPENDENCY_PLACEHOLDER, JS_DEPENDENCY_PLACEHOLDER
if TYPE_CHECKING:
from django_components.component import Component
@ -88,16 +79,8 @@ def component_dependencies_tag(preload=""):
if is_dependency_middleware_active():
preloaded_dependencies = []
for component in get_components_from_preload_str(preload):
preloaded_dependencies.append(
RENDERED_COMMENT_TEMPLATE.format(
name=component.registered_name
)
)
return mark_safe(
"\n".join(preloaded_dependencies)
+ CSS_DEPENDENCY_PLACEHOLDER
+ JS_DEPENDENCY_PLACEHOLDER
)
preloaded_dependencies.append(RENDERED_COMMENT_TEMPLATE.format(name=component.registered_name))
return mark_safe("\n".join(preloaded_dependencies) + CSS_DEPENDENCY_PLACEHOLDER + JS_DEPENDENCY_PLACEHOLDER)
else:
rendered_dependencies = []
for component in get_components_from_registry(component_registry):
@ -113,14 +96,8 @@ def component_css_dependencies_tag(preload=""):
if is_dependency_middleware_active():
preloaded_dependencies = []
for component in get_components_from_preload_str(preload):
preloaded_dependencies.append(
RENDERED_COMMENT_TEMPLATE.format(
name=component.registered_name
)
)
return mark_safe(
"\n".join(preloaded_dependencies) + CSS_DEPENDENCY_PLACEHOLDER
)
preloaded_dependencies.append(RENDERED_COMMENT_TEMPLATE.format(name=component.registered_name))
return mark_safe("\n".join(preloaded_dependencies) + CSS_DEPENDENCY_PLACEHOLDER)
else:
rendered_dependencies = []
for component in get_components_from_registry(component_registry):
@ -136,14 +113,8 @@ def component_js_dependencies_tag(preload=""):
if is_dependency_middleware_active():
preloaded_dependencies = []
for component in get_components_from_preload_str(preload):
preloaded_dependencies.append(
RENDERED_COMMENT_TEMPLATE.format(
name=component.registered_name
)
)
return mark_safe(
"\n".join(preloaded_dependencies) + JS_DEPENDENCY_PLACEHOLDER
)
preloaded_dependencies.append(RENDERED_COMMENT_TEMPLATE.format(name=component.registered_name))
return mark_safe("\n".join(preloaded_dependencies) + JS_DEPENDENCY_PLACEHOLDER)
else:
rendered_dependencies = []
for component in get_components_from_registry(component_registry):
@ -151,6 +122,7 @@ def component_js_dependencies_tag(preload=""):
return mark_safe("\n".join(rendered_dependencies))
class UserSlotVar:
"""
Extensible mechanism for offering 'fill' blocks in template access to properties
@ -216,24 +188,17 @@ class SlotNode(Node, TemplateAwareNodeMixin):
def render(self, context):
try:
filled_slots_map: FilledSlotsContext = context[
FILLED_SLOTS_CONTENT_CONTEXT_KEY
]
filled_slots_map: FilledSlotsContext = context[FILLED_SLOTS_CONTENT_CONTEXT_KEY]
except KeyError:
raise TemplateSyntaxError(
f"Attempted to render SlotNode '{self.name}' outside a parent component."
)
raise TemplateSyntaxError(f"Attempted to render SlotNode '{self.name}' outside a parent component.")
extra_context = {}
try:
slot_fill_content: Optional[FillContent] = filled_slots_map[
(self.name, self.template)
]
slot_fill_content: Optional[FillContent] = filled_slots_map[(self.name, self.template)]
except KeyError:
if self.is_required:
raise TemplateSyntaxError(
f"Slot '{self.name}' is marked as 'required' (i.e. non-optional), "
f"yet no fill is provided. "
f"Slot '{self.name}' is marked as 'required' (i.e. non-optional), " f"yet no fill is provided. "
)
nodelist = self.nodelist
else:
@ -257,9 +222,7 @@ def do_slot(parser, token):
if 1 <= len(args) <= 3:
slot_name, *options = args
if not is_wrapped_in_quotes(slot_name):
raise TemplateSyntaxError(
f"'{bits[0]}' name must be a string 'literal'."
)
raise TemplateSyntaxError(f"'{bits[0]}' name must be a string 'literal'.")
slot_name = strip_quotes(slot_name)
modifiers_count = len(options)
if SLOT_REQUIRED_OPTION_KEYWORD in options:
@ -273,9 +236,7 @@ def do_slot(parser, token):
SLOT_REQUIRED_OPTION_KEYWORD,
SLOT_DEFAULT_OPTION_KEYWORD,
]
raise TemplateSyntaxError(
f"Invalid options passed to 'slot' tag. Valid choices: {keywords}."
)
raise TemplateSyntaxError(f"Invalid options passed to 'slot' tag. Valid choices: {keywords}.")
else:
raise TemplateSyntaxError(
"'slot' tag does not match pattern "
@ -354,14 +315,10 @@ def do_fill(parser, token):
elif len(args) == 3:
tgt_slot_name, as_keyword, alias = args
if as_keyword.lower() != "as":
raise TemplateSyntaxError(
f"{tag} tag args do not conform to pattern '<target slot> as <alias>'"
)
raise TemplateSyntaxError(f"{tag} tag args do not conform to pattern '<target slot> as <alias>'")
alias_fexp = FilterExpression(alias, parser)
else:
raise TemplateSyntaxError(
f"'{tag}' tag takes either 1 or 3 arguments: Received {len(args)}."
)
raise TemplateSyntaxError(f"'{tag}' tag takes either 1 or 3 arguments: Received {len(args)}.")
nodelist = parser.parse(parse_until=["endfill"])
parser.delete_first_token()
@ -397,27 +354,18 @@ class ComponentNode(Node):
def __repr__(self):
return "<ComponentNode: %s. Contents: %r>" % (
self.name_fexp,
getattr(
self, "nodelist", None
), # 'nodelist' attribute only assigned later.
getattr(self, "nodelist", None), # 'nodelist' attribute only assigned later.
)
def render(self, context: Context):
resolved_component_name = self.name_fexp.resolve(context)
component_cls: Type[Component] = component_registry.get(
resolved_component_name
)
component_cls: Type[Component] = component_registry.get(resolved_component_name)
# Resolve FilterExpressions and Variables that were passed as args to the
# component, then call component's context method
# to get values to insert into the context
resolved_context_args = [
safe_resolve(arg, context) for arg in self.context_args
]
resolved_context_kwargs = {
key: safe_resolve(kwarg, context)
for key, kwarg in self.context_kwargs.items()
}
resolved_context_args = [safe_resolve(arg, context) for arg in self.context_args]
resolved_context_kwargs = {key: safe_resolve(kwarg, context) for key, kwarg in self.context_kwargs.items()}
if isinstance(self.fill_nodes, ImplicitFillNode):
fill_content = self.fill_nodes.nodelist
@ -437,9 +385,7 @@ class ComponentNode(Node):
)
else:
resolved_alias: None = None
fill_content.append(
(resolved_name, fill_node.nodelist, resolved_alias)
)
fill_content.append((resolved_name, fill_node.nodelist, resolved_alias))
component: Component = component_cls(
registered_name=resolved_component_name,
@ -447,9 +393,7 @@ class ComponentNode(Node):
fill_content=fill_content,
)
component_context: dict = component.get_context_data(
*resolved_context_args, **resolved_context_kwargs
)
component_context: dict = component.get_context_data(*resolved_context_args, **resolved_context_kwargs)
if self.isolated_context:
context = context.new()
@ -457,10 +401,7 @@ class ComponentNode(Node):
rendered_component = component.render(context)
if is_dependency_middleware_active():
return (
RENDERED_COMMENT_TEMPLATE.format(name=resolved_component_name)
+ rendered_component
)
return RENDERED_COMMENT_TEMPLATE.format(name=resolved_component_name) + rendered_component
else:
return rendered_component
@ -482,9 +423,7 @@ def do_component_block(parser, token):
bits = token.split_contents()
bits, isolated_context = check_for_isolated_context_keyword(bits)
component_name, context_args, context_kwargs = parse_component_with_args(
parser, bits, "component_block"
)
component_name, context_args, context_kwargs = parse_component_with_args(parser, bits, "component_block")
body: NodeList = parser.parse(parse_until=["endcomponent_block"])
parser.delete_first_token()
fill_nodes = ()
@ -575,10 +514,7 @@ def is_whitespace_token(token):
def is_block_tag_token(token, name):
return (
token.token_type == TokenType.BLOCK
and token.split_contents()[0] == name
)
return token.token_type == TokenType.BLOCK and token.split_contents()[0] == name
@register.tag(name="if_filled")
@ -610,9 +546,7 @@ def do_if_filled_block(parser, token):
slot_name, is_positive = parse_if_filled_bits(bits)
nodelist = parser.parse(("elif_filled", "else_filled", "endif_filled"))
branches: List[_IfSlotFilledBranchNode] = [
IfSlotFilledConditionBranchNode(
slot_name=slot_name, nodelist=nodelist, is_positive=is_positive
)
IfSlotFilledConditionBranchNode(slot_name=slot_name, nodelist=nodelist, is_positive=is_positive)
]
token = parser.next_token()
@ -621,13 +555,9 @@ def do_if_filled_block(parser, token):
while token.contents.startswith("elif_filled"):
bits = token.split_contents()
slot_name, is_positive = parse_if_filled_bits(bits)
nodelist: NodeList = parser.parse(
("elif_filled", "else_filled", "endif_filled")
)
nodelist: NodeList = parser.parse(("elif_filled", "else_filled", "endif_filled"))
branches.append(
IfSlotFilledConditionBranchNode(
slot_name=slot_name, nodelist=nodelist, is_positive=is_positive
)
IfSlotFilledConditionBranchNode(slot_name=slot_name, nodelist=nodelist, is_positive=is_positive)
)
token = parser.next_token()
@ -656,9 +586,7 @@ def parse_if_filled_bits(
tag, args = bits[0], bits[1:]
if tag in ("else_filled", "endif_filled"):
if len(args) != 0:
raise TemplateSyntaxError(
f"Tag '{tag}' takes no arguments. Received '{' '.join(args)}'"
)
raise TemplateSyntaxError(f"Tag '{tag}' takes no arguments. Received '{' '.join(args)}'")
else:
return None, None
if len(args) == 1:
@ -669,13 +597,10 @@ def parse_if_filled_bits(
is_positive = bool_from_string(args[1])
else:
raise TemplateSyntaxError(
f"{bits[0]} tag arguments '{' '.join(args)}' do not match pattern "
f"'<slotname> (<is_positive>)'"
f"{bits[0]} tag arguments '{' '.join(args)}' do not match pattern " f"'<slotname> (<is_positive>)'"
)
if not is_wrapped_in_quotes(slot_name):
raise TemplateSyntaxError(
f"First argument of '{bits[0]}' must be a quoted string 'literal'."
)
raise TemplateSyntaxError(f"First argument of '{bits[0]}' must be a quoted string 'literal'.")
slot_name = strip_quotes(slot_name)
return slot_name, is_positive
@ -691,9 +616,7 @@ class _IfSlotFilledBranchNode(Node):
raise NotImplementedError
class IfSlotFilledConditionBranchNode(
_IfSlotFilledBranchNode, TemplateAwareNodeMixin
):
class IfSlotFilledConditionBranchNode(_IfSlotFilledBranchNode, TemplateAwareNodeMixin):
def __init__(
self,
slot_name: str,
@ -706,9 +629,7 @@ class IfSlotFilledConditionBranchNode(
def evaluate(self, context) -> bool:
try:
filled_slots: FilledSlotsContext = context[
FILLED_SLOTS_CONTENT_CONTEXT_KEY
]
filled_slots: FilledSlotsContext = context[FILLED_SLOTS_CONTENT_CONTEXT_KEY]
except KeyError:
raise TemplateSyntaxError(
f"Attempted to render {type(self).__name__} outside a Component rendering context."
@ -777,9 +698,7 @@ def parse_component_with_args(parser, bits, tag_name):
)
if tag_name != tag_args[0].token:
raise RuntimeError(
f"Internal error: Expected tag_name to be {tag_name}, but it was {tag_args[0].token}"
)
raise RuntimeError(f"Internal error: Expected tag_name to be {tag_name}, but it was {tag_args[0].token}")
if len(tag_args) > 1:
# At least one position arg, so take the first as the component name
component_name = tag_args[1].token
@ -791,9 +710,7 @@ def parse_component_with_args(parser, bits, tag_name):
context_args = []
context_kwargs = tag_kwargs
except IndexError:
raise TemplateSyntaxError(
f"Call the '{tag_name}' tag with a component name as the first parameter"
)
raise TemplateSyntaxError(f"Call the '{tag_name}' tag with a component name as the first parameter")
return component_name, context_args, context_kwargs
@ -801,11 +718,7 @@ def parse_component_with_args(parser, bits, tag_name):
def safe_resolve(context_item, context):
"""Resolve FilterExpressions and Variables in context if possible. Return other items unchanged."""
return (
context_item.resolve(context)
if hasattr(context_item, "resolve")
else context_item
)
return context_item.resolve(context) if hasattr(context_item, "resolve") else context_item
def is_wrapped_in_quotes(s):
@ -813,9 +726,7 @@ def is_wrapped_in_quotes(s):
def is_dependency_middleware_active():
return getattr(settings, "COMPONENTS", {}).get(
"RENDER_DEPENDENCIES", False
)
return getattr(settings, "COMPONENTS", {}).get("RENDER_DEPENDENCIES", False)
def norm_and_validate_name(name: str, tag: str, context: Optional[str] = None):
@ -826,10 +737,7 @@ def norm_and_validate_name(name: str, tag: str, context: Optional[str] = None):
name = strip_quotes(name)
if not name.isidentifier():
context = f" in '{context}'" if context else ""
raise TemplateSyntaxError(
f"{tag} name '{name}'{context} "
"is not a valid Python identifier."
)
raise TemplateSyntaxError(f"{tag} name '{name}'{context} " "is not a valid Python identifier.")
return name

View file

@ -1,5 +1,5 @@
[tool.black]
line-length = 79
line-length = 119
include = '\.pyi?$'
exclude = '''
/(
@ -18,7 +18,21 @@ exclude = '''
[tool.isort]
profile = "black"
line_length = 79
line_length = 119
multi_line_output = 3
include_trailing_comma = "True"
known_first_party = "django_components"
[tool.flake8]
ignore = ['E302', 'W503']
max-line-length = 119
exclude = [
'migrations',
'__pycache__',
'manage.py',
'settings.py',
'env',
'.env',
'.venv',
'.tox',
]

View file

@ -2,5 +2,7 @@ django
tox
pytest
flake8
flake8-pyproject
isort
pre-commit
pre-commit
black

View file

@ -6,12 +6,16 @@
#
asgiref==3.7.2
# via django
black==24.1.1
# via -r requirements-dev.in
cachetools==5.3.2
# via tox
cfgv==3.4.0
# via pre-commit
chardet==5.2.0
# via tox
click==8.1.7
# via black
colorama==0.4.6
# via tox
distlib==0.3.8
@ -23,6 +27,10 @@ filelock==3.13.1
# tox
# virtualenv
flake8==7.0.0
# via
# -r requirements-dev.in
# flake8-pyproject
flake8-pyproject==1.2.3
# via -r requirements-dev.in
identify==2.5.33
# via pre-commit
@ -32,15 +40,21 @@ isort==5.13.2
# via -r requirements-dev.in
mccabe==0.7.0
# via flake8
mypy-extensions==1.0.0
# via black
nodeenv==1.8.0
# via pre-commit
packaging==23.2
# via
# black
# pyproject-api
# pytest
# tox
pathspec==0.12.1
# via black
platformdirs==4.1.0
# via
# black
# tox
# virtualenv
pluggy==1.3.0

View file

@ -30,9 +30,7 @@ def get_supported_versions(url):
django_to_python = {
version_to_tuple(python_version): [
version_to_tuple(version_string)
for version_string in re.findall(
r"(?<!\.)\d+\.\d+(?!\.)", django_versions
)
for version_string in re.findall(r"(?<!\.)\d+\.\d+(?!\.)", django_versions)
]
for python_version, django_versions in version_dict.items()
}
@ -46,9 +44,7 @@ def get_latest_version(url):
response_content = response.read()
content = response_content.decode("utf-8")
version_string = re.findall(
r"The latest official version is (\d+\.\d)", content
)[0]
version_string = re.findall(r"The latest official version is (\d+\.\d)", content)[0]
return version_to_tuple(version_string)
@ -108,9 +104,7 @@ def build_deps_envlist(python_to_django):
(
env_format(django_version),
env_format(django_version, divider="."),
env_format(
(django_version[0], django_version[1] + 1), divider="."
),
env_format((django_version[0], django_version[1] + 1), divider="."),
)
for django_version in sorted(all_django_versions)
]
@ -123,9 +117,7 @@ def build_pypi_classifiers(python_to_django):
all_python_versions = python_to_django.keys()
for python_version in all_python_versions:
classifiers.append(
f'"Programming Language :: Python :: {env_format(python_version, divider=".")}",'
)
classifiers.append(f'"Programming Language :: Python :: {env_format(python_version, divider=".")}",')
all_django_versions = set()
for django_versions in python_to_django.values():
@ -133,13 +125,9 @@ def build_pypi_classifiers(python_to_django):
all_django_versions.add(django_version)
for django_version in sorted(all_django_versions):
classifiers.append(
f'"Framework :: Django :: {env_format(django_version, divider=".")}",'
)
classifiers.append(f'"Framework :: Django :: {env_format(django_version, divider=".")}",')
return textwrap.indent(
"classifiers=[\n", prefix=" " * 4
) + textwrap.indent("\n".join(classifiers), prefix=" " * 8)
return textwrap.indent("classifiers=[\n", prefix=" " * 4) + textwrap.indent("\n".join(classifiers), prefix=" " * 8)
def build_readme(python_to_django):
@ -154,9 +142,7 @@ def build_readme(python_to_django):
lines = [
(
env_format(python_version, divider="."),
", ".join(
env_format(version, divider=".") for version in django_versions
),
", ".join(env_format(version, divider=".") for version in django_versions),
)
for python_version, django_versions in python_to_django.items()
]
@ -169,13 +155,9 @@ def build_pyenv(python_to_django):
lines = []
all_python_versions = python_to_django.keys()
for python_version in all_python_versions:
lines.append(
f'pyenv install -s {env_format(python_version, divider=".")}'
)
lines.append(f'pyenv install -s {env_format(python_version, divider=".")}')
lines.append(
f'pyenv local {" ".join(env_format(version, divider=".") for version in all_python_versions)}'
)
lines.append(f'pyenv local {" ".join(env_format(version, divider=".") for version in all_python_versions)}')
lines.append("tox -p")
@ -185,20 +167,15 @@ def build_pyenv(python_to_django):
def build_ci_python_versions(python_to_django):
# Outputs python-version: ['3.6', '3.7', '3.8', '3.9', '3.10', '3.11']
lines = [
f"'{env_format(python_version, divider='.')}'"
for python_version, django_versions in python_to_django.items()
f"'{env_format(python_version, divider='.')}'" for python_version, django_versions in python_to_django.items()
]
lines = " " * 8 + f"python-version: [{', '.join(lines)}]"
return lines
def main():
django_to_python = get_supported_versions(
"https://docs.djangoproject.com/en/dev/faq/install/"
)
latest_version = get_latest_version(
"https://www.djangoproject.com/download/"
)
django_to_python = get_supported_versions("https://docs.djangoproject.com/en/dev/faq/install/")
latest_version = get_latest_version("https://www.djangoproject.com/download/")
python_to_django = build_python_to_django(django_to_python, latest_version)

View file

@ -1,12 +0,0 @@
[flake8]
ignore = E302,W503
max-line-length = 119
exclude =
migrations
__pycache__
manage.py
settings.py
env
.env
.venv
.tox

View file

@ -10,9 +10,7 @@ setup(
packages=find_packages(exclude=["tests"]),
version=VERSION,
description="A way to create simple reusable template components in Django.",
long_description=open(
os.path.join(os.path.dirname(__file__), "README.md"), encoding="utf8"
).read(),
long_description=open(os.path.join(os.path.dirname(__file__), "README.md"), encoding="utf8").read(),
long_description_content_type="text/markdown",
author="Emil Stenström",
author_email="emil@emilstenstrom.se",

View file

@ -11,9 +11,7 @@ if not settings.configured:
}
],
COMPONENTS={"template_cache_size": 128},
MIDDLEWARE=[
"django_components.middleware.ComponentDependencyMiddleware"
],
MIDDLEWARE=["django_components.middleware.ComponentDependencyMiddleware"],
DATABASES={
"default": {
"ENGINE": "django.db.backends.sqlite3",

View file

@ -4,7 +4,7 @@ from django.template.engine import Engine
from django.urls import include, path
# isort: off
from .django_test_setup import * # noqa
from .django_test_setup import settings
from .testutils import Django30CompatibleSimpleTestCase as SimpleTestCase
# isort: on
@ -28,9 +28,7 @@ class TestAutodiscover(SimpleTestCase):
try:
autodiscover()
except component.AlreadyRegistered:
self.fail(
"Autodiscover should not raise AlreadyRegistered exception"
)
self.fail("Autodiscover should not raise AlreadyRegistered exception")
class TestLoaderSettingsModule(SimpleTestCase):
@ -42,26 +40,17 @@ class TestLoaderSettingsModule(SimpleTestCase):
current_engine = Engine.get_default()
loader = Loader(current_engine)
dirs = loader.get_dirs()
self.assertEqual(
dirs, [Path(__file__).parent.resolve() / "components"]
)
self.assertEqual(dirs, [Path(__file__).parent.resolve() / "components"])
def test_complex_settings_module(self):
settings.SETTINGS_MODULE = ( # noqa
"tests.test_structures.test_structure_1.config.settings"
)
settings.SETTINGS_MODULE = "tests.test_structures.test_structure_1.config.settings" # noqa
current_engine = Engine.get_default()
loader = Loader(current_engine)
dirs = loader.get_dirs()
self.assertEqual(
dirs,
[
Path(__file__).parent.resolve()
/ "test_structures"
/ "test_structure_1"
/ "components"
],
[Path(__file__).parent.resolve() / "test_structures" / "test_structure_1" / "components"],
)
def test_complex_settings_module_2(self):
@ -72,13 +61,7 @@ class TestLoaderSettingsModule(SimpleTestCase):
dirs = loader.get_dirs()
self.assertEqual(
dirs,
[
Path(__file__).parent.resolve()
/ "test_structures"
/ "test_structure_2"
/ "project"
/ "components"
],
[Path(__file__).parent.resolve() / "test_structures" / "test_structure_2" / "project" / "components"],
)
def test_complex_settings_module_3(self):
@ -88,19 +71,8 @@ class TestLoaderSettingsModule(SimpleTestCase):
loader = Loader(current_engine)
dirs = loader.get_dirs()
expected = [
(
Path(__file__).parent.resolve()
/ "test_structures"
/ "test_structure_3"
/ "components"
),
(
Path(__file__).parent.resolve()
/ "test_structures"
/ "test_structure_3"
/ "project"
/ "components"
),
(Path(__file__).parent.resolve() / "test_structures" / "test_structure_3" / "components"),
(Path(__file__).parent.resolve() / "test_structures" / "test_structure_3" / "project" / "components"),
]
self.assertEqual(
sorted(dirs),
@ -110,11 +82,7 @@ class TestLoaderSettingsModule(SimpleTestCase):
class TestBaseDir(SimpleTestCase):
def setUp(self):
settings.BASE_DIR = ( # noqa
Path(__file__).parent.resolve()
/ "test_structures"
/ "test_structure_1"
)
settings.BASE_DIR = Path(__file__).parent.resolve() / "test_structures" / "test_structure_1" # noqa
settings.SETTINGS_MODULE = "tests_fake.test_autodiscover_fake" # noqa
def tearDown(self) -> None:
@ -125,10 +93,5 @@ class TestBaseDir(SimpleTestCase):
current_engine = Engine.get_default()
loader = Loader(current_engine)
dirs = loader.get_dirs()
expected = [
Path(__file__).parent.resolve()
/ "test_structures"
/ "test_structure_1"
/ "components"
]
expected = [Path(__file__).parent.resolve() / "test_structures" / "test_structure_1" / "components"]
self.assertEqual(dirs, expected)

View file

@ -234,9 +234,7 @@ class InlineComponentTest(SimpleTestCase):
css = "path/to/style.css"
js = "path/to/script.js"
comp = HTMLStringFileCSSJSComponent(
"html_string_file_css_js_component"
)
comp = HTMLStringFileCSSJSComponent("html_string_file_css_js_component")
self.assertHTMLEqual(
comp.render(Context({})),
"<div class='html-string-file'>Content</div>",
@ -259,9 +257,7 @@ class InlineComponentTest(SimpleTestCase):
class Media:
css = "path/to/style.css"
comp = HTMLStringFileCSSJSComponent(
"html_string_file_css_js_component"
)
comp = HTMLStringFileCSSJSComponent("html_string_file_css_js_component")
self.assertHTMLEqual(
comp.render(Context({})),
"<div class='html-string-file'>Content</div>",
@ -284,9 +280,7 @@ class InlineComponentTest(SimpleTestCase):
class Media:
js = "path/to/script.js"
comp = HTMLStringFileCSSJSComponent(
"html_string_file_css_js_component"
)
comp = HTMLStringFileCSSJSComponent("html_string_file_css_js_component")
self.assertHTMLEqual(
comp.render(Context({})),
"<div class='html-string-file'>Content</div>",
@ -303,9 +297,7 @@ class InlineComponentTest(SimpleTestCase):
def test_component_with_variable_in_html(self):
class VariableHTMLComponent(component.Component):
def get_template(self, context):
return Template(
"<div class='variable-html'>{{ variable }}</div>"
)
return Template("<div class='variable-html'>{{ variable }}</div>")
comp = VariableHTMLComponent("variable_html_component")
context = Context({"variable": "Dynamic Content"})

View file

@ -49,9 +49,7 @@ class MockComponentSlot(component.Component):
"""
def get(self, request, *args, **kwargs) -> HttpResponse:
return self.render_to_response(
{"name": "Bob"}, {"second_slot": "Nice to meet you, Bob"}
)
return self.render_to_response({"name": "Bob"}, {"second_slot": "Nice to meet you, Bob"})
@component.register("testcomponent_context_insecure")
@ -64,9 +62,7 @@ class MockInsecureComponentContext(component.Component):
"""
def get(self, request, *args, **kwargs) -> HttpResponse:
return self.render_to_response(
{"variable": "<script>alert(1);</script>"}
)
return self.render_to_response({"variable": "<script>alert(1);</script>"})
@component.register("testcomponent_slot_insecure")
@ -80,9 +76,7 @@ class MockInsecureComponentSlot(component.Component):
"""
def get(self, request, *args, **kwargs) -> HttpResponse:
return self.render_to_response(
{}, {"test_slot": "<script>alert(1);</script>"}
)
return self.render_to_response({}, {"test_slot": "<script>alert(1);</script>"})
def render_template_view(request):

View file

@ -65,15 +65,11 @@ class OuterContextComponent(component.Component):
component.registry.register(name="parent_component", component=ParentComponent)
component.registry.register(
name="parent_with_args", component=ParentComponentWithArgs
)
component.registry.register(name="parent_with_args", component=ParentComponentWithArgs)
component.registry.register(name="variable_display", component=VariableDisplay)
component.registry.register(name="incrementer", component=IncrementerComponent)
component.registry.register(name="simple_component", component=SimpleComponent)
component.registry.register(
name="outer_context_component", component=OuterContextComponent
)
component.registry.register(name="outer_context_component", component=OuterContextComponent)
class ContextTests(SimpleTestCase):
@ -86,17 +82,13 @@ class ContextTests(SimpleTestCase):
)
rendered = template.render(Context())
self.assertIn(
"<h1>Shadowing variable = override</h1>", rendered, rendered
)
self.assertIn("<h1>Shadowing variable = override</h1>", rendered, rendered)
self.assertIn(
"<h1>Shadowing variable = slot_default_override</h1>",
rendered,
rendered,
)
self.assertNotIn(
"<h1>Shadowing variable = NOT SHADOWED</h1>", rendered, rendered
)
self.assertNotIn("<h1>Shadowing variable = NOT SHADOWED</h1>", rendered, rendered)
def test_nested_component_instances_have_unique_context_with_unfilled_slots_and_component_tag(
self,
@ -107,9 +99,7 @@ class ContextTests(SimpleTestCase):
)
rendered = template.render(Context())
self.assertIn(
"<h1>Uniquely named variable = unique_val</h1>", rendered, rendered
)
self.assertIn("<h1>Uniquely named variable = unique_val</h1>", rendered, rendered)
self.assertIn(
"<h1>Uniquely named variable = slot_default_unique</h1>",
rendered,
@ -125,17 +115,13 @@ class ContextTests(SimpleTestCase):
)
rendered = template.render(Context())
self.assertIn(
"<h1>Shadowing variable = override</h1>", rendered, rendered
)
self.assertIn("<h1>Shadowing variable = override</h1>", rendered, rendered)
self.assertIn(
"<h1>Shadowing variable = slot_default_override</h1>",
rendered,
rendered,
)
self.assertNotIn(
"<h1>Shadowing variable = NOT SHADOWED</h1>", rendered, rendered
)
self.assertNotIn("<h1>Shadowing variable = NOT SHADOWED</h1>", rendered, rendered)
def test_nested_component_instances_have_unique_context_with_unfilled_slots_and_component_block_tag(
self,
@ -146,9 +132,7 @@ class ContextTests(SimpleTestCase):
)
rendered = template.render(Context())
self.assertIn(
"<h1>Uniquely named variable = unique_val</h1>", rendered, rendered
)
self.assertIn("<h1>Uniquely named variable = unique_val</h1>", rendered, rendered)
self.assertIn(
"<h1>Uniquely named variable = slot_default_unique</h1>",
rendered,
@ -156,7 +140,8 @@ class ContextTests(SimpleTestCase):
)
def test_nested_component_context_shadows_parent_with_filled_slots(self):
template = Template("""
template = Template(
"""
{% load component_tags %}{% component_dependencies %}
{% component_block 'parent_component' %}
{% fill 'content' %}
@ -164,25 +149,23 @@ class ContextTests(SimpleTestCase):
{% endcomponent_block %}
{% endfill %}
{% endcomponent_block %}
""") # NOQA
""" # NOQA
)
rendered = template.render(Context())
self.assertIn(
"<h1>Shadowing variable = override</h1>", rendered, rendered
)
self.assertIn("<h1>Shadowing variable = override</h1>", rendered, rendered)
self.assertIn(
"<h1>Shadowing variable = shadow_from_slot</h1>",
rendered,
rendered,
)
self.assertNotIn(
"<h1>Shadowing variable = NOT SHADOWED</h1>", rendered, rendered
)
self.assertNotIn("<h1>Shadowing variable = NOT SHADOWED</h1>", rendered, rendered)
def test_nested_component_instances_have_unique_context_with_filled_slots(
self,
):
template = Template("""
template = Template(
"""
{% load component_tags %}{% component_dependencies %}
{% component_block 'parent_component' %}
{% fill 'content' %}
@ -190,12 +173,11 @@ class ContextTests(SimpleTestCase):
{% endcomponent_block %}
{% endfill %}
{% endcomponent_block %}
""") # NOQA
""" # NOQA
)
rendered = template.render(Context())
self.assertIn(
"<h1>Uniquely named variable = unique_val</h1>", rendered, rendered
)
self.assertIn("<h1>Uniquely named variable = unique_val</h1>", rendered, rendered)
self.assertIn(
"<h1>Uniquely named variable = unique_from_slot</h1>",
rendered,
@ -209,21 +191,15 @@ class ContextTests(SimpleTestCase):
"{% load component_tags %}{% component_dependencies %}"
"{% component_block name='parent_component' %}{% endcomponent_block %}"
)
rendered = template.render(
Context({"shadowing_variable": "NOT SHADOWED"})
)
rendered = template.render(Context({"shadowing_variable": "NOT SHADOWED"}))
self.assertIn(
"<h1>Shadowing variable = override</h1>", rendered, rendered
)
self.assertIn("<h1>Shadowing variable = override</h1>", rendered, rendered)
self.assertIn(
"<h1>Shadowing variable = slot_default_override</h1>",
rendered,
rendered,
)
self.assertNotIn(
"<h1>Shadowing variable = NOT SHADOWED</h1>", rendered, rendered
)
self.assertNotIn("<h1>Shadowing variable = NOT SHADOWED</h1>", rendered, rendered)
def test_nested_component_context_shadows_outer_context_with_unfilled_slots_and_component_block_tag(
self,
@ -232,26 +208,21 @@ class ContextTests(SimpleTestCase):
"{% load component_tags %}{% component_dependencies %}"
"{% component_block 'parent_component' %}{% endcomponent_block %}"
)
rendered = template.render(
Context({"shadowing_variable": "NOT SHADOWED"})
)
rendered = template.render(Context({"shadowing_variable": "NOT SHADOWED"}))
self.assertIn(
"<h1>Shadowing variable = override</h1>", rendered, rendered
)
self.assertIn("<h1>Shadowing variable = override</h1>", rendered, rendered)
self.assertIn(
"<h1>Shadowing variable = slot_default_override</h1>",
rendered,
rendered,
)
self.assertNotIn(
"<h1>Shadowing variable = NOT SHADOWED</h1>", rendered, rendered
)
self.assertNotIn("<h1>Shadowing variable = NOT SHADOWED</h1>", rendered, rendered)
def test_nested_component_context_shadows_outer_context_with_filled_slots(
self,
):
template = Template("""
template = Template(
"""
{% load component_tags %}{% component_dependencies %}
{% component_block 'parent_component' %}
{% fill 'content' %}
@ -259,22 +230,17 @@ class ContextTests(SimpleTestCase):
{% endcomponent_block %}
{% endfill %}
{% endcomponent_block %}
""") # NOQA
rendered = template.render(
Context({"shadowing_variable": "NOT SHADOWED"})
""" # NOQA
)
rendered = template.render(Context({"shadowing_variable": "NOT SHADOWED"}))
self.assertIn(
"<h1>Shadowing variable = override</h1>", rendered, rendered
)
self.assertIn("<h1>Shadowing variable = override</h1>", rendered, rendered)
self.assertIn(
"<h1>Shadowing variable = shadow_from_slot</h1>",
rendered,
rendered,
)
self.assertNotIn(
"<h1>Shadowing variable = NOT SHADOWED</h1>", rendered, rendered
)
self.assertNotIn("<h1>Shadowing variable = NOT SHADOWED</h1>", rendered, rendered)
class ParentArgsTests(SimpleTestCase):
@ -286,15 +252,9 @@ class ParentArgsTests(SimpleTestCase):
)
rendered = template.render(Context({"parent_value": "passed_in"}))
self.assertIn(
"<h1>Shadowing variable = passed_in</h1>", rendered, rendered
)
self.assertIn(
"<h1>Uniquely named variable = passed_in</h1>", rendered, rendered
)
self.assertNotIn(
"<h1>Shadowing variable = NOT SHADOWED</h1>", rendered, rendered
)
self.assertIn("<h1>Shadowing variable = passed_in</h1>", rendered, rendered)
self.assertIn("<h1>Uniquely named variable = passed_in</h1>", rendered, rendered)
self.assertNotIn("<h1>Shadowing variable = NOT SHADOWED</h1>", rendered, rendered)
def test_parent_args_available_outside_slots(self):
template = Template(
@ -303,18 +263,13 @@ class ParentArgsTests(SimpleTestCase):
)
rendered = template.render(Context())
self.assertIn(
"<h1>Shadowing variable = passed_in</h1>", rendered, rendered
)
self.assertIn(
"<h1>Uniquely named variable = passed_in</h1>", rendered, rendered
)
self.assertNotIn(
"<h1>Shadowing variable = NOT SHADOWED</h1>", rendered, rendered
)
self.assertIn("<h1>Shadowing variable = passed_in</h1>", rendered, rendered)
self.assertIn("<h1>Uniquely named variable = passed_in</h1>", rendered, rendered)
self.assertNotIn("<h1>Shadowing variable = NOT SHADOWED</h1>", rendered, rendered)
def test_parent_args_available_in_slots(self):
template = Template("""
template = Template(
"""
{% load component_tags %}{% component_dependencies %}
{% component_block 'parent_with_args' parent_value='passed_in' %}
{% fill 'content' %}
@ -322,18 +277,13 @@ class ParentArgsTests(SimpleTestCase):
{% endcomponent_block %}
{% endfill %}
{% endcomponent_block %}
""") # NOQA
""" # NOQA
)
rendered = template.render(Context())
self.assertIn(
"<h1>Shadowing variable = value_from_slot</h1>", rendered, rendered
)
self.assertIn(
"<h1>Uniquely named variable = passed_in</h1>", rendered, rendered
)
self.assertNotIn(
"<h1>Shadowing variable = NOT SHADOWED</h1>", rendered, rendered
)
self.assertIn("<h1>Shadowing variable = value_from_slot</h1>", rendered, rendered)
self.assertIn("<h1>Uniquely named variable = passed_in</h1>", rendered, rendered)
self.assertNotIn("<h1>Shadowing variable = NOT SHADOWED</h1>", rendered, rendered)
class ContextCalledOnceTests(SimpleTestCase):
@ -344,9 +294,7 @@ class ContextCalledOnceTests(SimpleTestCase):
)
rendered = template.render(Context()).strip()
self.assertEqual(
rendered, '<p class="incrementer">value=1;calls=1</p>', rendered
)
self.assertEqual(rendered, '<p class="incrementer">value=1;calls=1</p>', rendered)
def test_one_context_call_with_simple_component_and_arg(self):
template = Template(
@ -354,31 +302,21 @@ class ContextCalledOnceTests(SimpleTestCase):
)
rendered = template.render(Context()).strip()
self.assertEqual(
rendered, '<p class="incrementer">value=3;calls=1</p>', rendered
)
self.assertEqual(rendered, '<p class="incrementer">value=3;calls=1</p>', rendered)
def test_one_context_call_with_component_block(self):
template = Template(
"{% load component_tags %}"
"{% component_block 'incrementer' %}{% endcomponent_block %}"
)
template = Template("{% load component_tags %}" "{% component_block 'incrementer' %}{% endcomponent_block %}")
rendered = template.render(Context()).strip()
self.assertEqual(
rendered, '<p class="incrementer">value=1;calls=1</p>', rendered
)
self.assertEqual(rendered, '<p class="incrementer">value=1;calls=1</p>', rendered)
def test_one_context_call_with_component_block_and_arg(self):
template = Template(
"{% load component_tags %}"
"{% component_block 'incrementer' value='3' %}{% endcomponent_block %}"
"{% load component_tags %}" "{% component_block 'incrementer' value='3' %}{% endcomponent_block %}"
)
rendered = template.render(Context()).strip()
self.assertEqual(
rendered, '<p class="incrementer">value=4;calls=1</p>', rendered
)
self.assertEqual(rendered, '<p class="incrementer">value=4;calls=1</p>', rendered)
def test_one_context_call_with_slot(self):
template = Template(
@ -415,9 +353,7 @@ class ComponentsCanAccessOuterContext(SimpleTestCase):
"{% load component_tags %}{% component_dependencies %}"
"{% component_block 'simple_component' %}{% endcomponent_block %}"
)
rendered = template.render(
Context({"variable": "outer_value"})
).strip()
rendered = template.render(Context({"variable": "outer_value"})).strip()
self.assertIn("outer_value", rendered, rendered)
@ -427,9 +363,7 @@ class IsolatedContextTests(SimpleTestCase):
"{% load component_tags %}{% component_dependencies %}"
"{% component_block 'simple_component' variable only %}{% endcomponent_block %}"
)
rendered = template.render(
Context({"variable": "outer_value"})
).strip()
rendered = template.render(Context({"variable": "outer_value"})).strip()
self.assertIn("outer_value", rendered, rendered)
def test_simple_component_cannot_use_outer_context(self):
@ -437,9 +371,7 @@ class IsolatedContextTests(SimpleTestCase):
"{% load component_tags %}{% component_dependencies %}"
"{% component_block 'simple_component' only %}{% endcomponent_block %}"
)
rendered = template.render(
Context({"variable": "outer_value"})
).strip()
rendered = template.render(Context({"variable": "outer_value"})).strip()
self.assertNotIn("outer_value", rendered, rendered)
@ -504,9 +436,7 @@ class OuterContextPropertyTests(SimpleTestCase):
"{% load component_tags %}{% component_dependencies %}"
"{% component_block 'outer_context_component' only %}{% endcomponent_block %}"
)
rendered = template.render(
Context({"variable": "outer_value"})
).strip()
rendered = template.render(Context({"variable": "outer_value"})).strip()
self.assertIn("outer_value", rendered, rendered)
def test_outer_context_property_with_component_block(self):
@ -514,7 +444,5 @@ class OuterContextPropertyTests(SimpleTestCase):
"{% load component_tags %}{% component_dependencies %}"
"{% component_block 'outer_context_component' only %}{% endcomponent_block %}"
)
rendered = template.render(
Context({"variable": "outer_value"})
).strip()
rendered = template.render(Context({"variable": "outer_value"})).strip()
self.assertIn("outer_value", rendered, rendered)

View file

@ -52,9 +52,7 @@ class ComponentMediaRenderingTests(SimpleTestCase):
def test_no_dependencies_when_no_components_used(self):
component.registry.register(name="test", component=SimpleComponent)
template = Template(
"{% load component_tags %}{% component_dependencies %}"
)
template = Template("{% load component_tags %}{% component_dependencies %}")
rendered = create_and_process_template_response(template)
self.assertInHTML('<script src="script.js">', rendered, count=0)
self.assertInHTML(
@ -66,18 +64,14 @@ class ComponentMediaRenderingTests(SimpleTestCase):
def test_no_js_dependencies_when_no_components_used(self):
component.registry.register(name="test", component=SimpleComponent)
template = Template(
"{% load component_tags %}{% component_js_dependencies %}"
)
template = Template("{% load component_tags %}{% component_js_dependencies %}")
rendered = create_and_process_template_response(template)
self.assertInHTML('<script src="script.js">', rendered, count=0)
def test_no_css_dependencies_when_no_components_used(self):
component.registry.register(name="test", component=SimpleComponent)
template = Template(
"{% load component_tags %}{% component_css_dependencies %}"
)
template = Template("{% load component_tags %}{% component_css_dependencies %}")
rendered = create_and_process_template_response(template)
self.assertInHTML(
'<link href="style.css" media="all" rel="stylesheet"/>',
@ -88,9 +82,7 @@ class ComponentMediaRenderingTests(SimpleTestCase):
def test_preload_dependencies_render_when_no_components_used(self):
component.registry.register(name="test", component=SimpleComponent)
template = Template(
"{% load component_tags %}{% component_dependencies preload='test' %}"
)
template = Template("{% load component_tags %}{% component_dependencies preload='test' %}")
rendered = create_and_process_template_response(template)
self.assertInHTML('<script src="script.js">', rendered, count=1)
self.assertInHTML(
@ -102,9 +94,7 @@ class ComponentMediaRenderingTests(SimpleTestCase):
def test_preload_css_dependencies_render_when_no_components_used(self):
component.registry.register(name="test", component=SimpleComponent)
template = Template(
"{% load component_tags %}{% component_css_dependencies preload='test' %}"
)
template = Template("{% load component_tags %}{% component_css_dependencies preload='test' %}")
rendered = create_and_process_template_response(template)
self.assertInHTML(
'<link href="style.css" media="all" rel="stylesheet"/>',
@ -170,9 +160,7 @@ class ComponentMediaRenderingTests(SimpleTestCase):
def test_placeholder_removed_when_preload_rendered(self):
component.registry.register(name="test", component=SimpleComponent)
template = Template(
"{% load component_tags %}{% component_dependencies preload='test' %}"
)
template = Template("{% load component_tags %}{% component_dependencies preload='test' %}")
rendered = create_and_process_template_response(template)
self.assertNotIn("_RENDERED", rendered)
@ -226,7 +214,10 @@ class ComponentMediaRenderingTests(SimpleTestCase):
):
component.registry.register(name="test", component=MultistyleComponent)
template = Template(
"{% load component_tags %}{% component_js_dependencies %}{% component_block 'test' %}{% endcomponent_block %}"
"""
{% load component_tags %}{% component_js_dependencies %}
{% component_block 'test' %}{% endcomponent_block %}
"""
)
rendered = create_and_process_template_response(template)
self.assertInHTML('<script src="script.js">', rendered, count=1)
@ -247,7 +238,10 @@ class ComponentMediaRenderingTests(SimpleTestCase):
):
component.registry.register(name="test", component=MultistyleComponent)
template = Template(
"{% load component_tags %}{% component_css_dependencies %}{% component_block 'test' %}{% endcomponent_block %}"
"""
{% load component_tags %}{% component_css_dependencies %}
{% component_block 'test' %}{% endcomponent_block %}
"""
)
rendered = create_and_process_template_response(template)
self.assertInHTML('<script src="script.js">', rendered, count=0)
@ -265,13 +259,9 @@ class ComponentMediaRenderingTests(SimpleTestCase):
def test_no_dependencies_with_multiple_unused_components(self):
component.registry.register(name="test1", component=SimpleComponent)
component.registry.register(
name="test2", component=SimpleComponentAlternate
)
component.registry.register(name="test2", component=SimpleComponentAlternate)
template = Template(
"{% load component_tags %}{% component_dependencies %}"
)
template = Template("{% load component_tags %}{% component_dependencies %}")
rendered = create_and_process_template_response(template)
self.assertInHTML('<script src="script.js">', rendered, count=0)
self.assertInHTML('<script src="script2.js">', rendered, count=0)
@ -288,9 +278,7 @@ class ComponentMediaRenderingTests(SimpleTestCase):
def test_correct_css_dependencies_with_multiple_components(self):
component.registry.register(name="test1", component=SimpleComponent)
component.registry.register(
name="test2", component=SimpleComponentAlternate
)
component.registry.register(name="test2", component=SimpleComponentAlternate)
template = Template(
"{% load component_tags %}{% component_css_dependencies %}"
@ -310,9 +298,7 @@ class ComponentMediaRenderingTests(SimpleTestCase):
def test_correct_js_dependencies_with_multiple_components(self):
component.registry.register(name="test1", component=SimpleComponent)
component.registry.register(
name="test2", component=SimpleComponentAlternate
)
component.registry.register(name="test2", component=SimpleComponentAlternate)
template = Template(
"{% load component_tags %}{% component_js_dependencies %}"
@ -324,9 +310,7 @@ class ComponentMediaRenderingTests(SimpleTestCase):
def test_correct_dependencies_with_multiple_components(self):
component.registry.register(name="test1", component=SimpleComponent)
component.registry.register(
name="test2", component=SimpleComponentAlternate
)
component.registry.register(name="test2", component=SimpleComponentAlternate)
template = Template(
"{% load component_tags %}{% component_dependencies %}"
@ -348,19 +332,17 @@ class ComponentMediaRenderingTests(SimpleTestCase):
def test_shared_dependencies_rendered_once(self):
component.registry.register(name="test1", component=SimpleComponent)
component.registry.register(
name="test2", component=SimpleComponentAlternate
)
component.registry.register(
name="test3", component=SimpleComponentWithSharedDependency
)
component.registry.register(name="test2", component=SimpleComponentAlternate)
component.registry.register(name="test3", component=SimpleComponentWithSharedDependency)
template = Template("""
template = Template(
"""
{% load component_tags %}{% component_dependencies %}
{% component_block 'test1' variable='variable' %}{% endcomponent_block %}
{% component_block 'test2' variable='variable' %}{% endcomponent_block %}
{% component_block 'test1' variable='variable' %}{% endcomponent_block %}
""")
"""
)
rendered = create_and_process_template_response(template)
self.assertInHTML('<script src="script.js">', rendered, count=1)
self.assertInHTML('<script src="script2.js">', rendered, count=1)
@ -377,27 +359,23 @@ class ComponentMediaRenderingTests(SimpleTestCase):
def test_placeholder_removed_when_multiple_component_rendered(self):
component.registry.register(name="test1", component=SimpleComponent)
component.registry.register(
name="test2", component=SimpleComponentAlternate
)
component.registry.register(
name="test3", component=SimpleComponentWithSharedDependency
)
component.registry.register(name="test2", component=SimpleComponentAlternate)
component.registry.register(name="test3", component=SimpleComponentWithSharedDependency)
template = Template("""
template = Template(
"""
{% load component_tags %}{% component_dependencies %}
{% component_block 'test1' variable='variable' %}{% endcomponent_block %}
{% component_block 'test2' variable='variable' %}{% endcomponent_block %}
{% component_block 'test1' variable='variable' %}{% endcomponent_block %}
""")
"""
)
rendered = create_and_process_template_response(template)
self.assertNotIn("_RENDERED", rendered)
def test_middleware_response_without_content_type(self):
response = HttpResponseNotModified()
middleware = ComponentDependencyMiddleware(
get_response=lambda _: response
)
middleware = ComponentDependencyMiddleware(get_response=lambda _: response)
request = Mock()
self.assertEqual(response, middleware(request=request))
@ -410,9 +388,7 @@ class ComponentMediaRenderingTests(SimpleTestCase):
"test_component",
]
for component_name in component_names:
component.registry.register(
name=component_name, component=SimpleComponent
)
component.registry.register(name=component_name, component=SimpleComponent)
template = Template(
"{% load component_tags %}"
"{% component_js_dependencies %}"

View file

@ -27,9 +27,7 @@ class ComponentRegistryTest(unittest.TestCase):
class TestComponent(component.Component):
pass
self.assertEqual(
component.registry.get("decorated_component"), TestComponent
)
self.assertEqual(component.registry.get("decorated_component"), TestComponent)
def test_simple_register(self):
self.registry.register(name="testcomponent", component=MockComponent)
@ -49,18 +47,12 @@ class ComponentRegistryTest(unittest.TestCase):
def test_prevent_registering_different_components_with_the_same_name(self):
self.registry.register(name="testcomponent", component=MockComponent)
with self.assertRaises(component.AlreadyRegistered):
self.registry.register(
name="testcomponent", component=MockComponent2
)
self.registry.register(name="testcomponent", component=MockComponent2)
def test_allow_duplicated_registration_of_the_same_component(self):
try:
self.registry.register(
name="testcomponent", component=MockComponentView
)
self.registry.register(
name="testcomponent", component=MockComponentView
)
self.registry.register(name="testcomponent", component=MockComponentView)
self.registry.register(name="testcomponent", component=MockComponentView)
except component.AlreadyRegistered:
self.fail("Should not raise AlreadyRegistered")

View file

@ -52,15 +52,11 @@ class CreateComponentCommandTest(TestCase):
os.path.join(self.temp_dir, component_name, "test.js"),
os.path.join(self.temp_dir, component_name, "test.css"),
os.path.join(self.temp_dir, component_name, "test.html"),
os.path.join(
self.temp_dir, component_name, f"{component_name}.py"
),
os.path.join(self.temp_dir, component_name, f"{component_name}.py"),
]
for file_path in expected_files:
self.assertTrue(
os.path.exists(file_path), f"File {file_path} was not created"
)
self.assertTrue(os.path.exists(file_path), f"File {file_path} was not created")
def test_dry_run(self):
component_name = "dryruncomponent"
@ -80,9 +76,7 @@ class CreateComponentCommandTest(TestCase):
component_path = os.path.join(self.temp_dir, component_name)
os.makedirs(component_path)
with open(
os.path.join(component_path, f"{component_name}.py"), "w"
) as f:
with open(os.path.join(component_path, f"{component_name}.py"), "w") as f:
f.write("hello world")
call_command(
@ -93,9 +87,7 @@ class CreateComponentCommandTest(TestCase):
"--force",
)
with open(
os.path.join(component_path, f"{component_name}.py"), "r"
) as f:
with open(os.path.join(component_path, f"{component_name}.py"), "r") as f:
self.assertNotIn("hello world", f.read())
def test_error_existing_component_no_force(self):
@ -104,9 +96,7 @@ class CreateComponentCommandTest(TestCase):
os.makedirs(component_path)
with self.assertRaises(CommandError):
call_command(
"startcomponent", component_name, "--path", self.temp_dir
)
call_command("startcomponent", component_name, "--path", self.temp_dir)
def test_verbose_output(self):
component_name = "verbosecomponent"

View file

@ -100,41 +100,44 @@ class ComponentTemplateTagTest(SimpleTestCase):
def test_single_component(self):
component.registry.register(name="test", component=SimpleComponent)
simple_tag_tempate = '{% load component_tags %}{% component_block name="test" variable="variable" %}{% endcomponent_block %}'
simple_tag_tempate = """
{% load component_tags %}
{% component_block name="test" variable="variable" %}{% endcomponent_block %}
"""
block_tag_template = self.inline_to_block(simple_tag_tempate)
for tag in [simple_tag_tempate, block_tag_template]:
template = Template(tag)
rendered = template.render(Context({}))
self.assertHTMLEqual(
rendered, "Variable: <strong>variable</strong>\n"
)
self.assertHTMLEqual(rendered, "Variable: <strong>variable</strong>\n")
def test_call_with_invalid_name(self):
# Note: No tag registered
simple_tag_tempate = '{% load component_tags %}{% component_block name="test" variable="variable" %}{% endcomponent_block %}'
simple_tag_tempate = """
{% load component_tags %}
{% component_block name="test" variable="variable" %}{% endcomponent_block %}
"""
block_tag_template = self.inline_to_block(simple_tag_tempate)
for tag in [simple_tag_tempate, block_tag_template]:
template = Template(tag)
with self.assertRaises(
django_components.component_registry.NotRegistered
):
with self.assertRaises(django_components.component_registry.NotRegistered):
template.render(Context({}))
def test_component_called_with_positional_name(self):
component.registry.register(name="test", component=SimpleComponent)
simple_tag_tempate = '{% load component_tags %}{% component_block "test" variable="variable" %}{% endcomponent_block %}'
simple_tag_tempate = """
{% load component_tags %}
{% component_block "test" variable="variable" %}{% endcomponent_block %}
"""
block_tag_template = self.inline_to_block(simple_tag_tempate)
for tag in [simple_tag_tempate, block_tag_template]:
template = Template(tag)
rendered = template.render(Context({}))
self.assertHTMLEqual(
rendered, "Variable: <strong>variable</strong>\n"
)
self.assertHTMLEqual(rendered, "Variable: <strong>variable</strong>\n")
def test_call_component_with_two_variables(self):
component.registry.register(name="test", component=IffedComponent)
@ -148,24 +151,22 @@ class ComponentTemplateTagTest(SimpleTestCase):
for tag in [simple_tag_tempate, block_tag_template]:
template = Template(tag)
rendered = template.render(Context({}))
expected_outcome = (
"""Variable: <strong>variable</strong>\n"""
"""Variable2: <strong>hej</strong>"""
)
expected_outcome = """Variable: <strong>variable</strong>\n""" """Variable2: <strong>hej</strong>"""
self.assertHTMLEqual(rendered, textwrap.dedent(expected_outcome))
def test_component_called_with_singlequoted_name(self):
component.registry.register(name="test", component=SimpleComponent)
simple_tag_tempate = """{% load component_tags %}{% component_block 'test' variable="variable" %}{% endcomponent_block %}"""
simple_tag_tempate = """
{% load component_tags %}
{% component_block 'test' variable="variable" %}{% endcomponent_block %}
"""
block_tag_template = self.inline_to_block(simple_tag_tempate)
for tag in [simple_tag_tempate, block_tag_template]:
template = Template(tag)
rendered = template.render(Context({}))
self.assertHTMLEqual(
rendered, "Variable: <strong>variable</strong>\n"
)
self.assertHTMLEqual(rendered, "Variable: <strong>variable</strong>\n")
def test_component_called_with_variable_as_name(self):
component.registry.register(name="test", component=SimpleComponent)
@ -181,9 +182,7 @@ class ComponentTemplateTagTest(SimpleTestCase):
for tag in [simple_tag_tempate, block_tag_template]:
template = Template(tag)
rendered = template.render(Context({}))
self.assertHTMLEqual(
rendered, "Variable: <strong>variable</strong>\n"
)
self.assertHTMLEqual(rendered, "Variable: <strong>variable</strong>\n")
def test_component_called_with_invalid_variable_as_name(self):
component.registry.register(name="test", component=SimpleComponent)
@ -199,9 +198,7 @@ class ComponentTemplateTagTest(SimpleTestCase):
for tag in [simple_tag_tempate, block_tag_template]:
template = Template(tag)
with self.assertRaises(
django_components.component_registry.NotRegistered
):
with self.assertRaises(django_components.component_registry.NotRegistered):
template.render(Context({}))
@ -241,9 +238,7 @@ class ComponentSlottedTemplateTagTest(SimpleTestCase):
)
def test_slotted_template_with_context_var(self):
component.registry.register(
name="test1", component=SlottedComponentWithContext
)
component.registry.register(name="test1", component=SlottedComponentWithContext)
template = Template(
"""
@ -276,9 +271,7 @@ class ComponentSlottedTemplateTagTest(SimpleTestCase):
def test_slotted_template_no_slots_filled(self):
component.registry.register(name="test", component=SlottedComponent)
template = Template(
'{% load component_tags %}{% component_block "test" %}{% endcomponent_block %}'
)
template = Template('{% load component_tags %}{% component_block "test" %}{% endcomponent_block %}')
rendered = template.render(Context({}))
self.assertHTMLEqual(
@ -293,9 +286,7 @@ class ComponentSlottedTemplateTagTest(SimpleTestCase):
)
def test_slotted_template_without_slots(self):
component.registry.register(
name="test", component=SlottedComponentNoSlots
)
component.registry.register(name="test", component=SlottedComponentNoSlots)
template = Template(
"""
{% load component_tags %}
@ -307,9 +298,7 @@ class ComponentSlottedTemplateTagTest(SimpleTestCase):
self.assertHTMLEqual(rendered, "<custom-template></custom-template>")
def test_slotted_template_without_slots_and_single_quotes(self):
component.registry.register(
name="test", component=SlottedComponentNoSlots
)
component.registry.register(name="test", component=SlottedComponentNoSlots)
template = Template(
"""
{% load component_tags %}
@ -397,9 +386,7 @@ class ComponentSlottedTemplateTagTest(SimpleTestCase):
self.assertHTMLEqual(rendered, expected)
def test_error_raised_when_default_and_required_slot_not_filled(self):
component.registry.register(
"test_comp", ComponentWithDefaultAndRequiredSlot
)
component.registry.register("test_comp", ComponentWithDefaultAndRequiredSlot)
template = Template(
"""
{% load component_tags %}
@ -488,9 +475,7 @@ class ComponentSlottedTemplateTagTest(SimpleTestCase):
def test_component_template_cannot_have_multiple_default_slots(self):
class BadComponent(component.Component):
def get_template(
self, context, template_name: Optional[str] = None
) -> Template:
def get_template(self, context, template_name: Optional[str] = None) -> Template:
return Template(
"""
{% load django_components %}
@ -543,9 +528,7 @@ class SlottedTemplateRegressionTests(SimpleTestCase):
component.registry.clear()
def test_slotted_template_that_uses_missing_variable(self):
component.registry.register(
name="test", component=SlottedComponentWithMissingVariable
)
component.registry.register(name="test", component=SlottedComponentWithMissingVariable)
template = Template(
"""
{% load component_tags %}
@ -566,9 +549,7 @@ class SlottedTemplateRegressionTests(SimpleTestCase):
)
def test_component_block_accepts_provided_and_default_parameters(self):
component.registry.register(
name="test", component=ComponentWithProvidedAndDefaultParameters
)
component.registry.register(name="test", component=ComponentWithProvidedAndDefaultParameters)
template = Template(
"""
@ -590,32 +571,22 @@ class MultiComponentTests(SimpleTestCase):
def register_components(self):
component.registry.register("first_component", SlottedComponent)
component.registry.register(
"second_component", SlottedComponentWithContext
)
component.registry.register("second_component", SlottedComponentWithContext)
def make_template(self, first_component_slot="", second_component_slot=""):
return Template(
"{% load component_tags %}"
"{% component_block 'first_component' %}"
+ first_component_slot
+ "{% endcomponent_block %}"
"{% component_block 'first_component' %}" + first_component_slot + "{% endcomponent_block %}"
"{% component_block 'second_component' variable='xyz' %}"
+ second_component_slot
+ "{% endcomponent_block %}"
)
def expected_result(
self, first_component_slot="", second_component_slot=""
):
def expected_result(self, first_component_slot="", second_component_slot=""):
return (
"<custom-template><header>{}</header>".format(
first_component_slot or "Default header"
)
"<custom-template><header>{}</header>".format(first_component_slot or "Default header")
+ "<main>Default main</main><footer>Default footer</footer></custom-template>"
+ "<custom-template><header>{}</header>".format(
second_component_slot or "Default header"
)
+ "<custom-template><header>{}</header>".format(second_component_slot or "Default header")
+ "<main>Default main</main><footer>Default footer</footer></custom-template>"
)
@ -633,9 +604,7 @@ class MultiComponentTests(SimpleTestCase):
second_slot_content = "<div>Slot #2</div>"
first_slot = self.wrap_with_slot_tags(first_slot_content)
second_slot = self.wrap_with_slot_tags(second_slot_content)
rendered = self.make_template(first_slot, second_slot).render(
Context({})
)
rendered = self.make_template(first_slot, second_slot).render(Context({}))
self.assertHTMLEqual(
rendered,
self.expected_result(first_slot_content, second_slot_content),
@ -646,18 +615,14 @@ class MultiComponentTests(SimpleTestCase):
first_slot_content = "<p>Slot #1</p>"
first_slot = self.wrap_with_slot_tags(first_slot_content)
rendered = self.make_template(first_slot).render(Context({}))
self.assertHTMLEqual(
rendered, self.expected_result(first_slot_content)
)
self.assertHTMLEqual(rendered, self.expected_result(first_slot_content))
def test_both_components_render_correctly_when_only_second_has_slots(self):
self.register_components()
second_slot_content = "<div>Slot #2</div>"
second_slot = self.wrap_with_slot_tags(second_slot_content)
rendered = self.make_template("", second_slot).render(Context({}))
self.assertHTMLEqual(
rendered, self.expected_result("", second_slot_content)
)
self.assertHTMLEqual(rendered, self.expected_result("", second_slot_content))
class TemplateInstrumentationTest(SimpleTestCase):
@ -689,9 +654,7 @@ class TemplateInstrumentationTest(SimpleTestCase):
def receive_template_signal(sender, template, context, **_kwargs):
templates_used.append(template.name)
template_rendered.connect(
receive_template_signal, dispatch_uid="test_method"
)
template_rendered.connect(receive_template_signal, dispatch_uid="test_method")
subject_template.render(render_context or Context({}))
template_rendered.disconnect(dispatch_uid="test_method")
return templates_used
@ -823,9 +786,7 @@ class ConditionalSlotTests(SimpleTestCase):
"""
)
rendered = template.render(Context({}))
self.assertHTMLEqual(
rendered, '<p id="a">Default A</p><p id="b">Default B</p>'
)
self.assertHTMLEqual(rendered, '<p id="a">Default A</p><p id="b">Default B</p>')
def test_one_slot_overridden(self):
template = Template(
@ -840,9 +801,7 @@ class ConditionalSlotTests(SimpleTestCase):
"""
)
rendered = template.render(Context({}))
self.assertHTMLEqual(
rendered, '<p id="a">Default A</p><p id="b">Override B</p>'
)
self.assertHTMLEqual(rendered, '<p id="a">Default A</p><p id="b">Override B</p>')
def test_both_slots_overridden(self):
template = Template(
@ -859,9 +818,7 @@ class ConditionalSlotTests(SimpleTestCase):
"""
)
rendered = template.render(Context({}))
self.assertHTMLEqual(
rendered, '<p id="a">Override A</p><p id="b">Override B</p>'
)
self.assertHTMLEqual(rendered, '<p id="a">Override A</p><p id="b">Override B</p>')
class SlotSuperTests(SimpleTestCase):
@ -957,9 +914,7 @@ class TemplateSyntaxErrorTests(SimpleTestCase):
super().setUpClass()
component.registry.register("test", SlottedComponent)
component.registry.register("broken_component", BrokenComponent)
component.registry.register(
"nonunique_slot_component", NonUniqueSlotsComponent
)
component.registry.register("nonunique_slot_component", NonUniqueSlotsComponent)
@classmethod
def tearDownClass(cls) -> None:
@ -1141,16 +1096,12 @@ class ConditionalIfFilledSlotsTests(SimpleTestCase):
@classmethod
def setUpClass(cls) -> None:
super().setUpClass()
component.registry.register(
"conditional_slots", cls.ComponentWithConditionalSlots
)
component.registry.register("conditional_slots", cls.ComponentWithConditionalSlots)
component.registry.register(
"complex_conditional_slots",
cls.ComponentWithComplexConditionalSlots,
)
component.registry.register(
"negated_conditional_slot", cls.ComponentWithNegatedConditionalSlot
)
component.registry.register("negated_conditional_slot", cls.ComponentWithNegatedConditionalSlot)
@classmethod
def tearDownClass(cls) -> None:
@ -1310,9 +1261,7 @@ class IterationFillTest(SimpleTestCase):
django_components.component.registry.clear()
def test_inner_slot_iteration_basic(self):
component.registry.register(
"slot_in_a_loop", self.ComponentSimpleSlotInALoop
)
component.registry.register("slot_in_a_loop", self.ComponentSimpleSlotInALoop)
template = Template(
"""
@ -1336,9 +1285,7 @@ class IterationFillTest(SimpleTestCase):
)
def test_inner_slot_iteration_with_variable_from_outer_scope(self):
component.registry.register(
"slot_in_a_loop", self.ComponentSimpleSlotInALoop
)
component.registry.register("slot_in_a_loop", self.ComponentSimpleSlotInALoop)
template = Template(
"""
@ -1372,9 +1319,7 @@ class IterationFillTest(SimpleTestCase):
)
def test_inner_slot_iteration_nested(self):
component.registry.register(
"slot_in_a_loop", self.ComponentSimpleSlotInALoop
)
component.registry.register("slot_in_a_loop", self.ComponentSimpleSlotInALoop)
objects = [
{"inner": ["OBJECT1_ITER1", "OBJECT2_ITER1"]},
@ -1408,9 +1353,7 @@ class IterationFillTest(SimpleTestCase):
)
def test_inner_slot_iteration_nested_with_outer_scope_variable(self):
component.registry.register(
"slot_in_a_loop", self.ComponentSimpleSlotInALoop
)
component.registry.register("slot_in_a_loop", self.ComponentSimpleSlotInALoop)
objects = [
{"inner": ["OBJECT1_ITER1", "OBJECT2_ITER1"]},
@ -1460,9 +1403,7 @@ class IterationFillTest(SimpleTestCase):
)
def test_inner_slot_iteration_nested_with_slot_default(self):
component.registry.register(
"slot_in_a_loop", self.ComponentSimpleSlotInALoop
)
component.registry.register("slot_in_a_loop", self.ComponentSimpleSlotInALoop)
objects = [
{"inner": ["OBJECT1_ITER1", "OBJECT2_ITER1"]},
@ -1498,9 +1439,7 @@ class IterationFillTest(SimpleTestCase):
def test_inner_slot_iteration_nested_with_slot_default_and_outer_scope_variable(
self,
):
component.registry.register(
"slot_in_a_loop", self.ComponentSimpleSlotInALoop
)
component.registry.register("slot_in_a_loop", self.ComponentSimpleSlotInALoop)
objects = [
{"inner": ["OBJECT1_ITER1", "OBJECT2_ITER1"]},

View file

@ -8,9 +8,7 @@ from django_components.middleware import ComponentDependencyMiddleware
# Create middleware instance
response_stash = None
middleware = ComponentDependencyMiddleware(
get_response=lambda _: response_stash
)
middleware = ComponentDependencyMiddleware(get_response=lambda _: response_stash)
class Django30CompatibleSimpleTestCase(SimpleTestCase):
@ -19,9 +17,7 @@ class Django30CompatibleSimpleTestCase(SimpleTestCase):
left = left.replace(' type="text/css"', "")
right = right.replace(' type="text/javascript"', "")
right = right.replace(' type="text/css"', "")
super(Django30CompatibleSimpleTestCase, self).assertHTMLEqual(
left, right
)
super(Django30CompatibleSimpleTestCase, self).assertHTMLEqual(left, right)
def assertInHTML(self, needle, haystack, count=None, msg_prefix=""):
haystack = haystack.replace(' type="text/javascript"', "")
@ -37,9 +33,7 @@ request = Mock()
mock_template = Mock()
def create_and_process_template_response(
template, context=None, use_middleware=True
):
def create_and_process_template_response(template, context=None, use_middleware=True):
context = context if context is not None else Context({})
mock_template.render = lambda context, _: template.render(context)
response = TemplateResponse(request, mock_template, context)