diff --git a/README.md b/README.md index c9c56bf8..bedfc0cc 100644 --- a/README.md +++ b/README.md @@ -63,8 +63,8 @@ class Calendar(Component): js_file = "calendar.js" css_file = "calendar.css" - def get_context_data(self, date): - return {"date": date} + def get_template_data(self, args, kwargs, slots, context): + return {"date": kwargs["date"]} ``` Use the component like this: @@ -125,9 +125,9 @@ class Calendar(Component): css = ["bootstrap/dist/css/bootstrap.min.css"] # Variables available in the template - def get_context_data(self, date): + def get_template_data(self, args, kwargs, slots, context): return { - "date": date + "date": kwargs["date"] } ``` @@ -232,7 +232,7 @@ class Table(Component): """ - def get_context_data(self, var1, var2, variable, another, **attrs): + def get_template_data(self, args, kwargs, slots, context): # Access component's ID assert self.id == "djc1A2b3c" @@ -247,7 +247,7 @@ class Table(Component): assert self.context_processors_data['user'].username == "admin" return { - "variable": variable, + "variable": kwargs["variable"], } # Access component's HTML / JS / CSS @@ -347,9 +347,9 @@ class Calendar(Component): }, ) - def get_context_data(self, page): + def get_template_data(self, args, kwargs, slots, context): return { - "page": page, + "page": kwargs["page"], } # Get auto-generated URL for the component @@ -381,7 +381,7 @@ Read more about [Provide / Inject](https://django-components.github.io/django-co class Header(Component): template = "..." - def get_context_data(self, *args, **kwargs): + def get_template_data(self, args, kwargs, slots, context): theme = self.inject("theme").variant return { "theme": theme, diff --git a/docs/concepts/advanced/component_caching.md b/docs/concepts/advanced/component_caching.md index 4d427fa5..5ee84072 100644 --- a/docs/concepts/advanced/component_caching.md +++ b/docs/concepts/advanced/component_caching.md @@ -98,8 +98,8 @@ class MyComponent(Component): ttl = 300 # Cache for 5 minutes cache_name = "my_cache" - def get_context_data(self, name, **kwargs): - return {"name": name} + def get_template_data(self, args, kwargs, slots, context): + return {"name": kwargs["name"]} ``` In this example, the component's rendered output is cached for 5 minutes using the `my_cache` backend. diff --git a/docs/concepts/advanced/component_context_scope.md b/docs/concepts/advanced/component_context_scope.md index 119b5c43..418a1d69 100644 --- a/docs/concepts/advanced/component_context_scope.md +++ b/docs/concepts/advanced/component_context_scope.md @@ -12,7 +12,7 @@ NOTE: `{% csrf_token %}` tags need access to the top-level context, and they wil If you find yourself using the `only` modifier often, you can set the [context_behavior](#context-behavior) option to `"isolated"`, which automatically applies the `only` modifier. This is useful if you want to make sure that components don't accidentally access the outer context. -Components can also access the outer context in their context methods like `get_context_data` by accessing the property `self.outer_context`. +Components can also access the outer context in their context methods like `get_template_data` by accessing the property `self.outer_context`. ## Example of Accessing Outer Context @@ -22,14 +22,14 @@ Components can also access the outer context in their context methods like `get_ ``` -Assuming that the rendering context has variables such as `date`, you can use `self.outer_context` to access them from within `get_context_data`. Here's how you might implement it: +Assuming that the rendering context has variables such as `date`, you can use `self.outer_context` to access them from within `get_template_data`. Here's how you might implement it: ```python class Calender(Component): ... - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): outer_field = self.outer_context["date"] return { "date": outer_fields, @@ -56,7 +56,7 @@ This has two modes: [`{% with %}`](https://docs.djangoproject.com/en/5.1/ref/templates/builtins/#with) tags. - Any loops ([`{% for ... %}`](https://docs.djangoproject.com/en/5.1/ref/templates/builtins/#cycle)) that the `{% fill %}` tag is part of. - - Data returned from [`Component.get_context_data()`](../../../reference/api#django_components.Component.get_context_data) + - Data returned from [`Component.get_template_data()`](../../../reference/api#django_components.Component.get_template_data) of the component that owns the fill tag. - `"isolated"` @@ -69,12 +69,12 @@ This has two modes: - Any loops ([`{% for ... %}`](https://docs.djangoproject.com/en/5.1/ref/templates/builtins/#cycle)) that the `{% fill %}` tag is part of. - - [`Component.get_context_data()`](../../../reference/api#django_components.Component.get_context_data) + - [`Component.get_template_data()`](../../../reference/api#django_components.Component.get_template_data) of the component which defined the template (AKA the "root" component). !!! warning - Notice that the component whose `get_context_data()` we use inside + Notice that the component whose `get_template_data()` we use inside [`{% fill %}`](../../../reference/template_tags#fill) is NOT the same across the two modes! @@ -93,10 +93,10 @@ This has two modes: """ ``` - - `"django"` - `my_var` has access to data from `get_context_data()` of both `Inner` and `Outer`. + - `"django"` - `my_var` has access to data from `get_template_data()` of both `Inner` and `Outer`. If there are variables defined in both, then `Inner` overshadows `Outer`. - - `"isolated"` - `my_var` has access to data from `get_context_data()` of ONLY `Outer`. + - `"isolated"` - `my_var` has access to data from `get_template_data()` of ONLY `Outer`. ### Example "django" @@ -115,11 +115,11 @@ class RootComp(Component): {% endwith %} """ - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): return { "my_var": 123 } ``` -Then if [`get_context_data()`](../../../reference/api#django_components.Component.get_context_data) +Then if [`get_template_data()`](../../../reference/api#django_components.Component.get_template_data) of the component `"my_comp"` returns following data: ```py @@ -154,11 +154,11 @@ class RootComp(Component): {% endwith %} """ - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): return { "my_var": 123 } ``` -Then if [`get_context_data()`](../../../reference/api#django_components.Component.get_context_data) +Then if [`get_template_data()`](../../../reference/api#django_components.Component.get_template_data) of the component `"my_comp"` returns following data: ```py @@ -172,7 +172,7 @@ Then the template will be rendered as: # cheese ``` -Because variables `"my_var"` and `"cheese"` are searched only inside `RootComponent.get_context_data()`. +Because variables `"my_var"` and `"cheese"` are searched only inside `RootComponent.get_template_data()`. But since `"cheese"` is not defined there, it's empty. !!! info diff --git a/docs/concepts/advanced/component_registry.md b/docs/concepts/advanced/component_registry.md index 57e2e328..f5865420 100644 --- a/docs/concepts/advanced/component_registry.md +++ b/docs/concepts/advanced/component_registry.md @@ -12,9 +12,9 @@ class Calendar(Component): template_file = "template.html" # This component takes one parameter, a date string to show in the template - def get_context_data(self, date): + def get_template_data(self, args, kwargs, slots, context): return { - "date": date, + "date": kwargs["date"], } ``` diff --git a/docs/concepts/advanced/extensions.md b/docs/concepts/advanced/extensions.md index 97a9a196..dad769e6 100644 --- a/docs/concepts/advanced/extensions.md +++ b/docs/concepts/advanced/extensions.md @@ -42,7 +42,7 @@ Extensions can define methods to hook into lifecycle events, such as: - Un/registering a component - Creating or deleting a registry - Pre-processing data passed to a component on render -- Post-processing data returned from [`get_context_data()`](../../../reference/api#django_components.Component.get_context_data) +- Post-processing data returned from [`get_template_data()`](../../../reference/api#django_components.Component.get_template_data) and others. See the full list in [Extension Hooks Reference](../../../reference/extension_hooks). @@ -122,7 +122,7 @@ For example, the View extension is available as `self.view`: ```python class MyTable(Component): - def get_context_data(self, request): + def get_template_data(self, args, kwargs, slots, context): # `self.view` points to the instance of `View` extension. return { "view": self.view, @@ -133,7 +133,7 @@ And the Storybook extension is available as `self.storybook`: ```python class MyTable(Component): - def get_context_data(self, request): + def get_template_data(self, args, kwargs, slots, context): # `self.storybook` points to the instance of `Storybook` extension. return { "title": self.storybook.title(), diff --git a/docs/concepts/advanced/provide_inject.md b/docs/concepts/advanced/provide_inject.md index a2013fdf..3c843f5e 100644 --- a/docs/concepts/advanced/provide_inject.md +++ b/docs/concepts/advanced/provide_inject.md @@ -78,7 +78,7 @@ In the example from previous section, we've defined two kwargs: `hello="hi" anot ```py class ChildComponent(Component): - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): my_data = self.inject("my_data") print(my_data.hello) # hi print(my_data.another) # 123 @@ -94,7 +94,7 @@ To avoid the error, you can pass a second argument to [`inject()`](../../../refe ```py class ChildComponent(Component): - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): my_data = self.inject("invalid_key", DEFAULT_DATA) assert my_data == DEFAULT_DATA return {} @@ -119,7 +119,7 @@ class ChildComponent(Component):
{{ my_data.another }}
""" - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): my_data = self.inject("my_data", "default") return {"my_data": my_data} diff --git a/docs/concepts/fundamentals/component_defaults.md b/docs/concepts/fundamentals/component_defaults.md index 804226c5..23b6ec9d 100644 --- a/docs/concepts/fundamentals/component_defaults.md +++ b/docs/concepts/fundamentals/component_defaults.md @@ -1,5 +1,5 @@ When a component is being rendered, the component inputs are passed to various methods like -[`get_context_data()`](../../../reference/api#django_components.Component.get_context_data), +[`get_template_data()`](../../../reference/api#django_components.Component.get_template_data), [`get_js_data()`](../../../reference/api#django_components.Component.get_js_data), or [`get_css_data()`](../../../reference/api#django_components.Component.get_css_data). @@ -24,10 +24,10 @@ class MyTable(Component): position = "left" selected_items = Default(lambda: [1, 2, 3]) - def get_context_data(self, position, selected_items): + def get_template_data(self, args, kwargs, slots, context): return { - "position": position, - "selected_items": selected_items, + "position": kwargs["position"], + "selected_items": kwargs["selected_items"], } ... @@ -138,10 +138,10 @@ class MyTable(Component): position = "left" selected_items = Default(lambda: [1, 2, 3]) - def get_context_data(self, position, selected_items): + def get_template_data(self, args, kwargs, slots, context): return { - "position": position, - "selected_items": selected_items, + "position": kwargs["position"], + "selected_items": kwargs["selected_items"], } ``` diff --git a/docs/concepts/fundamentals/html_attributes.md b/docs/concepts/fundamentals/html_attributes.md index b990133b..22b111d3 100644 --- a/docs/concepts/fundamentals/html_attributes.md +++ b/docs/concepts/fundamentals/html_attributes.md @@ -47,10 +47,10 @@ You can use this for example to allow users of your component to add extra attri ```djc_py @register("my_comp") class MyComp(Component): - # Capture extra kwargs in `attrs` - def get_context_data(self, **attrs): + # Pass all kwargs as `attrs` + def get_template_data(self, args, kwargs, slots, context): return { - "attrs": attrs, + "attrs": kwargs, "classes": "text-red", "my_id": 123, } @@ -607,10 +607,11 @@ class MyComp(Component): """ - def get_context_data(self, date: Date, attrs: dict): + def get_template_data(self, args, kwargs, slots, context): + date = kwargs.pop("date") return { "date": date, - "attrs": attrs, + "attrs": kwargs, "class_from_var": "extra-class" } @@ -625,7 +626,7 @@ class Parent(Component): / %} """ - def get_context_data(self, date: Date): + def get_template_data(self, args, kwargs, slots, context): return { "date": datetime.now(), "json_data": json.dumps({"value": 456}) @@ -669,7 +670,7 @@ So all kwargs that start with `attrs:` will be collected into an `attrs` dict. attrs:@click="(e) => onClick(e, 'from_parent')" ``` -And `get_context_data` of `MyComp` will receive `attrs` input with following keys: +And `get_template_data` of `MyComp` will receive a kwarg named `attrs` with following keys: ```py attrs = { diff --git a/docs/concepts/fundamentals/html_js_css_variables.md b/docs/concepts/fundamentals/html_js_css_variables.md index af30fbc0..6b0da6fe 100644 --- a/docs/concepts/fundamentals/html_js_css_variables.md +++ b/docs/concepts/fundamentals/html_js_css_variables.md @@ -100,6 +100,44 @@ class ProfileCard(Component): } ``` +There is a slight difference between [`get_context_data()`](../../../reference/api/#django_components.Component.get_context_data) and [`get_template_data()`](../../../reference/api/#django_components.Component.get_template_data) +when rendering a component with the [`{% component %}`](../../../reference/template_tags/#component) tag. + +For example if you have component that accepts kwarg `date`: + +```py +class MyComponent(Component): + def get_context_data(self, date, *args, **kwargs): + return { + "date": date, + } + + def get_template_data(self, args, kwargs, slots, context): + return { + "date": kwargs["date"], + } +``` + +The difference is that: + +- With [`get_context_data()`](../../../reference/api/#django_components.Component.get_context_data), you can pass `date` either as arg or kwarg: + + ```django + ✅ + {% component "my_component" date=some_date %} + {% component "my_component" some_date %} + ``` + +- But with [`get_template_data()`](../../../reference/api/#django_components.Component.get_template_data), `date` MUST be passed as kwarg: + + ```django + ✅ + {% component "my_component" date=some_date %} + + ❌ + {% component "my_component" some_date %} + ``` + !!! warning [`get_template_data()`](../../../reference/api/#django_components.Component.get_template_data) diff --git a/docs/concepts/fundamentals/http_request.md b/docs/concepts/fundamentals/http_request.md index 39fc7dc0..c6d3847d 100644 --- a/docs/concepts/fundamentals/http_request.md +++ b/docs/concepts/fundamentals/http_request.md @@ -48,7 +48,7 @@ When the component has access to the `request` object, the request object will b ```python class MyComponent(Component): - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): return { 'user_id': self.request.GET['user_id'], } @@ -77,11 +77,11 @@ class MyComponent(Component): MyComponent.render(request=request) ``` -You can also access the context processors data from within [`get_context_data()`](../../../reference/api#django_components.Component.get_context_data) and other methods under [`Component.context_processors_data`](../../../reference/api#django_components.Component.context_processors_data). +You can also access the context processors data from within [`get_template_data()`](../../../reference/api#django_components.Component.get_template_data) and other methods under [`Component.context_processors_data`](../../../reference/api#django_components.Component.context_processors_data). ```python class MyComponent(Component): - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): csrf_token = self.context_processors_data['csrf_token'] return { 'csrf_token': csrf_token, diff --git a/docs/concepts/fundamentals/render_api.md b/docs/concepts/fundamentals/render_api.md index a8adc728..09dfcff1 100644 --- a/docs/concepts/fundamentals/render_api.md +++ b/docs/concepts/fundamentals/render_api.md @@ -20,7 +20,7 @@ Example: ```python class Table(Component): - def get_context_data(self, *args, **attrs): + def get_template_data(self, args, kwargs, slots, context): # Access component's ID assert self.id == "c1A2b3c" @@ -77,7 +77,7 @@ If you need to expand this limit, please open an issue on GitHub. ```python class Table(Component): - def get_context_data(self, *args, **attrs): + def get_template_data(self, args, kwargs, slots, context): # Access component's ID assert self.id == "c1A2b3c" @@ -102,7 +102,7 @@ to access the positional and keyword arguments passed to [`Component.render()`]( ```python class Table(Component): - def get_context_data(self, *args, **kwargs): + def get_template_data(self, args, kwargs, slots, context): # Access component's inputs, slots and context assert self.input.args == [123, "str"] assert self.input.kwargs == {"variable": "test", "another": 1} @@ -140,7 +140,7 @@ Read more about the request object and context processors in the [HTTP Request]( from django.http import HttpRequest class Table(Component): - def get_context_data(self, *args, **attrs): + def get_template_data(self, args, kwargs, slots, context): # Access the request object and Django's context processors assert self.request.GET == {"query": "something"} assert self.context_processors_data['user'].username == "admin" @@ -166,7 +166,7 @@ Read more about [Provide / Inject](../advanced/provide_inject.md). ```python class Table(Component): - def get_context_data(self, *args, **attrs): + def get_template_data(self, args, kwargs, slots, context): # Access provided data data = self.inject("some_data") assert data.some_data == "some_data" diff --git a/docs/concepts/fundamentals/single_file_components.md b/docs/concepts/fundamentals/single_file_components.md index 456bc49f..6f9b0765 100644 --- a/docs/concepts/fundamentals/single_file_components.md +++ b/docs/concepts/fundamentals/single_file_components.md @@ -30,9 +30,9 @@ from django_components import Component, register, types @register("calendar") class Calendar(Component): - def get_context_data(self, date): + def get_template_data(self, args, kwargs, slots, context): return { - "date": date, + "date": kwargs["date"], } template: types.django_html = """ @@ -114,9 +114,9 @@ from django_components import Component, register, types @register("calendar") class Calendar(Component): - def get_context_data(self, date): + def get_template_data(self, args, kwargs, slots, context): return { - "date": date, + "date": kwargs["date"], } template: types.django_html = """ @@ -155,9 +155,9 @@ from django_components import Component, register @register("calendar") class Calendar(Component): - def get_context_data(self, date): + def get_template_data(self, args, kwargs, slots, context): return { - "date": date, + "date": kwargs["date"], } # language=HTML diff --git a/docs/concepts/fundamentals/slots.md b/docs/concepts/fundamentals/slots.md index 9e7b7025..b1f7453c 100644 --- a/docs/concepts/fundamentals/slots.md +++ b/docs/concepts/fundamentals/slots.md @@ -165,8 +165,8 @@ like so: ```py class MyTable(Component): - def get_context_data(self, *args, **kwargs): - default_slot = self.input.slots["default"] + def get_template_data(self, args, kwargs, slots, context): + default_slot = slots["default"] return { "default_slot": default_slot, } @@ -475,8 +475,8 @@ class MyComp(Component): """ - def get_context_data(self, input): - processed_input = do_something(input) + def get_template_data(self, args, kwargs, slots, context): + processed_input = do_something(kwargs["input"]) return {"input": processed_input} ``` @@ -504,8 +504,8 @@ class MyComp(Component): """ - def get_context_data(self, input): - processed_input = do_something(input) + def get_template_data(self, args, kwargs, slots, context): + processed_input = do_something(kwargs["input"]) return { "input": processed_input, } @@ -646,9 +646,9 @@ You can dynamically pass all slots to a child component. This is similar to ```djc_py class MyTable(Component): - def get_context_data(self, *args, **kwargs): + def get_template_data(self, args, kwargs, slots, context): return { - "slots": self.input.slots, + "slots": slots, } template = """ diff --git a/docs/concepts/fundamentals/subclassing_components.md b/docs/concepts/fundamentals/subclassing_components.md index c1207577..4f8c1284 100644 --- a/docs/concepts/fundamentals/subclassing_components.md +++ b/docs/concepts/fundamentals/subclassing_components.md @@ -100,7 +100,7 @@ class BaseForm(Component): """ - def get_context_data(self, **kwargs): + def get_template_data(self, args, kwargs, slots, context): return { "form_content": self.get_form_content(), "submit_text": "Submit" @@ -112,8 +112,8 @@ class BaseForm(Component): class ContactForm(BaseForm): # Extend parent's "context" # but override "submit_text" - def get_context_data(self, **kwargs): - context = super().get_context_data(**kwargs) + def get_template_data(self, args, kwargs, slots, context): + context = super().get_template_data(args, kwargs, slots, context) context["submit_text"] = "Send Message" return context diff --git a/docs/concepts/fundamentals/template_tag_syntax.md b/docs/concepts/fundamentals/template_tag_syntax.md index 96b99f58..54f59697 100644 --- a/docs/concepts/fundamentals/template_tag_syntax.md +++ b/docs/concepts/fundamentals/template_tag_syntax.md @@ -30,14 +30,12 @@ so are still valid: ``` -These can then be accessed inside `get_context_data` so: +These can then be accessed inside `get_template_data` so: ```py @register("calendar") class Calendar(Component): - # Since # . @ - are not valid identifiers, we have to - # use `**kwargs` so the method can accept these args. - def get_context_data(self, **kwargs): + def get_template_data(self, args, kwargs, slots, context): return { "date": kwargs["my-date"], "id": kwargs["#some_id"], @@ -92,17 +90,17 @@ _New in version 0.93_ When passing data around, sometimes you may need to do light transformations, like negating booleans or filtering lists. Normally, what you would have to do is to define ALL the variables -inside `get_context_data()`. But this can get messy if your components contain a lot of logic. +inside `get_template_data()`. But this can get messy if your components contain a lot of logic. ```py @register("calendar") class Calendar(Component): - def get_context_data(self, id: str, editable: bool): + def get_template_data(self, args, kwargs, slots, context): return { - "editable": editable, - "readonly": not editable, - "input_id": f"input-{id}", - "icon_id": f"icon-{id}", + "editable": kwargs["editable"], + "readonly": not kwargs["editable"], + "input_id": f"input-{kwargs['id']}", + "icon_id": f"icon-{kwargs['id']}", ... } ``` @@ -200,10 +198,10 @@ class MyComp(Component): {% component "other" attrs=attrs / %} """ - def get_context_data(self, some_id: str): + def get_template_data(self, args, kwargs, slots, context): attrs = { "class": "pa-4 flex", - "data-some-id": some_id, + "data-some-id": kwargs["some_id"], "@click.stop": "onClickHandler", } return {"attrs": attrs} @@ -231,8 +229,8 @@ class MyComp(Component): / %} """ - def get_context_data(self, some_id: str): - return {"some_id": some_id} + def get_template_data(self, args, kwargs, slots, context): + return {"some_id": kwargs["some_id"]} ``` Sweet! Now all the relevant HTML is inside the template, and we can move it to a separate file with confidence: diff --git a/docs/getting_started/adding_js_and_css.md b/docs/getting_started/adding_js_and_css.md index 0b097935..d02b353a 100644 --- a/docs/getting_started/adding_js_and_css.md +++ b/docs/getting_started/adding_js_and_css.md @@ -184,7 +184,7 @@ class Calendar(Component): js_file = "calendar.js" # <--- new css_file = "calendar.css" # <--- new - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): return { "date": "1970-01-01", } @@ -256,7 +256,7 @@ class Calendar(Component): "https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css", # Tailwind ] - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): return { "date": "1970-01-01", } diff --git a/docs/getting_started/adding_slots.md b/docs/getting_started/adding_slots.md index 6447522c..91cb7c2a 100644 --- a/docs/getting_started/adding_slots.md +++ b/docs/getting_started/adding_slots.md @@ -158,7 +158,7 @@ the to `2024-12-14`, which is Saturday, our template from previous step would re The first instance rendered `2024-12-16`, while the rest rendered `2024-12-14`! -Why? Remember that in the [`get_context_data()`](../../reference/api#django_components.Component.get_context_data) +Why? Remember that in the [`get_template_data()`](../../reference/api#django_components.Component.get_template_data) method of our Calendar component, we pre-process the date. If the date falls on Saturday or Sunday, we shift it to next Monday: ```python title="[project root]/components/calendar/calendar.py" @@ -174,11 +174,11 @@ def to_workweek_date(d: date): class Calendar(Component): template_file = "calendar.html" ... - def get_context_data(self, date: date, extra_class: str | None = None): - workweek_date = to_workweek_date(date) + def get_template_data(self, args, kwargs, slots, context): + workweek_date = to_workweek_date(kwargs["date"]) return { "date": workweek_date, - "extra_class": extra_class, + "extra_class": kwargs.get("extra_class", "text-blue"), } ``` @@ -284,7 +284,7 @@ each time: Generally, slots are more flexible - you can access the slot data, even the original slot content. Thus, slots behave more like functions that render content based on their context. - On the other hand, variables are static - the variable you pass to a component is what will be used. + On the other hand, variables are simpler - the variable you pass to a component is what will be used. Moreover, slots are treated as part of the template - for example the CSS scoping (work in progress) is applied to the slot content too. diff --git a/docs/getting_started/components_in_templates.md b/docs/getting_started/components_in_templates.md index f630849a..627ac7b5 100644 --- a/docs/getting_started/components_in_templates.md +++ b/docs/getting_started/components_in_templates.md @@ -30,7 +30,7 @@ class Calendar(Component): js_file = "calendar.js" css_file = "calendar.css" - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): return { "date": "1970-01-01", } diff --git a/docs/getting_started/parametrising_components.md b/docs/getting_started/parametrising_components.md index 5b787f3d..653c7856 100644 --- a/docs/getting_started/parametrising_components.md +++ b/docs/getting_started/parametrising_components.md @@ -10,7 +10,7 @@ What we want is to be able to use the Calendar component within the template lik ### 1. Understading component inputs In section [Create your first component](../your_first_component), we defined -the [`get_context_data()`](../../reference/api#django_components.Component.get_context_data) method +the [`get_template_data()`](../../reference/api#django_components.Component.get_template_data) method that defines what variables will be available within the template: ```python title="[project root]/components/calendar/calendar.py" @@ -20,13 +20,13 @@ from django_components import Component, register class Calendar(Component): template_file = "calendar.html" ... - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): return { "date": "1970-01-01", } ``` -What we didn't say is that [`get_context_data()`](../../reference/api#django_components.Component.get_context_data) +What we didn't say is that [`get_template_data()`](../../reference/api#django_components.Component.get_template_data) actually receives the args and kwargs that were passed to a component. So if we call a component with a `date` and `extra_class` keywords: @@ -38,7 +38,10 @@ So if we call a component with a `date` and `extra_class` keywords: This is the same as calling: ```py -Calendar.get_context_data(date="2024-12-13", extra_class="text-red") +Calendar.get_template_data( + args=[], + kwargs={"date": "2024-12-13", "extra_class": "text-red"}, +) ``` And same applies to positional arguments, or mixing args and kwargs, where: @@ -50,13 +53,16 @@ And same applies to positional arguments, or mixing args and kwargs, where: is same as ```py -Calendar.get_context_data("2024-12-13", extra_class="text-red") +Calendar.get_template_data( + args=["2024-12-13"], + kwargs={"extra_class": "text-red"}, +) ``` -### 2. Define inputs for `get_context_data` +### 2. Define inputs Let's put this to test. We want to pass `date` and `extra_class` kwargs to the component. -And so, we can write the [`get_context_data()`](../../reference/api#django_components.Component.get_context_data) +And so, we can write the [`get_template_data()`](../../reference/api#django_components.Component.get_template_data) method such that it expects those parameters: ```python title="[project root]/components/calendar/calendar.py" @@ -68,46 +74,40 @@ from django_components import Component, register class Calendar(Component): template_file = "calendar.html" ... - def get_context_data(self, date: date, extra_class: str = "text-blue"): + def get_template_data(self, args, kwargs, slots, context): return { - "date": date, - "extra_class": extra_class, + "date": kwargs["date"], + "extra_class": kwargs.get("extra_class", "text-blue"), } ``` -!!! info - - Since [`get_context_data()`](../../reference/api#django_components.Component.get_context_data) - is just a regular Python function, type hints annotations work the same way as anywhere else. - -!!! warning - - Since [`get_context_data()`](../../reference/api#django_components.Component.get_context_data) - is just a regular Python function, it will raise TypeError if it receives incorrect parameters. - Since `extra_class` is optional in the function signature, it's optional also in the template. So both following calls are valid: ```htmldjango -{% component "calendar" "2024-12-13" / %} -{% component "calendar" "2024-12-13" extra_class="text-red" / %} +{% component "calendar" date="2024-12-13" / %} +{% component "calendar" date="2024-12-13" extra_class="text-red" / %} ``` -However, `date` is required. Thus we MUST provide it. Same with regular Python functions, -`date` can be set either as positional or keyword argument. But either way it MUST be set: +!!! warning -```htmldjango -✅ -{% component "calendar" "2024-12-13" / %} -{% component "calendar" extra_class="text-red" date="2024-12-13" / %} + [`get_template_data()`](../../reference/api#django_components.Component.get_template_data) + differentiates between positional and keyword arguments, + so you have to make sure to pass the arguments correctly. -❌ -{% component "calendar" extra_class="text-red" / %} -``` + Since `date` is expected to be a keyword argument, it MUST be provided as such: -### 3. Process inputs in `get_context_data` + ```htmldjango + ✅ `date` is kwarg + {% component "calendar" date="2024-12-13" / %} -The [`get_context_data()`](../../reference/api#django_components.Component.get_context_data) + ❌ `date` is arg + {% component "calendar" "2024-12-13" / %} + ``` + +### 3. Process inputs + +The [`get_template_data()`](../../reference/api#django_components.Component.get_template_data) method is powerful, because it allows us to decouple component inputs from the template variables. In other words, we can pre-process the component inputs, and massage them into a shape that's most appropriate for @@ -160,12 +160,14 @@ cities_by_pop = [ ] ``` -Without the `get_context_data()` method, we'd have to either: +Without the [`get_template_data()`](../../reference/api#django_components.Component.get_template_data) method, +we'd have to either: 1. Pre-process the data in Python before passing it to the components. 2. Define a Django filter or template tag to take the data and process it on the spot. -Instead, with `get_context_data()`, we can keep this transformation private to this component, +Instead, with [`get_template_data()`](../../reference/api#django_components.Component.get_template_data), +we can keep this transformation private to this component, and keep the rest of the codebase clean. ```py @@ -176,13 +178,14 @@ def group_by_pop(data): class PopulationTable(Component): template_file = "population_table.html" - def get_context_data(self, data): + def get_template_data(self, args, kwargs, slots, context): return { - "data": group_by_pop(data), + "data": group_by_pop(kwargs["data"]), } ``` -Similarly we can make use of `get_context_data()` to pre-process the date that was given to the component: +Similarly we can make use of [`get_template_data()`](../../reference/api#django_components.Component.get_template_data) +to pre-process the date that was given to the component: ```python title="[project root]/components/calendar/calendar.py" from datetime import date @@ -197,17 +200,17 @@ def to_workweek_date(d: date): class Calendar(Component): template_file = "calendar.html" ... - def get_context_data(self, date: date, extra_class: str = "text-blue"): - workweek_date = to_workweek_date(date) # <--- new + def get_template_data(self, args, kwargs, slots, context): + workweek_date = to_workweek_date(kwargs["date"]) # <--- new return { "date": workweek_date, # <--- changed - "extra_class": extra_class, + "extra_class": kwargs.get("extra_class", "text-blue"), } ``` ### 4. Pass inputs to components -Once we're happy with `Calendar.get_contex_data()`, we can update our templates to use +Once we're happy with `Calendar.get_template_data()`, we can update our templates to use the parametrized version of the component: ```htmldjango @@ -224,7 +227,7 @@ Next, you will learn [how to use slots give your components even more flexibilit ### 5. Add defaults In our example, we've set the `extra_class` to default to `"text-blue"` by setting it in the -[`get_context_data()`](../../reference/api#django_components.Component.get_context_data) +[`get_template_data()`](../../reference/api#django_components.Component.get_template_data) method. However, you may want to use the same default value in multiple methods, like @@ -248,10 +251,10 @@ class Calendar(Component): class Defaults: # <--- new extra_class = "text-blue" - def get_context_data(self, date: date, extra_class: str): # <--- changed - workweek_date = to_workweek_date(date) + def get_template_data(self, args, kwargs, slots, context): + workweek_date = to_workweek_date(kwargs["date"]) return { "date": workweek_date, - "extra_class": extra_class, + "extra_class": kwargs["extra_class"], # <--- changed } ``` diff --git a/docs/getting_started/rendering_components.md b/docs/getting_started/rendering_components.md index d4a2444f..da480a59 100644 --- a/docs/getting_started/rendering_components.md +++ b/docs/getting_started/rendering_components.md @@ -19,7 +19,7 @@ class Calendar(Component): js_file = "calendar.js" css_file = "calendar.css" - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): return { "date": "1970-01-01", } diff --git a/docs/getting_started/your_first_component.md b/docs/getting_started/your_first_component.md index 85df4743..21b403af 100644 --- a/docs/getting_started/your_first_component.md +++ b/docs/getting_started/your_first_component.md @@ -104,7 +104,7 @@ Inside `calendar.html`, write: ``` In this example we've defined one template variable `date`. You can use any and as many variables as you like. These variables will be -defined in the Python file in [`get_context_data()`](../../reference/api#django_components.Component.get_context_data) +defined in the Python file in [`get_template_data()`](../../reference/api#django_components.Component.get_template_data) when creating an instance of this component. !!! note @@ -142,7 +142,7 @@ class Calendar(Component): In `calendar.html`, we've used the variable `date`. So we need to define it for the template to work. -This is done using [`Component.get_context_data()`](../../reference/api#django_components.Component.get_context_data). +This is done using [`Component.get_template_data()`](../../reference/api#django_components.Component.get_template_data). It's a function that returns a dictionary. The entries in this dictionary will become available within the template as variables, e.g. as `{{ date }}`. @@ -152,7 +152,7 @@ from django_components import Component class Calendar(Component): template_file = "calendar.html" - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): return { "date": "1970-01-01", } diff --git a/docs/guides/devguides/slot_rendering.md b/docs/guides/devguides/slot_rendering.md index 38c27f9d..5d5ef3f3 100644 --- a/docs/guides/devguides/slot_rendering.md +++ b/docs/guides/devguides/slot_rendering.md @@ -246,6 +246,6 @@ Instead, our solution is closer to [how Vue handles slots](https://vuejs.org/gui While we do not wrap the logic in a function, we do PREPARE IN ADVANCE: 1. The content that should be rendered for each slot -2. The context variables from `get_context_data()` +2. The context variables from `get_template_data()` Thus, once we reach the `{% slot %}` node, in it's `render()` method, we access the data above, and, depending on the `context_behavior` setting, include the current context or not. For more info, see `SlotNode.render()`. diff --git a/docs/overview/welcome.md b/docs/overview/welcome.md index 97ff2ee5..95b6d6a0 100644 --- a/docs/overview/welcome.md +++ b/docs/overview/welcome.md @@ -53,8 +53,8 @@ class Calendar(Component): js_file = "calendar.js" css_file = "calendar.css" - def get_context_data(self, date): - return {"date": date} + def get_template_data(self, args, kwargs, slots, context): + return {"date": kwargs["date"]} ``` Use the component like this: @@ -115,9 +115,9 @@ class Calendar(Component): css = ["bootstrap/dist/css/bootstrap.min.css"] # Variables available in the template - def get_context_data(self, date): + def get_template_data(self, args, kwargs, slots, context): return { - "date": date + "date": kwargs["date"] } ``` @@ -222,7 +222,7 @@ class Table(Component): """ - def get_context_data(self, var1, var2, variable, another, **attrs): + def get_template_data(self, args, kwargs, slots, context): # Access component's ID assert self.id == "djc1A2b3c" @@ -237,7 +237,7 @@ class Table(Component): assert self.context_processors_data['user'].username == "admin" return { - "variable": variable, + "variable": kwargs["variable"], } # Access component's HTML / JS / CSS @@ -337,9 +337,9 @@ class Calendar(Component): }, ) - def get_context_data(self, page): + def get_template_data(self, args, kwargs, slots, context): return { - "page": page, + "page": kwargs["page"], } # Get auto-generated URL for the component @@ -371,7 +371,7 @@ Read more about [Provide / Inject](https://django-components.github.io/django-co class Header(Component): template = "..." - def get_context_data(self, *args, **kwargs): + def get_template_data(self, args, kwargs, slots, context): theme = self.inject("theme").variant return { "theme": theme, diff --git a/docs/reference/template_tags.md b/docs/reference/template_tags.md index 9d50e16d..669a8936 100644 --- a/docs/reference/template_tags.md +++ b/docs/reference/template_tags.md @@ -67,7 +67,7 @@ If you insert this tag multiple times, ALL JS scripts will be duplicately insert -See source code +See source code @@ -363,9 +363,9 @@ class Parent(Component): """ - def get_context_data(self, user: User): + def get_template_data(self, args, kwargs, slots, context): return { - "user": user, + "user": kwargs["user"], } ``` @@ -381,7 +381,7 @@ class Child(Component): """ - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): user = self.inject("user_data").user return { "user": user, diff --git a/sampleproject/components/calendar/calendar.py b/sampleproject/components/calendar/calendar.py index 49f01096..425a5916 100644 --- a/sampleproject/components/calendar/calendar.py +++ b/sampleproject/components/calendar/calendar.py @@ -1,3 +1,5 @@ +from typing import NamedTuple + from django_components import Component, register @@ -13,9 +15,12 @@ class Calendar(Component): js_file = "calendar/calendar.js" # This component takes one parameter, a date string to show in the template - def get_context_data(self, date): + class Kwargs(NamedTuple): + date: str + + def get_template_data(self, args, kwargs: Kwargs, slots, context): return { - "date": date, + "date": kwargs.date, } class View: @@ -41,9 +46,12 @@ class CalendarRelative(Component): js_file = "calendar.js" # This component takes one parameter, a date string to show in the template - def get_context_data(self, date): + class Kwargs(NamedTuple): + date: str + + def get_template_data(self, args, kwargs: Kwargs, slots, context): return { - "date": date, + "date": kwargs.date, } class View: diff --git a/sampleproject/components/greeting.py b/sampleproject/components/greeting.py index e9801472..6543f25a 100644 --- a/sampleproject/components/greeting.py +++ b/sampleproject/components/greeting.py @@ -1,24 +1,8 @@ -from typing import Any, Dict - from django_components import Component, register, types @register("greeting") class Greeting(Component): - class View: - def get(self, request, *args, **kwargs): - slots = {"message": "Hello, world!"} - return Greeting.render_to_response( - request=request, - slots=slots, - kwargs={ - "name": request.GET.get("name", ""), - }, - ) - - def get_context_data(self, name, *args, **kwargs) -> Dict[str, Any]: - return {"name": name} - template: types.django_html = """
Hello, {{ name }}!
{% slot "message" %}{% endslot %} @@ -37,3 +21,17 @@ class Greeting(Component): alert("Hello!"); }); """ + + def get_template_data(self, args, kwargs, slots, context): + return {"name": kwargs["name"]} + + class View: + def get(self, request, *args, **kwargs): + slots = {"message": "Hello, world!"} + return Greeting.render_to_response( + request=request, + slots=slots, + kwargs={ + "name": request.GET.get("name", ""), + }, + ) diff --git a/sampleproject/components/nested/calendar/calendar.py b/sampleproject/components/nested/calendar/calendar.py index f8e7dbc4..4bc8b412 100644 --- a/sampleproject/components/nested/calendar/calendar.py +++ b/sampleproject/components/nested/calendar/calendar.py @@ -1,3 +1,5 @@ +from typing import NamedTuple + from django_components import Component, register @@ -13,9 +15,12 @@ class CalendarNested(Component): js_file = "calendar.js" # This component takes one parameter, a date string to show in the template - def get_context_data(self, date): + class Kwargs(NamedTuple): + date: str + + def get_template_data(self, args, kwargs: Kwargs, slots, context): return { - "date": date, + "date": kwargs.date, } class View: diff --git a/sampleproject/components/recursive.py b/sampleproject/components/recursive.py index be5d6f97..80bd4a10 100644 --- a/sampleproject/components/recursive.py +++ b/sampleproject/components/recursive.py @@ -1,27 +1,11 @@ import time -from typing import Any, Dict +from typing import NamedTuple from django_components import Component, register, types @register("recursive") class Recursive(Component): - class View: - def get(self, request): - time_before = time.time() - output = Recursive.render_to_response( - request=request, - kwargs={ - "depth": 0, - }, - ) - time_after = time.time() - print("TIME: ", time_after - time_before) - return output - - def get_context_data(self, depth: int = 0) -> Dict[str, Any]: - return {"depth": depth + 1} - template: types.django_html = """
depth: {{ depth }} @@ -31,3 +15,25 @@ class Recursive(Component): {% endif %}
""" + + class Kwargs(NamedTuple): + depth: int + + class Defaults: + depth = 0 + + def get_template_data(self, args, kwargs: Kwargs, slots, context): + return {"depth": kwargs.depth + 1} + + class View: + def get(self, request): + time_before = time.time() + output = Recursive.render_to_response( + request=request, + kwargs=Recursive.Kwargs( + depth=0, + ), + ) + time_after = time.time() + print("TIME: ", time_after - time_before) + return output diff --git a/src/django_components/app_settings.py b/src/django_components/app_settings.py index b03686a9..0c7720fe 100644 --- a/src/django_components/app_settings.py +++ b/src/django_components/app_settings.py @@ -56,7 +56,7 @@ class ContextBehavior(str, Enum): That is, they enrich the context, and pass it along. 1. Component fills use the context of the component they are within. - 2. Variables from [`Component.get_context_data()`](../api#django_components.Component.get_context_data) + 2. Variables from [`Component.get_template_data()`](../api#django_components.Component.get_template_data) are available to the component fill. **Example:** @@ -71,7 +71,7 @@ class ContextBehavior(str, Enum): {% endwith %} ``` - and this context returned from the `Component.get_context_data()` method + and this context returned from the `Component.get_template_data()` method ```python { "my_var": 123 } ``` @@ -98,7 +98,7 @@ class ContextBehavior(str, Enum): """ This setting makes the component fills behave similar to Vue or React, where the fills use EXCLUSIVELY the context variables defined in - [`Component.get_context_data()`](../api#django_components.Component.get_context_data). + [`Component.get_template_data()`](../api#django_components.Component.get_template_data). **Example:** @@ -112,7 +112,7 @@ class ContextBehavior(str, Enum): {% endwith %} ``` - and this context returned from the `get_context_data()` method + and this context returned from the `get_template_data()` method ```python { "my_var": 123 } ``` diff --git a/src/django_components/commands/create.py b/src/django_components/commands/create.py index 77988514..cc83a8e2 100644 --- a/src/django_components/commands/create.py +++ b/src/django_components/commands/create.py @@ -199,16 +199,20 @@ class CreateCommand(ComponentCommand): @register("{name}") class {name.capitalize()}(Component): - template_file = "{name}/{template_filename}" + template_file = "{template_filename}" + js_file = "{js_filename}" + css_file = "{css_filename}" - def get_context_data(self, value): + class Kwargs(NamedTuple): + param: str + + class Defaults: + param = "sample value" + + def get_template_data(self, args, kwargs: Kwargs, slots, context): return {{ - "param": "sample value", + "param": kwargs.param, }} - - class Media: - css = "{name}/{css_filename}" - js = "{name}/{js_filename}" """ ) f.write(py_content.strip()) diff --git a/src/django_components/component.py b/src/django_components/component.py index cb4f4489..0d8751c5 100644 --- a/src/django_components/component.py +++ b/src/django_components/component.py @@ -231,9 +231,9 @@ class ComponentVars(NamedTuple): ```py class MyTable(Component): - def get_context_data(self, *args, **kwargs): + def get_template_data(self, args, kwargs, slots, context): return { - "my_slot_filled": "my_slot" in self.input.slots + "my_slot_filled": "my_slot" in slots } ``` """ @@ -508,7 +508,7 @@ class Component(metaclass=ComponentMeta): class MyComponent(Component): template_file = "path/to/template.html" - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): return {"name": "World"} ``` """ @@ -556,7 +556,7 @@ class Component(metaclass=ComponentMeta): class MyComponent(Component): template = "Hello, {{ name }}!" - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): return {"name": "World"} ``` """ @@ -1663,7 +1663,7 @@ class Component(metaclass=ComponentMeta): ```py class MyComponent(Component): - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): print(f"Rendering '{self.id}'") return {} @@ -1702,14 +1702,9 @@ class Component(metaclass=ComponentMeta): **Example:** - Use can use [`self.input.args`](../api/#django_components.ComponentInput.args) - and [`self.input.kwargs`](../api/#django_components.ComponentInput.kwargs) - to access the positional and keyword arguments passed to - [`Component.render()`](../api/#django_components.Component.render). - ```python class Table(Component): - def get_context_data(self, *args, **kwargs): + def get_template_data(self, args, kwargs, slots, context): # Access component's inputs, slots and context assert self.input.args == [123, "str"] assert self.input.kwargs == {"variable": "test", "another": 1} @@ -1778,7 +1773,7 @@ class Component(metaclass=ComponentMeta): ```py class MyComponent(Component): - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): user_id = self.request.GET['user_id'] return { 'user_id': user_id, @@ -1801,7 +1796,7 @@ class Component(metaclass=ComponentMeta): This data is also available from within the component's template, without having to return this data from - [`get_context_data()`](../api#django_components.Component.get_context_data). + [`get_template_data()`](../api#django_components.Component.get_template_data). In regular Django templates, you need to use [`RequestContext`](https://docs.djangoproject.com/en/5.1/ref/templates/api/#django.template.RequestContext) @@ -1831,7 +1826,7 @@ class Component(metaclass=ComponentMeta): ```py class MyComponent(Component): - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): user = self.context_processors_data['user'] return { 'is_logged_in': user.is_authenticated, @@ -2371,7 +2366,7 @@ class Component(metaclass=ComponentMeta): # By adding the current input to the stack, we temporarily allow users # to access the provided context, slots, etc. Also required so users can - # call `self.inject()` from within `get_context_data()`. + # call `self.inject()` from within `get_template_data()`. # # This is handled as a stack, as users can potentially call `component.render()` # from within component hooks. Thus, then they do so, `component.id` will be the ID diff --git a/src/django_components/component_media.py b/src/django_components/component_media.py index 0bf26cae..9bc60e37 100644 --- a/src/django_components/component_media.py +++ b/src/django_components/component_media.py @@ -539,7 +539,7 @@ def _resolve_media(comp_cls: Type["Component"], comp_media: ComponentMedia) -> N class MyComponent(Component): media_class = MyMedia - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): assert isinstance(self.media, MyMedia) ``` """ diff --git a/src/django_components/components/dynamic.py b/src/django_components/components/dynamic.py index 68cf6696..8244a1f0 100644 --- a/src/django_components/components/dynamic.py +++ b/src/django_components/components/dynamic.py @@ -99,13 +99,14 @@ class DynamicComponent(Component): _is_dynamic_component = True - def get_context_data( + def get_template_data( self, - *args: Any, - registry: Optional[ComponentRegistry] = None, - **kwargs: Any, + args: Any, + kwargs: Any, + slots: Any, + context: Any, ) -> Dict: - # NOTE: We have to access `is` via kwargs, because it's a special keyword in Python + registry: Optional[ComponentRegistry] = kwargs.pop("registry", None) comp_name_or_class: Union[str, Type[Component]] = kwargs.pop("is", None) if not comp_name_or_class: raise TypeError(f"Component '{self.name}' is missing a required argument 'is'") diff --git a/src/django_components/extension.py b/src/django_components/extension.py index 0ccf06c8..7378b0f2 100644 --- a/src/django_components/extension.py +++ b/src/django_components/extension.py @@ -172,7 +172,7 @@ class ComponentExtension: class MyExtension: ... - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): return { "my_extension": self.my_extension.do_something(), } @@ -212,7 +212,7 @@ class ComponentExtension: class MyExtension: ... - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): return { "my_extension": self.my_extension.do_something(), } @@ -450,7 +450,7 @@ class ComponentExtension: Use this hook to modify or validate component inputs before they're processed. This is the first hook that is called when rendering a component. As such this hook is called before - [`Component.get_context_data()`](../api#django_components.Component.get_context_data), + [`Component.get_template_data()`](../api#django_components.Component.get_template_data), [`Component.get_js_data()`](../api#django_components.Component.get_js_data), and [`Component.get_css_data()`](../api#django_components.Component.get_css_data) methods, and the @@ -482,7 +482,7 @@ class ComponentExtension: after a component's context and data methods have been processed. This hook is called after - [`Component.get_context_data()`](../api#django_components.Component.get_context_data), + [`Component.get_template_data()`](../api#django_components.Component.get_template_data), [`Component.get_js_data()`](../api#django_components.Component.get_js_data) and [`Component.get_css_data()`](../api#django_components.Component.get_css_data). @@ -498,7 +498,7 @@ class ComponentExtension: class MyExtension(ComponentExtension): def on_component_data(self, ctx: OnComponentDataContext) -> None: # Add extra template variable to all components when they are rendered - ctx.context_data["my_template_var"] = "my_value" + ctx.template_data["my_template_var"] = "my_value" ``` """ pass diff --git a/src/django_components/node.py b/src/django_components/node.py index 71f545db..eb69d1c9 100644 --- a/src/django_components/node.py +++ b/src/django_components/node.py @@ -100,9 +100,9 @@ class NodeMeta(type): # # ```py # class MyComponent(Component): - # def get_context_data(self, name: str, **kwargs: Any) -> str: + # def get_template_data(self, args, kwargs, slots, context) -> str: # return { - # "name": name, + # "name": kwargs.pop("name"), # "attrs": kwargs, # } # template = """ diff --git a/src/django_components/provide.py b/src/django_components/provide.py index 55b0f1b3..e1976d59 100644 --- a/src/django_components/provide.py +++ b/src/django_components/provide.py @@ -41,9 +41,9 @@ class ProvideNode(BaseNode): \"\"\" - def get_context_data(self, user: User): + def get_template_data(self, args, kwargs, slots, context): return { - "user": user, + "user": kwargs["user"], } ``` @@ -59,7 +59,7 @@ class ProvideNode(BaseNode): \"\"\" - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): user = self.inject("user_data").user return { "user": user, @@ -138,7 +138,7 @@ def set_provided_context_var( ) -> str: """ 'Provide' given data under given key. In other words, this data can be retrieved - using `self.inject(key)` inside of `get_context_data()` method of components that + using `self.inject(key)` inside of `get_template_data()` method of components that are nested inside the `{% provide %}` tag. """ # NOTE: We raise TemplateSyntaxError since this func should be called only from diff --git a/src/django_components/slots.py b/src/django_components/slots.py index 6349ffba..33ad1594 100644 --- a/src/django_components/slots.py +++ b/src/django_components/slots.py @@ -1083,8 +1083,8 @@ def _nodelist_to_slot_render_func( # # And so we want to put the `extra_context` into the same layer that contains `_COMPONENT_CONTEXT_KEY`. # - # HOWEVER, the layer with `_COMPONENT_CONTEXT_KEY` also contains user-defined data from `get_context_data()`. - # Data from `get_context_data()` should take precedence over `extra_context`. So we have to insert + # HOWEVER, the layer with `_COMPONENT_CONTEXT_KEY` also contains user-defined data from `get_template_data()`. + # Data from `get_template_data()` should take precedence over `extra_context`. So we have to insert # the forloop variables BEFORE that. index_of_last_component_layer = get_last_index(ctx.dicts, lambda d: _COMPONENT_CONTEXT_KEY in d) if index_of_last_component_layer is None: @@ -1096,8 +1096,8 @@ def _nodelist_to_slot_render_func( # the following line can be removed. index_of_last_component_layer -= 1 - # Insert the `extra_context` layer BEFORE the layer that defines the variables from get_context_data. - # Thus, get_context_data will overshadow these on conflict. + # Insert the `extra_context` layer BEFORE the layer that defines the variables from get_template_data. + # Thus, get_template_data will overshadow these on conflict. ctx.dicts.insert(index_of_last_component_layer, extra_context or {}) trace_component_msg("RENDER_NODELIST", component_name, component_id=None, slot_name=slot_name) diff --git a/tests/components/multi_file/multi_file.py b/tests/components/multi_file/multi_file.py index 2592b4ce..167d6cec 100644 --- a/tests/components/multi_file/multi_file.py +++ b/tests/components/multi_file/multi_file.py @@ -23,5 +23,5 @@ class MultFileComponent(Component): kwargs={"variable": "GET"}, ) - def get_context_data(self, variable, *args, **kwargs) -> Dict[str, Any]: - return {"variable": variable} + def get_template_data(self, args, kwargs, slots, context) -> Dict[str, Any]: + return {"variable": kwargs["variable"]} diff --git a/tests/components/relative_file/relative_file.py b/tests/components/relative_file/relative_file.py index b7e21abf..429827ac 100644 --- a/tests/components/relative_file/relative_file.py +++ b/tests/components/relative_file/relative_file.py @@ -27,5 +27,5 @@ class RelativeFileComponent(Component): kwargs={"variable": "GET"}, ) - def get_context_data(self, variable, *args, **kwargs) -> Dict[str, Any]: - return {"variable": variable} + def get_template_data(self, args, kwargs, slots, context) -> Dict[str, Any]: + return {"variable": kwargs["variable"]} diff --git a/tests/components/relative_file_pathobj/relative_file_pathobj.py b/tests/components/relative_file_pathobj/relative_file_pathobj.py index c81e7b8c..2d49eba4 100644 --- a/tests/components/relative_file_pathobj/relative_file_pathobj.py +++ b/tests/components/relative_file_pathobj/relative_file_pathobj.py @@ -32,5 +32,5 @@ class RelativeFileWithPathObjComponent(Component): js = PathObj("relative_file_pathobj.js") css = PathObj("relative_file_pathobj.css") - def get_context_data(self, variable, *args, **kwargs) -> Dict[str, Any]: - return {"variable": variable} + def get_template_data(self, args, kwargs, slots, context) -> Dict[str, Any]: + return {"variable": kwargs["variable"]} diff --git a/tests/components/single_file.py b/tests/components/single_file.py index d0cef7e7..e71f30d9 100644 --- a/tests/components/single_file.py +++ b/tests/components/single_file.py @@ -29,5 +29,5 @@ class SingleFileComponent(Component): kwargs={"variable": "GET"}, ) - def get_context_data(self, variable, *args, **kwargs) -> Dict[str, Any]: - return {"variable": variable} + def get_template_data(self, args, kwargs, slots, context) -> Dict[str, Any]: + return {"variable": kwargs["variable"]} diff --git a/tests/components/staticfiles/staticfiles.py b/tests/components/staticfiles/staticfiles.py index 50e9c746..ba4f07fa 100644 --- a/tests/components/staticfiles/staticfiles.py +++ b/tests/components/staticfiles/staticfiles.py @@ -12,5 +12,5 @@ class RelativeFileWithPathObjComponent(Component): js = "staticfiles.js" css = "staticfiles.css" - def get_context_data(self, variable, *args, **kwargs) -> Dict[str, Any]: - return {"variable": variable} + def get_template_data(self, args, kwargs, slots, context) -> Dict[str, Any]: + return {"variable": kwargs["variable"]} diff --git a/tests/e2e/testserver/testserver/components/__init__.py b/tests/e2e/testserver/testserver/components/__init__.py index 7b60804e..b44a7170 100644 --- a/tests/e2e/testserver/testserver/components/__init__.py +++ b/tests/e2e/testserver/testserver/components/__init__.py @@ -17,10 +17,13 @@ class SimpleComponent(Component): globalThis.testSimpleComponent = 'kapowww!' """ - def get_context_data(self, variable, variable2="default"): + class Defaults: + variable2 = "default" + + def get_template_data(self, args, kwargs, slots, context): return { - "variable": variable, - "variable2": variable2, + "variable": kwargs["variable"], + "variable2": kwargs["variable2"], } class Media: @@ -48,8 +51,8 @@ class SimpleComponentNested(Component): globalThis.testSimpleComponentNested = 'bongo!' """ - def get_context_data(self, variable): - return {"variable": variable} + def get_template_data(self, args, kwargs, slots, context): + return {"variable": kwargs["variable"]} class Media: css = ["style.css", "style2.css"] @@ -72,8 +75,8 @@ class OtherComponent(Component): globalThis.testOtherComponent = 'wowzee!' """ - def get_context_data(self, variable): - return {"variable": variable} + def get_template_data(self, args, kwargs, slots, context): + return {"variable": kwargs["variable"]} class Media: css = "style.css" diff --git a/tests/test_app/components/app_lvl_comp/app_lvl_comp.py b/tests/test_app/components/app_lvl_comp/app_lvl_comp.py index e4c0af7f..9a94c0b2 100644 --- a/tests/test_app/components/app_lvl_comp/app_lvl_comp.py +++ b/tests/test_app/components/app_lvl_comp/app_lvl_comp.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, Optional +from typing import Optional from django_components import Component, register @@ -14,5 +14,5 @@ class AppLvlCompComponent(Component): js = "app_lvl_comp.js" css = "app_lvl_comp.css" - def get_context_data(self, variable, *args, **kwargs) -> Dict[str, Any]: - return {"variable": variable} + def get_template_data(self, args, kwargs, slots, context): + return {"variable": kwargs["variable"]} diff --git a/tests/test_app/custom_comps_dir/app_lvl_comp/app_lvl_comp.py b/tests/test_app/custom_comps_dir/app_lvl_comp/app_lvl_comp.py index 89d5b526..57b90aa8 100644 --- a/tests/test_app/custom_comps_dir/app_lvl_comp/app_lvl_comp.py +++ b/tests/test_app/custom_comps_dir/app_lvl_comp/app_lvl_comp.py @@ -1,5 +1,3 @@ -from typing import Any, Dict - from django_components import Component, register @@ -12,5 +10,5 @@ class AppLvlCompComponent(Component): js = "app_lvl_comp.js" css = "app_lvl_comp.css" - def get_context_data(self, variable, *args, **kwargs) -> Dict[str, Any]: - return {"variable": variable} + def get_template_data(self, args, kwargs, slots, context): + return {"variable": kwargs["variable"]} diff --git a/tests/test_app_nested/app/components/app_lvl_comp.py b/tests/test_app_nested/app/components/app_lvl_comp.py index f8426587..36c2aaaa 100644 --- a/tests/test_app_nested/app/components/app_lvl_comp.py +++ b/tests/test_app_nested/app/components/app_lvl_comp.py @@ -1,5 +1,3 @@ -from typing import Any, Dict - from django_components import Component, register @@ -10,5 +8,5 @@ class AppLvlCompComponent(Component): {{ variable }} """ - def get_context_data(self, variable, *args, **kwargs) -> Dict[str, Any]: - return {"variable": variable} + def get_template_data(self, args, kwargs, slots, context): + return {"variable": kwargs["variable"]} diff --git a/tests/test_attributes.py b/tests/test_attributes.py index 9015b70c..61c5e6cb 100644 --- a/tests/test_attributes.py +++ b/tests/test_attributes.py @@ -144,9 +144,9 @@ class TestHtmlAttrs: """ # noqa: E501 - def get_context_data(self, *args, attrs): + def get_template_data(self, args, kwargs, slots, context): return { - "attrs": attrs, + "attrs": kwargs["attrs"], "defaults": {"class": "override-me"}, } @@ -172,9 +172,9 @@ class TestHtmlAttrs: """ # noqa: E501 - def get_context_data(self, *args, attrs): + def get_template_data(self, args, kwargs, slots, context): return { - "attrs": attrs, + "attrs": kwargs["attrs"], "defaults": {"class": "override-me"}, "class": "123 457", } @@ -197,9 +197,9 @@ class TestHtmlAttrs: """ # noqa: E501 - def get_context_data(self, *args, attrs): + def get_template_data(self, args, kwargs, slots, context): return { - "attrs": attrs, + "attrs": kwargs["attrs"], "defaults": {"class": "override-me"}, } @@ -225,9 +225,9 @@ class TestHtmlAttrs: """ # noqa: E501 - def get_context_data(self, *args, attrs): + def get_template_data(self, args, kwargs, slots, context): return { - "attrs": attrs, + "attrs": kwargs["attrs"], "defaults": {"class": "override-me"}, } @@ -253,10 +253,10 @@ class TestHtmlAttrs: """ # noqa: E501 - def get_context_data(self, *args, attrs): + def get_template_data(self, args, kwargs, slots, context): return { "props": { - "attrs": attrs, + "attrs": kwargs["attrs"], "defaults": {"class": "override-me"}, "class": "added_class", "data-id": 123, @@ -285,8 +285,8 @@ class TestHtmlAttrs: """ # noqa: E501 - def get_context_data(self, *args, attrs): - return {"attrs": attrs} + def get_template_data(self, args, kwargs, slots, context): + return {"attrs": kwargs["attrs"]} template = Template(self.template_str) rendered = template.render(Context({"class_var": "padding-top-8"})) @@ -318,8 +318,8 @@ class TestHtmlAttrs: """ # noqa: E501 - def get_context_data(self, *args, attrs): - return {"attrs": attrs} + def get_template_data(self, args, kwargs, slots, context): + return {"attrs": kwargs["attrs"]} template = Template(self.template_str) @@ -346,8 +346,8 @@ class TestHtmlAttrs: """ # noqa: E501 - def get_context_data(self, *args, attrs): - return {"attrs": attrs} + def get_template_data(self, args, kwargs, slots, context): + return {"attrs": kwargs["attrs"]} template = Template(self.template_str) @@ -367,8 +367,8 @@ class TestHtmlAttrs: """ # noqa: E501 - def get_context_data(self, *args, attrs): - return {"attrs": attrs} + def get_template_data(self, args, kwargs, slots, context): + return {"attrs": kwargs["attrs"]} template = Template(self.template_str) rendered = template.render(Context({"class_var": "padding-top-8"})) @@ -391,8 +391,8 @@ class TestHtmlAttrs: """ # noqa: E501 - def get_context_data(self, *args, attrs): - return {"attrs": attrs} + def get_template_data(self, args, kwargs, slots, context): + return {"attrs": kwargs["attrs"]} template_str: types.django_html = """ {% load component_tags %} @@ -421,8 +421,8 @@ class TestHtmlAttrs: """ # noqa: E501 - def get_context_data(self, *args, attrs): - return {"attrs": attrs} + def get_template_data(self, args, kwargs, slots, context): + return {"attrs": kwargs["attrs"]} template = Template(self.template_str) rendered = template.render(Context({"class_var": "padding-top-8"})) @@ -446,9 +446,9 @@ class TestHtmlAttrs: """ - def get_context_data(self, *args, attrs): + def get_template_data(self, args, kwargs, slots, context): return { - "attrs": attrs, + "attrs": kwargs["attrs"], "defaults": {"class": "override-me"}, } @@ -474,7 +474,7 @@ class TestHtmlAttrs: """ - def get_context_data(self, *args, attrs): + def get_template_data(self, args, kwargs, slots, context): return { "attrs": None, "defaults": None, diff --git a/tests/test_component.py b/tests/test_component.py index d85c2d4c..a52e9bf4 100644 --- a/tests/test_component.py +++ b/tests/test_component.py @@ -4,7 +4,7 @@ For tests focusing on the `component` tag, see `test_templatetags_component.py` """ import re -from typing import Any, Dict, no_type_check +from typing import Dict, no_type_check import pytest from django.conf import settings @@ -48,9 +48,9 @@ class CustomClient(Client): super().__init__(*args, **kwargs) -# TODO_REMOVE_IN_V1 - Superseded by `self.get_template` in v1 @djc_test -class TestComponentOldTemplateApi: +class TestComponentLegacyApi: + # TODO_REMOVE_IN_V1 - Superseded by `self.get_template` in v1 @djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR) def test_get_template_string(self, components_settings): class SimpleComponent(Component): @@ -60,6 +60,31 @@ class TestComponentOldTemplateApi: """ return content + def get_template_data(self, args, kwargs, slots, context): + return { + "variable": kwargs.get("variable", None), + } + + class Media: + css = "style.css" + js = "script.js" + + rendered = SimpleComponent.render(kwargs={"variable": "test"}) + assertHTMLEqual( + rendered, + """ + Variable: test + """, + ) + + # TODO_REMOVE_IN_V2 - `get_context_data()` was superseded by `self.get_template_data` + @djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR) + def test_get_context_data(self, components_settings): + class SimpleComponent(Component): + template = """ + Variable: {{ variable }} + """ + def get_context_data(self, variable=None): return { "variable": variable, @@ -95,9 +120,9 @@ class TestComponent: Variable: {{ variable }} """ - def get_context_data(self, variable=None): + def get_template_data(self, args, kwargs, slots, context): return { - "variable": variable, + "variable": kwargs.get("variable", None), } class Media: @@ -121,9 +146,9 @@ class TestComponent: """ return content - def get_context_data(self, variable=None): + def get_template_data(self, args, kwargs, slots, context): return { - "variable": variable, + "variable": kwargs.get("variable", None), } class Media: @@ -143,9 +168,9 @@ class TestComponent: class SimpleComponent(Component): template_file = "simple_template.html" - def get_context_data(self, variable=None): + def get_template_data(self, args, kwargs, slots, context): return { - "variable": variable, + "variable": kwargs.get("variable", None), } class Media: @@ -165,9 +190,9 @@ class TestComponent: class SimpleComponent(Component): template_name = "simple_template.html" - def get_context_data(self, variable=None): + def get_template_data(self, args, kwargs, slots, context): return { - "variable": variable, + "variable": kwargs.get("variable", None), } class Media: @@ -214,12 +239,12 @@ class TestComponent: @djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR) def test_template_file_dynamic(self, components_settings): class SvgComponent(Component): - def get_context_data(self, name, css_class="", title="", **attrs): + def get_template_data(self, args, kwargs, slots, context): return { - "name": name, - "css_class": css_class, - "title": title, - **attrs, + "name": kwargs.pop("name", None), + "css_class": kwargs.pop("css_class", None), + "title": kwargs.pop("title", None), + **kwargs, } def get_template_name(self, context): @@ -241,9 +266,9 @@ class TestComponent: @djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR) def test_allows_to_return_template(self, components_settings): class TestComponent(Component): - def get_context_data(self, variable, **attrs): + def get_template_data(self, args, kwargs, slots, context): return { - "variable": variable, + "variable": kwargs.pop("variable", None), } def get_template(self, context): @@ -261,7 +286,7 @@ class TestComponent: def test_input(self): class TestComponent(Component): @no_type_check - def get_context_data(self, var1, var2, variable, another, **attrs): + def get_template_data(self, args, kwargs, slots, context): assert self.input.args == [123, "str"] assert self.input.kwargs == {"variable": "test", "another": 1} assert isinstance(self.input.context, Context) @@ -269,7 +294,7 @@ class TestComponent: assert self.input.slots["my_slot"](Context(), None, None) == "MY_SLOT" return { - "variable": variable, + "variable": kwargs["variable"], } @no_type_check @@ -312,15 +337,15 @@ class TestComponent: """ - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): data = self.inject("my_provide") data["data1"] # This should raise TypeError return {"data": data} @register("provider") class Provider(Component): - def get_context_data(self, data: Any) -> Any: - return {"data": data} + def get_template_data(self, args, kwargs, slots, context): + return {"data": kwargs["data"]} template: types.django_html = """ {% load component_tags %} @@ -331,8 +356,8 @@ class TestComponent: @register("parent") class Parent(Component): - def get_context_data(self, data: Any) -> Any: - return {"data": data} + def get_template_data(self, args, kwargs, slots, context): + return {"data": kwargs["data"]} template: types.django_html = """ {% load component_tags %} @@ -387,7 +412,7 @@ class TestComponent: class SimpleComponent(Component): template = "Hello" - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): return None assert SimpleComponent.render() == "Hello" @@ -412,11 +437,11 @@ class TestComponentRender: {% endslot %} """ - def get_context_data(self, the_arg2=None, *args, the_kwarg=None, **kwargs): + def get_template_data(self, args, kwargs, slots, context): return { - "the_arg2": the_arg2, - "the_kwarg": the_kwarg, - "args": args, + "the_arg2": args[0] if args else None, + "the_kwarg": kwargs.pop("the_kwarg", None), + "args": args[1:], "kwargs": kwargs, } @@ -425,7 +450,7 @@ class TestComponentRender: rendered, """ the_arg2: None - args: () + args: [] the_kwarg: None kwargs: {} --- @@ -456,12 +481,12 @@ class TestComponentRender: {% endslot %} """ - def get_context_data(self, the_arg, the_arg2=None, *args, the_kwarg, **kwargs): + def get_template_data(self, args, kwargs, slots, context): return { - "the_arg": the_arg, - "the_arg2": the_arg2, - "the_kwarg": the_kwarg, - "args": args, + "the_arg": args[0], + "the_arg2": args[1], + "the_kwarg": kwargs.pop("the_kwarg", None), + "args": args[2:], "kwargs": kwargs, } @@ -476,7 +501,7 @@ class TestComponentRender: """ the_arg: one the_arg2: two - args: ('three',) + args: ['three'] the_kwarg: test kwargs: {'kw2': 'ooo'} --- @@ -509,12 +534,12 @@ class TestComponentRender: {% endslot %} """ - def get_context_data(self, the_arg, the_arg2=None, *args, the_kwarg, **kwargs): + def get_template_data(self, args, kwargs, slots, context): return { - "the_arg": the_arg, - "the_arg2": the_arg2, - "the_kwarg": the_kwarg, - "args": args, + "the_arg": args[0], + "the_arg2": args[1], + "the_kwarg": kwargs.pop("the_kwarg"), + "args": args[2:], "kwargs": kwargs, } @@ -531,7 +556,7 @@ class TestComponentRender: """ the_arg: one the_arg2: two - args: ('three',) + args: ['three'] the_kwarg: test kwargs: {'kw2': 'ooo'} --- @@ -580,10 +605,10 @@ class TestComponentRender: {% endslot %} """ - def get_context_data(self, the_arg, the_kwarg=None, **kwargs): + def get_template_data(self, args, kwargs, slots, context): return { - "the_arg": the_arg, - "the_kwarg": the_kwarg, + "the_arg": args[0], + "the_kwarg": kwargs.pop("the_kwarg", None), "kwargs": kwargs, } @@ -592,7 +617,7 @@ class TestComponentRender: # NOTE: Since the slot has access to the Context object, it should behave # the same way as it does in templates - when in "isolated" mode, then the # slot fill has access only to the "root" context, but not to the data of - # get_context_data() of SimpleComponent. + # get_template_data() of SimpleComponent. if is_isolated: assert ctx.get("the_arg") is None assert ctx.get("the_kwarg") is None @@ -725,8 +750,8 @@ class TestComponentRender: """ - def get_context_data(self, *args, how: str, **kwargs): - return {"how": how} + def get_template_data(self, args, kwargs, slots, context): + return {"how": kwargs.pop("how")} class View(ComponentView): def get(self, request): @@ -734,7 +759,7 @@ class TestComponentRender: return self.component.render_to_response( context=RequestContext(self.request), - kwargs=self.component.get_context_data(how=how), + kwargs={"how": how}, ) client = CustomClient(urlpatterns=[path("test_thing/", Thing.as_view())]) @@ -869,7 +894,7 @@ class TestComponentRender: class TestComponent(Component): template = "Variable: {{ id }}" - def get_context_data(self, **attrs): + def get_template_data(self, args, kwargs, slots, context): return { "id": self.id, } @@ -885,7 +910,7 @@ class TestComponentRender: class TestComponent(Component): template = "Variable: {{ id }}" - def get_context_data(self, **attrs): + def get_template_data(self, args, kwargs, slots, context): return { "id": self.id, } @@ -923,7 +948,7 @@ class TestComponentHook: {% endcomponent %} """ - def get_context_data(self, *args, **kwargs): + def get_template_data(self, args, kwargs, slots, context): return { "args": args, "kwargs": kwargs, @@ -943,7 +968,7 @@ class TestComponentHook: assertHTMLEqual( rendered, """ - args: () + args: [] kwargs: {} --- from_on_before: :) @@ -984,7 +1009,7 @@ class TestComponentHook: {% endcomponent %} """ - def get_context_data(self, *args, **kwargs): + def get_template_data(self, args, kwargs, slots, context): return { "args": args, "kwargs": kwargs, @@ -1006,7 +1031,7 @@ class TestComponentHook: assertHTMLEqual( captured_content, """ - args: () + args: [] kwargs: {} --- from_on_after: @@ -1020,7 +1045,7 @@ class TestComponentHook: assertHTMLEqual( rendered, """ - args: () + args: [] kwargs: {} --- from_on_after: @@ -1060,7 +1085,7 @@ class TestComponentHook: {% endcomponent %} """ - def get_context_data(self, *args, **kwargs): + def get_template_data(self, args, kwargs, slots, context): return { "args": args, "kwargs": kwargs, @@ -1077,7 +1102,7 @@ class TestComponentHook: assertHTMLEqual( captured_content, """ - args: () + args: [] kwargs: {} --- from_on_before: @@ -1092,7 +1117,7 @@ class TestComponentHook: rendered, """ Chocolate cookie recipe: - args: () + args: [] kwargs: {} --- from_on_before: @@ -1131,7 +1156,7 @@ class TestComponentHook: {% endcomponent %} """ - def get_context_data(self, *args, **kwargs): + def get_template_data(self, args, kwargs, slots, context): return { "args": args, "kwargs": kwargs, diff --git a/tests/test_component_cache.py b/tests/test_component_cache.py index 61457afc..f7f0155b 100644 --- a/tests/test_component_cache.py +++ b/tests/test_component_cache.py @@ -1,5 +1,4 @@ import time -from typing import Any from django.core.cache import caches from django.template import Template @@ -33,7 +32,7 @@ class TestComponentCache: class Cache: enabled = True - def get_context_data(self, **kwargs: Any): + def get_template_data(self, args, kwargs, slots, context): nonlocal did_call_get did_call_get = True return {} @@ -55,7 +54,7 @@ class TestComponentCache: did_call_get = False component.render() - # get_context_data not called because the cache entry was returned + # get_template_data not called because the cache entry was returned assert not did_call_get assert result == "Hello" @@ -68,7 +67,7 @@ class TestComponentCache: class Cache: enabled = False - def get_context_data(self, **kwargs: Any): + def get_template_data(self, args, kwargs, slots, context): nonlocal did_call_get did_call_get = True return {} @@ -89,7 +88,7 @@ class TestComponentCache: did_call_get = False result = component.render() - # get_context_data IS called because the cache is NOT used + # get_template_data IS called because the cache is NOT used assert did_call_get assert result == "Hello" @@ -151,8 +150,8 @@ class TestComponentCache: class Cache: enabled = True - def get_context_data(self, input, **kwargs: Any): - return {"input": input} + def get_template_data(self, args, kwargs, slots, context): + return {"input": kwargs["input"]} component = TestComponent() component.render( @@ -200,7 +199,7 @@ class TestComponentCache: # Custom hash method for args and kwargs return "custom-args-and-kwargs" - def get_context_data(self, *args, **kwargs: Any): + def get_template_data(self, args, kwargs, slots, context): return {} component = TestComponent() diff --git a/tests/test_component_defaults.py b/tests/test_component_defaults.py index a9484a1f..8eef8bac 100644 --- a/tests/test_component_defaults.py +++ b/tests/test_component_defaults.py @@ -1,5 +1,4 @@ from dataclasses import field -from typing import Any from django.template import Context @@ -25,25 +24,36 @@ class TestComponentDefaults: extra = "extra" fn = lambda: "fn_as_val" # noqa: E731 - def get_context_data(self, arg1: Any, variable: Any, another: Any, **attrs: Any): + def get_template_data(self, args, kwargs, slots, context): nonlocal did_call_context did_call_context = True - # Check that args and slots are NOT affected by the defaults - assert self.input.args == [123] - assert [*self.input.slots.keys()] == ["my_slot"] - assert self.input.slots["my_slot"](Context(), None, None) == "MY_SLOT" # type: ignore[arg-type] - + assert kwargs == { + "variable": "test", # User-given + "another": 1, # Default because missing + "extra": "extra", # Default because `None` was given + "fn": self.Defaults.fn, # Default because missing + } assert self.input.kwargs == { "variable": "test", # User-given "another": 1, # Default because missing "extra": "extra", # Default because `None` was given "fn": self.Defaults.fn, # Default because missing } + + # Check that args and slots are NOT affected by the defaults + assert args == [123] + assert [*slots.keys()] == ["my_slot"] + assert slots["my_slot"](Context(), None, None) == "MY_SLOT" # type: ignore[arg-type] + + assert self.input.args == [123] + assert [*self.input.slots.keys()] == ["my_slot"] + assert self.input.slots["my_slot"](Context(), None, None) == "MY_SLOT" # type: ignore[arg-type] + assert isinstance(self.input.context, Context) return { - "variable": variable, + "variable": kwargs["variable"], } TestComponent.render( @@ -64,10 +74,14 @@ class TestComponentDefaults: variable = "test" fn = Default(lambda: "fn_as_factory") - def get_context_data(self, variable: Any, **attrs: Any): + def get_template_data(self, args, kwargs, slots, context): nonlocal did_call_context did_call_context = True + assert kwargs == { + "variable": "test", # User-given + "fn": "fn_as_factory", # Default because missing + } assert self.input.kwargs == { "variable": "test", # User-given "fn": "fn_as_factory", # Default because missing @@ -75,7 +89,7 @@ class TestComponentDefaults: assert isinstance(self.input.context, Context) return { - "variable": variable, + "variable": kwargs["variable"], } TestComponent.render( @@ -94,10 +108,15 @@ class TestComponentDefaults: variable = "test" fn = field(default=lambda: "fn_as_factory") - def get_context_data(self, variable: Any, **attrs: Any): + def get_template_data(self, args, kwargs, slots, context): nonlocal did_call_context did_call_context = True + assert kwargs == { + "variable": "test", # User-given + # NOTE: NOT a factory, because it was set as `field(default=...)` + "fn": self.Defaults.fn.default, # type: ignore[attr-defined] + } assert self.input.kwargs == { "variable": "test", # User-given # NOTE: NOT a factory, because it was set as `field(default=...)` @@ -106,7 +125,7 @@ class TestComponentDefaults: assert isinstance(self.input.context, Context) return { - "variable": variable, + "variable": kwargs["variable"], } TestComponent.render( @@ -125,10 +144,15 @@ class TestComponentDefaults: variable = "test" fn = field(default_factory=lambda: "fn_as_factory") - def get_context_data(self, variable: Any, **attrs: Any): + def get_template_data(self, args, kwargs, slots, context): nonlocal did_call_context did_call_context = True + assert kwargs == { + "variable": "test", # User-given + # NOTE: IS a factory, because it was set as `field(default_factory=...)` + "fn": "fn_as_factory", # Default because missing + } assert self.input.kwargs == { "variable": "test", # User-given # NOTE: IS a factory, because it was set as `field(default_factory=...)` @@ -137,7 +161,7 @@ class TestComponentDefaults: assert isinstance(self.input.context, Context) return { - "variable": variable, + "variable": kwargs["variable"], } TestComponent.render( diff --git a/tests/test_component_media.py b/tests/test_component_media.py index 3e81d1d8..bfdfc549 100644 --- a/tests/test_component_media.py +++ b/tests/test_component_media.py @@ -132,9 +132,9 @@ class TestMainMedia: css_file = "style.css" js_file = "script.js" - def get_context_data(self, variable): + def get_template_data(self, args, kwargs, slots, context): return { - "variable": variable, + "variable": kwargs["variable"], } registry.register("test", TestComponent) @@ -231,10 +231,10 @@ class TestMainMedia: Var2 (uppercased): {{ var2|upper }} """ - def get_context_data(self, var1=None, var2=None): + def get_template_data(self, args, kwargs, slots, context): return { - "var1": var1, - "var2": var2, + "var1": kwargs["var1"], + "var2": kwargs["var2"], } rendered = FilteredComponent.render(kwargs={"var1": "test1", "var2": "test2"}) @@ -871,7 +871,7 @@ class TestMediaRelativePath: """ # noqa - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): return {"shadowing_variable": "NOT SHADOWED"} class VariableDisplay(Component): @@ -881,12 +881,12 @@ class TestMediaRelativePath:

Uniquely named variable = {{ unique_variable }}

""" - def get_context_data(self, shadowing_variable=None, new_variable=None): + def get_template_data(self, args, kwargs, slots, context): context = {} - if shadowing_variable is not None: - context["shadowing_variable"] = shadowing_variable - if new_variable is not None: - context["unique_variable"] = new_variable + if kwargs["shadowing_variable"] is not None: + context["shadowing_variable"] = kwargs["shadowing_variable"] + if kwargs["new_variable"] is not None: + context["unique_variable"] = kwargs["new_variable"] return context # Settings required for autodiscover to work diff --git a/tests/test_component_typing.py b/tests/test_component_typing.py index 194be118..f50bb003 100644 --- a/tests/test_component_typing.py +++ b/tests/test_component_typing.py @@ -142,7 +142,7 @@ class TestComponentTyping: css_data_instance = None class Button(Component): - # Data returned from `get_context_data` + # Data returned from `get_template_data` @dataclass class TemplateData: data1: str @@ -232,7 +232,7 @@ class TestComponentTyping: css_data_instance = None class Button(Component): - # Data returned from `get_context_data` + # Data returned from `get_template_data` @dataclass class TemplateData: data1: str @@ -348,7 +348,7 @@ class TestComponentTyping: # The generic specifies the data available to the slot function footer: NotRequired[Slot[ButtonFooterSlotData]] - # Data returned from `get_context_data` + # Data returned from `get_template_data` class TemplateData(NamedTuple): data1: str data2: int diff --git a/tests/test_component_view.py b/tests/test_component_view.py index fbbb0f1c..339cca63 100644 --- a/tests/test_component_view.py +++ b/tests/test_component_view.py @@ -1,4 +1,4 @@ -from typing import Any, Dict +from typing import Any import pytest from django.conf import settings @@ -60,8 +60,8 @@ class TestComponentAsView(SimpleTestCase): """ - def get_context_data(self, variable, *args, **kwargs) -> Dict[str, Any]: - return {"variable": variable} + def get_template_data(self, args, kwargs, slots, context): + return {"variable": kwargs["variable"]} def render_template_view(request): template = Template( @@ -90,8 +90,8 @@ class TestComponentAsView(SimpleTestCase): """ - def get_context_data(self, variable): - return {"inner_var": variable} + def get_template_data(self, args, kwargs, slots, context): + return {"inner_var": kwargs["variable"]} class View(ComponentView): def get(self, request, *args, **kwargs) -> HttpResponse: @@ -115,8 +115,8 @@ class TestComponentAsView(SimpleTestCase): """ - def get_context_data(self, variable): - return {"inner_var": variable} + def get_template_data(self, args, kwargs, slots, context): + return {"inner_var": kwargs["variable"]} def get(self, request, *args, **kwargs) -> HttpResponse: return self.render_to_response(kwargs={"variable": "GET"}) @@ -139,8 +139,8 @@ class TestComponentAsView(SimpleTestCase): """ - def get_context_data(self, variable): - return {"inner_var": variable} + def get_template_data(self, args, kwargs, slots, context): + return {"inner_var": kwargs["variable"]} class View(ComponentView): def post(self, request, *args, **kwargs) -> HttpResponse: @@ -165,8 +165,8 @@ class TestComponentAsView(SimpleTestCase): """ - def get_context_data(self, variable): - return {"inner_var": variable} + def get_template_data(self, args, kwargs, slots, context): + return {"inner_var": kwargs["variable"]} def post(self, request, *args, **kwargs) -> HttpResponse: variable = request.POST.get("variable") @@ -188,8 +188,8 @@ class TestComponentAsView(SimpleTestCase): """ - def get_context_data(self, variable): - return {"inner_var": variable} + def get_template_data(self, args, kwargs, slots, context): + return {"inner_var": kwargs["variable"]} def get(self, request, *args, **kwargs) -> HttpResponse: return self.render_to_response(kwargs={"variable": self.name}) diff --git a/tests/test_context.py b/tests/test_context.py index da1039f9..87f03177 100644 --- a/tests/test_context.py +++ b/tests/test_context.py @@ -24,8 +24,8 @@ class SimpleComponent(Component): Variable: {{ variable }} """ - def get_context_data(self, variable=None): - return {"variable": variable} if variable is not None else {} + def get_template_data(self, args, kwargs, slots, context): + return {"variable": kwargs.get("variable", None)} if "variable" in kwargs else {} class VariableDisplay(Component): @@ -35,12 +35,12 @@ class VariableDisplay(Component):

Uniquely named variable = {{ unique_variable }}

""" - def get_context_data(self, shadowing_variable=None, new_variable=None): + def get_template_data(self, args, kwargs, slots, context): context = {} - if shadowing_variable is not None: - context["shadowing_variable"] = shadowing_variable - if new_variable is not None: - context["unique_variable"] = new_variable + if kwargs["shadowing_variable"] is not None: + context["shadowing_variable"] = kwargs["shadowing_variable"] + if kwargs["new_variable"] is not None: + context["unique_variable"] = kwargs["new_variable"] return context @@ -55,8 +55,8 @@ class IncrementerComponent(Component): super().__init__(*args, **kwargs) self.call_count = 0 - def get_context_data(self, value=0): - value = int(value) + def get_template_data(self, args, kwargs, slots, context): + value = int(kwargs.get("value", 0)) if hasattr(self, "call_count"): self.call_count += 1 else: @@ -88,7 +88,7 @@ class TestContext: """ # noqa - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): return {"shadowing_variable": "NOT SHADOWED"} @djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR) @@ -231,8 +231,8 @@ class TestParentArgs: """ # noqa - def get_context_data(self, parent_value): - return {"inner_parent_value": parent_value} + def get_template_data(self, args, kwargs, slots, context): + return {"inner_parent_value": kwargs["parent_value"]} @djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR) def test_parent_args_can_be_drawn_from_context(self, components_settings): @@ -463,7 +463,7 @@ class TestIsolatedContext: registry.register(name="simple_component", component=SimpleComponent) template_str: types.django_html = """ {% load component_tags %} - {% component 'simple_component' variable only %}{% endcomponent %} + {% component 'simple_component' variable=variable only %}{% endcomponent %} """ template = Template(template_str) rendered = template.render(Context({"variable": "outer_value"})).strip() @@ -490,7 +490,7 @@ class TestIsolatedContextSetting: registry.register(name="simple_component", component=SimpleComponent) template_str: types.django_html = """ {% load component_tags %} - {% component 'simple_component' variable %}{% endcomponent %} + {% component 'simple_component' variable=variable %}{% endcomponent %} """ template = Template(template_str) rendered = template.render(Context({"variable": "outer_value"})) @@ -516,7 +516,7 @@ class TestIsolatedContextSetting: registry.register(name="simple_component", component=SimpleComponent) template_str: types.django_html = """ {% load component_tags %} - {% component 'simple_component' variable %} + {% component 'simple_component' variable=variable %} {% endcomponent %} """ template = Template(template_str) @@ -549,7 +549,7 @@ class TestContextProcessors: class TestComponent(Component): template: types.django_html = """{% csrf_token %}""" - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): nonlocal context_processors_data nonlocal inner_request context_processors_data = self.context_processors_data @@ -585,7 +585,7 @@ class TestContextProcessors: {% component "test_child" / %} """ - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): nonlocal context_processors_data nonlocal parent_request context_processors_data = self.context_processors_data @@ -596,7 +596,7 @@ class TestContextProcessors: class TestChildComponent(Component): template: types.django_html = """{% csrf_token %}""" - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): nonlocal context_processors_data_child nonlocal child_request context_processors_data_child = self.context_processors_data @@ -635,7 +635,7 @@ class TestContextProcessors: {% endcomponent %} """ - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): nonlocal context_processors_data nonlocal parent_request context_processors_data = self.context_processors_data @@ -646,7 +646,7 @@ class TestContextProcessors: class TestChildComponent(Component): template: types.django_html = """{% csrf_token %}""" - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): nonlocal context_processors_data_child nonlocal child_request context_processors_data_child = self.context_processors_data @@ -680,7 +680,7 @@ class TestContextProcessors: class TestComponent(Component): template: types.django_html = """{% csrf_token %}""" - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): nonlocal context_processors_data nonlocal inner_request context_processors_data = self.context_processors_data @@ -709,7 +709,7 @@ class TestContextProcessors: {% component "test_child" / %} """ - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): nonlocal context_processors_data nonlocal parent_request context_processors_data = self.context_processors_data @@ -720,7 +720,7 @@ class TestContextProcessors: class TestChildComponent(Component): template: types.django_html = """{% csrf_token %}""" - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): nonlocal context_processors_data_child nonlocal child_request context_processors_data_child = self.context_processors_data @@ -746,7 +746,7 @@ class TestContextProcessors: class TestComponent(Component): template: types.django_html = """{% csrf_token %}""" - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): nonlocal context_processors_data nonlocal inner_request context_processors_data = self.context_processors_data @@ -774,7 +774,7 @@ class TestContextProcessors: {% component "test_child" / %} """ - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): nonlocal context_processors_data nonlocal parent_request context_processors_data = self.context_processors_data @@ -785,7 +785,7 @@ class TestContextProcessors: class TestChildComponent(Component): template: types.django_html = """{% csrf_token %}""" - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): nonlocal context_processors_data_child nonlocal child_request context_processors_data_child = self.context_processors_data @@ -811,7 +811,7 @@ class TestContextProcessors: class TestComponent(Component): template: types.django_html = """{% csrf_token %}""" - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): nonlocal context_processors_data nonlocal inner_request context_processors_data = self.context_processors_data @@ -834,7 +834,7 @@ class TestContextProcessors: class TestComponent(Component): template: types.django_html = """{% csrf_token %}""" - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): nonlocal context_processors_data nonlocal inner_request context_processors_data = self.context_processors_data @@ -857,7 +857,7 @@ class TestContextProcessors: class TestComponent(Component): template: types.django_html = """{% csrf_token %}""" - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): nonlocal context_processors_data nonlocal inner_request context_processors_data = self.context_processors_data @@ -902,7 +902,7 @@ class TestOuterContextProperty: Variable: {{ variable }} """ - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): return self.outer_context.flatten() # type: ignore[union-attr] template_str: types.django_html = """ diff --git a/tests/test_dependencies.py b/tests/test_dependencies.py index ca7dffe8..fce8101b 100644 --- a/tests/test_dependencies.py +++ b/tests/test_dependencies.py @@ -38,10 +38,10 @@ class SimpleComponent(Component): console.log("xyz"); """ - def get_context_data(self, variable, variable2="default"): + def get_template_data(self, args, kwargs, slots, context): return { - "variable": variable, - "variable2": variable2, + "variable": kwargs["variable"], + "variable2": kwargs.get("variable2", "default"), } class Media: @@ -551,7 +551,7 @@ class TestDependenciesStrategySimple: console.log("Hello"); """ - def get_context_data(self, variable): + def get_template_data(self, args, kwargs, slots, context): return {} class Media: @@ -573,7 +573,7 @@ class TestDependenciesStrategySimple: console.log("xyz"); """ - def get_context_data(self, variable): + def get_template_data(self, args, kwargs, slots, context): return {} class Media: @@ -711,7 +711,7 @@ class TestDependenciesStrategyPrepend: console.log("Hello"); """ - def get_context_data(self, variable): + def get_template_data(self, args, kwargs, slots, context): return {} class Media: @@ -733,7 +733,7 @@ class TestDependenciesStrategyPrepend: console.log("xyz"); """ - def get_context_data(self, variable): + def get_template_data(self, args, kwargs, slots, context): return {} class Media: @@ -868,7 +868,7 @@ class TestDependenciesStrategyAppend: console.log("Hello"); """ - def get_context_data(self, variable): + def get_template_data(self, args, kwargs, slots, context): return {} class Media: @@ -890,7 +890,7 @@ class TestDependenciesStrategyAppend: console.log("xyz"); """ - def get_context_data(self, variable): + def get_template_data(self, args, kwargs, slots, context): return {} class Media: diff --git a/tests/test_dependency_rendering.py b/tests/test_dependency_rendering.py index 219bf5e5..3a67ab6b 100644 --- a/tests/test_dependency_rendering.py +++ b/tests/test_dependency_rendering.py @@ -25,10 +25,10 @@ class SimpleComponent(Component): Variable: {{ variable }} """ - def get_context_data(self, variable, variable2="default"): + def get_template_data(self, args, kwargs, slots, context): return { - "variable": variable, - "variable2": variable2, + "variable": kwargs["variable"], + "variable2": kwargs.get("variable2", "default"), } class Media: @@ -55,7 +55,7 @@ class SimpleComponentNested(Component): console.log("Hello"); """ - def get_context_data(self, variable): + def get_template_data(self, args, kwargs, slots, context): return {} class Media: @@ -78,7 +78,7 @@ class OtherComponent(Component): console.log("xyz"); """ - def get_context_data(self, variable): + def get_template_data(self, args, kwargs, slots, context): return {} class Media: @@ -91,7 +91,7 @@ class SimpleComponentWithSharedDependency(Component): Variable: {{ variable }} """ - def get_context_data(self, variable, variable2="default"): + def get_template_data(self, args, kwargs, slots, context): return {} class Media: diff --git a/tests/test_expression.py b/tests/test_expression.py index 1df6861e..ebb1c9db 100644 --- a/tests/test_expression.py +++ b/tests/test_expression.py @@ -1,7 +1,7 @@ """Catch-all for tests that use template tags and don't fit other files""" import re -from typing import Any, Dict +from typing import Dict import pytest from django.template import Context, Template, TemplateSyntaxError @@ -68,21 +68,15 @@ class TestDynamicExpr: @register("test") class SimpleComponent(Component): - def get_context_data( - self, - pos_var1: Any, - *args: Any, - bool_var: bool, - list_var: Dict, - ): - captured["pos_var1"] = pos_var1 - captured["bool_var"] = bool_var - captured["list_var"] = list_var + def get_template_data(self, args, kwargs, slots, context): + captured["pos_var1"] = args[0] + captured["bool_var"] = kwargs["bool_var"] + captured["list_var"] = kwargs["list_var"] return { - "pos_var1": pos_var1, - "bool_var": bool_var, - "list_var": list_var, + "pos_var1": args[0], + "bool_var": kwargs["bool_var"], + "list_var": kwargs["list_var"], } template: types.django_html = """ @@ -135,24 +129,17 @@ class TestDynamicExpr: @register("test") class SimpleComponent(Component): - def get_context_data( - self, - pos_var1: Any, - *args: Any, - bool_var: bool, - list_var: Dict, - dict_var: Dict, - ): - captured["pos_var1"] = pos_var1 - captured["bool_var"] = bool_var - captured["list_var"] = list_var - captured["dict_var"] = dict_var + def get_template_data(self, args, kwargs, slots, context): + captured["pos_var1"] = args[0] + captured["bool_var"] = kwargs["bool_var"] + captured["list_var"] = kwargs["list_var"] + captured["dict_var"] = kwargs["dict_var"] return { - "pos_var1": pos_var1, - "bool_var": bool_var, - "list_var": list_var, - "dict_var": dict_var, + "pos_var1": args[0], + "bool_var": kwargs["bool_var"], + "list_var": kwargs["list_var"], + "dict_var": kwargs["dict_var"], } template: types.django_html = """ @@ -209,24 +196,17 @@ class TestDynamicExpr: @register("test") class SimpleComponent(Component): - def get_context_data( - self, - pos_var1: Any, - pos_var2: Any, - *args: Any, - bool_var: bool, - list_var: Dict, - ): - captured["pos_var1"] = pos_var1 - captured["pos_var2"] = pos_var2 - captured["bool_var"] = bool_var - captured["list_var"] = list_var + def get_template_data(self, args, kwargs, slots, context): + captured["pos_var1"] = args[0] + captured["pos_var2"] = args[1] + captured["bool_var"] = kwargs["bool_var"] + captured["list_var"] = kwargs["list_var"] return { - "pos_var1": pos_var1, - "pos_var2": pos_var2, - "bool_var": bool_var, - "list_var": list_var, + "pos_var1": args[0], + "pos_var2": args[1], + "bool_var": kwargs["bool_var"], + "list_var": kwargs["list_var"], } template: types.django_html = """ @@ -281,26 +261,18 @@ class TestDynamicExpr: @register("test") class SimpleComponent(Component): - def get_context_data( - self, - pos_var1: Any, - pos_var2: Any, - *args: Any, - bool_var: bool, - list_var: Dict, - dict_var: Dict, - ): - captured["pos_var1"] = pos_var1 - captured["bool_var"] = bool_var - captured["list_var"] = list_var - captured["dict_var"] = dict_var + def get_template_data(self, args, kwargs, slots, context): + captured["pos_var1"] = args[0] + captured["bool_var"] = kwargs["bool_var"] + captured["list_var"] = kwargs["list_var"] + captured["dict_var"] = kwargs["dict_var"] return { - "pos_var1": pos_var1, - "pos_var2": pos_var2, - "bool_var": bool_var, - "list_var": list_var, - "dict_var": dict_var, + "pos_var1": args[0], + "pos_var2": args[1], + "bool_var": kwargs["bool_var"], + "list_var": kwargs["list_var"], + "dict_var": kwargs["dict_var"], } template: types.django_html = """ @@ -357,17 +329,11 @@ class TestDynamicExpr: @register("test") class SimpleComponent(Component): - def get_context_data( - self, - pos_var1: Any, - pos_var2: Any, - *args: Any, - bool_var: bool, - ): + def get_template_data(self, args, kwargs, slots, context): return { - "pos_var1": pos_var1, - "pos_var2": pos_var2, - "bool_var": bool_var, + "pos_var1": args[0], + "pos_var2": args[1], + "bool_var": kwargs["bool_var"], } template: types.django_html = """ @@ -404,15 +370,10 @@ class TestDynamicExpr: @register("test") class SimpleComponent(Component): - def get_context_data( - self, - pos_var1: Any, - *args: Any, - bool_var: bool, - ): + def get_template_data(self, args, kwargs, slots, context): return { - "pos_var1": pos_var1, - "bool_var": bool_var, + "pos_var1": args[0], + "bool_var": kwargs["bool_var"], } template: types.django_html = """ @@ -461,17 +422,12 @@ class TestSpreadOperator: @register("test") class SimpleComponent(Component): - def get_context_data( - self, - pos_var1: Any, - *args: Any, - **kwargs: Any, - ): + def get_template_data(self, args, kwargs, slots, context): nonlocal captured captured = kwargs return { - "pos_var1": pos_var1, + "pos_var1": args[0], **kwargs, } @@ -531,7 +487,7 @@ class TestSpreadOperator: def test_slot(self, components_settings): @register("test") class SimpleComponent(Component): - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): return { "my_dict": { "attrs:@click": "() => {}", @@ -568,7 +524,7 @@ class TestSpreadOperator: def test_fill(self, components_settings): @register("test") class SimpleComponent(Component): - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): return { "my_dict": { "attrs:@click": "() => {}", @@ -618,7 +574,7 @@ class TestSpreadOperator: def test_provide(self, components_settings): @register("test") class SimpleComponent(Component): - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): data = self.inject("test") return { "attrs": data.attrs, @@ -692,11 +648,7 @@ class TestSpreadOperator: def test_later_spreads_do_not_overwrite_earlier(self, components_settings): @register("test") class SimpleComponent(Component): - def get_context_data( - self, - *args: Any, - **kwargs: Any, - ): + def get_template_data(self, args, kwargs, slots, context): return { **kwargs, } @@ -794,7 +746,7 @@ class TestSpreadOperator: class SimpleComponent(Component): template = "" - def get_context_data(self, *args, **kwargs): + def get_template_data(self, args, kwargs, slots, context): nonlocal captured captured = args, kwargs return {} @@ -820,7 +772,7 @@ class TestSpreadOperator: template.render(context) assert captured == ( - ("a", "b", "c", 1, 2, 3), + ["a", "b", "c", 1, 2, 3], {}, ) @@ -858,7 +810,7 @@ class TestAggregateKwargs: class Test(Component): template = "" - def get_context_data(self, *args, **kwargs): + def get_template_data(self, args, kwargs, slots, context): nonlocal captured captured = args, kwargs return {} @@ -879,7 +831,7 @@ class TestAggregateKwargs: template.render(Context({"class_var": "padding-top-8", "four": 4})) assert captured == ( - (), + [], { "attrs": { "@click.stop": "dispatch('click_event')", diff --git a/tests/test_extension.py b/tests/test_extension.py index bef472f7..76fce84d 100644 --- a/tests/test_extension.py +++ b/tests/test_extension.py @@ -116,8 +116,8 @@ def with_component_cls(on_created: Callable): class TempComponent(Component): template = "Hello {{ name }}!" - def get_context_data(self, name="World"): - return {"name": name} + def get_template_data(self, args, kwargs, slots, context): + return {"name": kwargs.get("name", "World")} on_created() @@ -143,8 +143,8 @@ class TestExtension: class TestAccessComp(Component): template = "Hello {{ name }}!" - def get_context_data(self, arg1, arg2, name="World"): - return {"name": name} + def get_template_data(self, args, kwargs, slots, context): + return {"name": kwargs.get("name", "World")} ext_class = TestAccessComp.TestExtension # type: ignore[attr-defined] assert issubclass(ext_class, ComponentExtension.ExtensionClass) @@ -240,8 +240,8 @@ class TestExtensionHooks: class TestComponent(Component): template = "Hello {{ name }}!" - def get_context_data(self, name="World"): - return {"name": name} + def get_template_data(self, args, kwargs, slots, context): + return {"name": kwargs.get("name", "World")} registry.register("test_comp", TestComponent) extension = cast(DummyExtension, app_settings.EXTENSIONS[3]) @@ -268,13 +268,13 @@ class TestExtensionHooks: class TestComponent(Component): template = "Hello {{ name }}!" - def get_context_data(self, arg1, arg2, name="World"): - return {"name": name} + def get_template_data(self, args, kwargs, slots, context): + return {"name": kwargs.get("name", "World")} - def get_js_data(self, *args, **kwargs): + def get_js_data(self, args, kwargs, slots, context): return {"script": "console.log('Hello!')"} - def get_css_data(self, *args, **kwargs): + def get_css_data(self, args, kwargs, slots, context): return {"style": "body { color: blue; }"} # Render the component with some args and kwargs diff --git a/tests/test_registry.py b/tests/test_registry.py index f7793954..d9b240c5 100644 --- a/tests/test_registry.py +++ b/tests/test_registry.py @@ -182,9 +182,9 @@ class TestMultipleComponentRegistries: Slot: {% slot "default" default / %} """ - def get_context_data(self, variable=None): + def get_template_data(self, args, kwargs, slots, context): return { - "variable": variable, + "variable": kwargs.get("variable", None), } registry_a.register("simple_a", SimpleComponent) diff --git a/tests/test_signals.py b/tests/test_signals.py index 9be81b74..af0890f9 100644 --- a/tests/test_signals.py +++ b/tests/test_signals.py @@ -51,10 +51,10 @@ class TestTemplateSignal: class InnerComponent(Component): template_file = "simple_template.html" - def get_context_data(self, variable, variable2="default"): + def get_template_data(self, args, kwargs, slots, context): return { - "variable": variable, - "variable2": variable2, + "variable": kwargs["variable"], + "variable2": kwargs.get("variable2", "default"), } class Media: diff --git a/tests/test_tag_parser.py b/tests/test_tag_parser.py index 2e65c3bb..ef96438e 100644 --- a/tests/test_tag_parser.py +++ b/tests/test_tag_parser.py @@ -2706,7 +2706,7 @@ class TestResolver: @register("test") class Test(Component): - def get_context_data(self, **kwargs): + def get_template_data(self, args, kwargs, slots, context): nonlocal captured captured = kwargs return {} @@ -2771,7 +2771,7 @@ class TestResolver: class Test(Component): template = "var" - def get_context_data(self, *args, **kwargs): + def get_template_data(self, args, kwargs, slots, context): nonlocal captured captured = args, kwargs return {} @@ -2783,7 +2783,7 @@ class TestResolver: """ Template(template_str).render(Context({"myvar": "myval", "val2": [1, 2, 3]})) - assert captured == ((42, "myval"), {"key": "val", "key2": [1, 2, 3]}) + assert captured == ([42, "myval"], {"key": "val", "key2": [1, 2, 3]}) def test_component_special_kwargs(self): captured = None @@ -2792,7 +2792,7 @@ class TestResolver: class Test(Component): template = "var" - def get_context_data(self, *args, **kwargs): + def get_template_data(self, args, kwargs, slots, context): nonlocal captured captured = args, kwargs return {} @@ -2805,7 +2805,7 @@ class TestResolver: Template(template_str).render(Context({"date": 2024, "bzz": "fzz"})) assert captured == ( - tuple([]), + [], { "date": 2024, "@lol": 2, diff --git a/tests/test_template.py b/tests/test_template.py index a11e14ca..4e8e0e6c 100644 --- a/tests/test_template.py +++ b/tests/test_template.py @@ -33,9 +33,9 @@ class TestTemplateCache: """ return content - def get_context_data(self, variable=None): + def get_template_data(self, args, kwargs, slots, context): return { - "variable": variable, + "variable": kwargs.get("variable", None), } comp = SimpleComponent() diff --git a/tests/test_template_parser.py b/tests/test_template_parser.py index 7d97a644..1c630643 100644 --- a/tests/test_template_parser.py +++ b/tests/test_template_parser.py @@ -215,8 +215,8 @@ class TestTemplateParser: Slot: {% slot "content" default / %} """ - def get_context_data(self, var: str) -> dict: - return {"var": var} + def get_template_data(self, args, kwargs, slots, context): + return {"var": kwargs["var"]} template_str: types.django_html = """ {% load component_tags %} diff --git a/tests/test_templatetags.py b/tests/test_templatetags.py index bd094046..56ed15b0 100644 --- a/tests/test_templatetags.py +++ b/tests/test_templatetags.py @@ -29,17 +29,17 @@ class TestMultilineTags: Variable: {{ variable }} """ - def get_context_data(self, variable, variable2="default"): + def get_template_data(self, args, kwargs, slots, context): return { - "variable": variable, - "variable2": variable2, + "variable": kwargs["variable"], + "variable2": kwargs.get("variable2", "default"), } template: types.django_html = """ {% load component_tags %} {% component "test_component" - 123 + variable=123 variable2="abc" %} {% endcomponent %} @@ -58,9 +58,9 @@ class TestNestedTags: Variable: {{ var }} """ - def get_context_data(self, var): + def get_template_data(self, args, kwargs, slots, context): return { - "var": var, + "var": kwargs["var"], } # See https://github.com/django-components/django-components/discussions/671 diff --git a/tests/test_templatetags_component.py b/tests/test_templatetags_component.py index a490520f..31590345 100644 --- a/tests/test_templatetags_component.py +++ b/tests/test_templatetags_component.py @@ -1,4 +1,5 @@ import re +from typing import NamedTuple import pytest from django.template import Context, Template, TemplateSyntaxError @@ -25,8 +26,8 @@ class SlottedComponentWithContext(Component): """ - def get_context_data(self, variable): - return {"variable": variable} + def get_template_data(self, args, kwargs, slots, context): + return {"variable": kwargs["variable"]} ####################### @@ -41,10 +42,10 @@ class TestComponentTemplateTag: Variable: {{ variable }} """ - def get_context_data(self, variable, variable2="default"): + def get_template_data(self, args, kwargs, slots, context): return { - "variable": variable, - "variable2": variable2, + "variable": kwargs["variable"], + "variable2": kwargs.get("variable2", "default"), } class Media: @@ -114,10 +115,10 @@ class TestComponentTemplateTag: {% endif %} """ - def get_context_data(self, variable, variable2="default"): + def get_template_data(self, args, kwargs, slots, context): return { - "variable": variable, - "variable2": variable2, + "variable": kwargs["variable"], + "variable2": kwargs.get("variable2", "default"), } class Media: @@ -178,8 +179,11 @@ class TestComponentTemplateTag: Default:

{{ default_param }}

""" - def get_context_data(self, variable, default_param="default text"): - return {"variable": variable, "default_param": default_param} + def get_template_data(self, args, kwargs, slots, context): + return { + "variable": kwargs["variable"], + "default_param": kwargs.get("default_param", "default text"), + } template_str: types.django_html = """ {% load component_tags %} @@ -204,10 +208,17 @@ class TestDynamicComponentTemplateTag: Variable: {{ variable }} """ - def get_context_data(self, variable, variable2="default"): + class Kwargs(NamedTuple): + variable: str + variable2: str + + class Defaults: + variable2 = "default" + + def get_template_data(self, args, kwargs: Kwargs, slots, context): return { - "variable": variable, - "variable2": variable2, + "variable": kwargs.variable, + "variable2": kwargs.variable2, } class Media: @@ -375,10 +386,10 @@ class TestDynamicComponentTemplateTag: Slot: {% slot "default" default / %} """ - def get_context_data(self, variable, variable2="default"): + def get_template_data(self, args, kwargs, slots, context): return { - "variable": variable, - "variable2": variable2, + "variable": kwargs["variable"], + "variable2": kwargs.get("variable2", "default"), } registry.register(name="test", component=SimpleSlottedComponent) @@ -412,10 +423,10 @@ class TestDynamicComponentTemplateTag: Slot 2: {% slot "two" / %} """ - def get_context_data(self, variable, variable2="default"): + def get_template_data(self, args, kwargs, slots, context): return { - "variable": variable, - "variable2": variable2, + "variable": kwargs["variable"], + "variable2": kwargs.get("variable2", "default"), } registry.register(name="test", component=SimpleSlottedComponent) @@ -455,10 +466,10 @@ class TestDynamicComponentTemplateTag: Slot 2: {% slot "two" / %} """ - def get_context_data(self, variable, variable2="default"): + def get_template_data(self, args, kwargs, slots, context): return { - "variable": variable, - "variable2": variable2, + "variable": kwargs["variable"], + "variable2": kwargs.get("variable2", "default"), } registry.register(name="test", component=SimpleSlottedComponent) @@ -722,8 +733,11 @@ class TestAggregateInput: """ - def get_context_data(self, *args, attrs, my_dict): - return {"attrs": attrs, "my_dict": my_dict} + def get_template_data(self, args, kwargs, slots, context): + return { + "attrs": kwargs["attrs"], + "my_dict": kwargs["my_dict"], + } template_str: types.django_html = """ {% load component_tags %} @@ -751,9 +765,12 @@ class TestRecursiveComponent: @register("recursive") class Recursive(Component): - def get_context_data(self, depth: int = 0): - print("depth:", depth) - return {"depth": depth + 1, "DEPTH": DEPTH} + class Defaults: + depth = 0 + + def get_template_data(self, args, kwargs, slots, context): + print("depth:", kwargs["depth"]) + return {"depth": kwargs["depth"] + 1, "DEPTH": DEPTH} template: types.django_html = """
diff --git a/tests/test_templatetags_extends.py b/tests/test_templatetags_extends.py index c963be2d..9b0de66b 100644 --- a/tests/test_templatetags_extends.py +++ b/tests/test_templatetags_extends.py @@ -820,7 +820,7 @@ class TestExtendsCompat:
injected: {{ var|safe }}
""" - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): var = self.inject("block_provide") return {"var": var} diff --git a/tests/test_templatetags_provide.py b/tests/test_templatetags_provide.py index f0675794..ae588138 100644 --- a/tests/test_templatetags_provide.py +++ b/tests/test_templatetags_provide.py @@ -1,5 +1,4 @@ import re -from typing import Any import pytest from django.template import Context, Template, TemplateSyntaxError @@ -29,7 +28,7 @@ class TestProvideTemplateTag:
injected: {{ var|safe }}
""" - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): var = self.inject("my_provide", "default") return {"var": var} @@ -79,7 +78,7 @@ class TestProvideTemplateTag:
another: {{ another }}
""" - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): my_provide = self.inject("my_provide") return { "key": my_provide.key, @@ -114,7 +113,7 @@ class TestProvideTemplateTag:
another: {{ my_provide.another }}
""" - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): my_provide = self.inject("my_provide") return { "my_provide": my_provide, @@ -147,7 +146,7 @@ class TestProvideTemplateTag:
injected: {{ var|safe }}
""" - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): var = self.inject("my_provide", "default") return {"var": var} @@ -179,7 +178,7 @@ class TestProvideTemplateTag:
injected: {{ var|safe }}
""" - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): var = self.inject("my_provide", "default") return {"var": var} @@ -214,7 +213,7 @@ class TestProvideTemplateTag:
""" - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): return {} template_str: types.django_html = """ @@ -246,7 +245,7 @@ class TestProvideTemplateTag:
injected: {{ var|safe }}
""" - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): var = self.inject("my_provide", "default") return {"var": var} @@ -279,7 +278,7 @@ class TestProvideTemplateTag:
injected: {{ var|safe }}
""" - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): var = self.inject("my_provide", "default") return {"var": var} @@ -318,7 +317,7 @@ class TestProvideTemplateTag:
injected: {{ var|safe }}
""" - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): var = self.inject("my_provide", "default") return {"var": var} @@ -361,7 +360,7 @@ class TestProvideTemplateTag:
injected: {{ var|safe }}
""" - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): var = self.inject("my_provide", "default") return {"var": var} @@ -390,7 +389,7 @@ class TestProvideTemplateTag:
injected: {{ var|safe }}
""" - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): var = self.inject("my_provide", "default") return {"var": var} @@ -419,7 +418,7 @@ class TestProvideTemplateTag:
injected: {{ var|safe }}
""" - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): var = self.inject("my_provide", "default") return {"var": var} @@ -446,7 +445,7 @@ class TestProvideTemplateTag:
injected: {{ var|safe }}
""" - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): var = self.inject("my_provide", "default") return {"var": var} @@ -478,7 +477,7 @@ class TestProvideTemplateTag:
injected: {{ var|safe }}
""" - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): var = self.inject("my_provide", "default") return {"var": var} @@ -515,7 +514,7 @@ class TestProvideTemplateTag:
injected: {{ var|safe }}
""" - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): var = self.inject("my_provide", "default") return {"var": var} @@ -558,7 +557,7 @@ class TestProvideTemplateTag:
second_provide: {{ second_provide|safe }}
""" - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): first_provide = self.inject("first_provide", "default") second_provide = self.inject("second_provide", "default") return { @@ -595,7 +594,7 @@ class TestProvideTemplateTag:
injected: {{ var|safe }}
""" - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): var = self.inject("my_provide", "default") return {"var": var} @@ -626,7 +625,7 @@ class TestProvideTemplateTag:
injected: {{ var|safe }}
""" - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): var = self.inject("my_provide", "default") return {"var": var} @@ -674,7 +673,7 @@ class TestInject:
injected: {{ var|safe }}
""" - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): var = self.inject("my_provide") return {"var": var} @@ -704,7 +703,7 @@ class TestInject:
injected: {{ var|safe }}
""" - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): var = self.inject("abc") return {"var": var} @@ -728,7 +727,7 @@ class TestInject:
injected: {{ var|safe }}
""" - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): var = self.inject("abc", "default") return {"var": var} @@ -755,7 +754,7 @@ class TestInject:
injected: {{ var|safe }}
""" - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): var = self.inject("") return {"var": var} @@ -783,7 +782,7 @@ class TestInject:
injected: {{ var|safe }}
""" - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): var = self.inject("abc", "default") return {"var": var} @@ -806,14 +805,14 @@ class TestInject: """ - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): data = self.inject("my_provide") return {"data": data} @register("provider") class Provider(Component): - def get_context_data(self, data: Any) -> Any: - return {"data": data} + def get_template_data(self, args, kwargs, slots, context): + return {"data": kwargs["data"]} template: types.django_html = """ {% load component_tags %} @@ -824,8 +823,8 @@ class TestInject: @register("parent") class Parent(Component): - def get_context_data(self, data: Any) -> Any: - return {"data": data} + def get_template_data(self, args, kwargs, slots, context): + return {"data": kwargs["data"]} template: types.django_html = """ {% load component_tags %} @@ -875,14 +874,14 @@ class TestInject: """ - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): data = self.inject("my_provide") return {"data": data} @register("provider") class Provider(Component): - def get_context_data(self, data: Any) -> Any: - return {"data": data} + def get_template_data(self, args, kwargs, slots, context): + return {"data": kwargs["data"]} template: types.django_html = """ {% load component_tags %} @@ -893,8 +892,8 @@ class TestInject: @register("parent") class Parent(Component): - def get_context_data(self, data: Any) -> Any: - return {"data": data} + def get_template_data(self, args, kwargs, slots, context): + return {"data": kwargs["data"]} template: types.django_html = """ {% load component_tags %} @@ -949,7 +948,7 @@ class TestProvideCache:
Ran: {{ ran }}
""" - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): assert len(provide_cache) == 1 data = self.inject("my_provide") @@ -989,7 +988,7 @@ class TestProvideCache: class Injectee(Component): template = "" - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): assert len(provide_cache) == 1 data = self.inject("my_provide") @@ -1022,7 +1021,7 @@ class TestProvideCache:
Ran: {{ ran }}
""" - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): assert len(provide_cache) == 1 data = self.inject("my_provide") @@ -1059,7 +1058,7 @@ class TestProvideCache: class Injectee(Component): template = "" - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): assert len(provide_cache) == 1 data = self.inject("my_provide") diff --git a/tests/test_templatetags_slot_fill.py b/tests/test_templatetags_slot_fill.py index 9b270094..121dcac5 100644 --- a/tests/test_templatetags_slot_fill.py +++ b/tests/test_templatetags_slot_fill.py @@ -1,5 +1,5 @@ import re -from typing import Any, Dict, List, Optional +from typing import Dict import pytest from django.template import Context, Template, TemplateSyntaxError @@ -40,10 +40,10 @@ class TestComponentSlot: class SimpleComponent(Component): template = """Variable: {{ variable }}""" - def get_context_data(self, variable, variable2="default"): + def get_template_data(self, args, kwargs, slots, context): return { - "variable": variable, - "variable2": variable2, + "variable": kwargs["variable"], + "variable2": kwargs.get("variable2", "default"), } class Media: @@ -96,10 +96,10 @@ class TestComponentSlot: class SimpleComponent(Component): template = """Variable: {{ variable }}""" - def get_context_data(self, variable, variable2="default"): + def get_template_data(self, args, kwargs, slots, context): return { - "variable": variable, - "variable2": variable2, + "variable": kwargs["variable"], + "variable2": kwargs.get("variable2", "default"), } template_str: types.django_html = """ @@ -152,8 +152,8 @@ class TestComponentSlot: """ - def get_context_data(self, variable): - return {"variable": variable} + def get_template_data(self, args, kwargs, slots, context): + return {"variable": kwargs["variable"]} template_str: types.django_html = """ {% load component_tags %} @@ -294,9 +294,9 @@ class TestComponentSlot:
""" - def get_context_data(self, name: Optional[str] = None) -> Dict[str, Any]: + def get_template_data(self, args, kwargs, slots, context): return { - "name": name, + "name": kwargs.get("name", None), } registry.register("test", SlottedComponent) @@ -451,8 +451,8 @@ class TestComponentSlot: @djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR) def test_multiple_slots_with_same_name_different_flags(self, components_settings): class TestComp(Component): - def get_context_data(self, required: bool) -> Any: - return {"required": required} + def get_template_data(self, args, kwargs, slots, context): + return {"required": kwargs["required"]} template: types.django_html = """ {% load component_tags %} @@ -824,8 +824,8 @@ class TestComponentSlotDefault: def test_implicit_fill_when_slot_marked_default_not_rendered(self, components_settings): @register("test_comp") class ConditionalSlotted(Component): - def get_context_data(self, var: bool) -> Any: - return {"var": var} + def get_template_data(self, args, kwargs, slots, context): + return {"var": kwargs["var"]} template: types.django_html = """ {% load component_tags %} @@ -885,9 +885,9 @@ class TestPassthroughSlots: """ - def get_context_data(self, name: Optional[str] = None) -> Dict[str, Any]: + def get_template_data(self, args, kwargs, slots, context): return { - "name": name, + "name": kwargs.get("name", None), } template_str: types.django_html = """ @@ -941,9 +941,9 @@ class TestPassthroughSlots: """ - def get_context_data(self, name: Optional[str] = None) -> Dict[str, Any]: + def get_template_data(self, args, kwargs, slots, context): return { - "name": name, + "name": kwargs.get("name", None), } template_str: types.django_html = """ @@ -985,9 +985,9 @@ class TestPassthroughSlots: """ - def get_context_data(self, name: Optional[str] = None) -> Dict[str, Any]: + def get_template_data(self, args, kwargs, slots, context): return { - "name": name, + "name": kwargs.get("name", None), } template_str: types.django_html = """ @@ -1021,7 +1021,7 @@ class TestPassthroughSlots: def test_slots_inside_loops(self, components_settings): @register("test_comp") class OuterComp(Component): - def get_context_data(self, name: Optional[str] = None) -> Dict[str, Any]: + def get_template_data(self, args, kwargs, slots, context): return { "slots": ["header", "main", "footer"], } @@ -1064,7 +1064,7 @@ class TestPassthroughSlots: @register("test_comp") class OuterComp(Component): - def get_context_data(self, name: Optional[str] = None) -> Dict[str, Any]: + def get_template_data(self, args, kwargs, slots, context): return { "slots": self.input.slots, } @@ -1115,7 +1115,7 @@ class TestPassthroughSlots: @register("test_comp") class OuterComp(Component): - def get_context_data(self, name: Optional[str] = None) -> Dict[str, Any]: + def get_template_data(self, args, kwargs, slots, context): return { "slots": self.input.slots, } @@ -1510,7 +1510,7 @@ class TestScopedSlot: """ - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): return { "abc": "def", "var123": 456, @@ -1545,7 +1545,7 @@ class TestScopedSlot: """ - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): return { "abc": "def", "var123": 456, @@ -1580,7 +1580,7 @@ class TestScopedSlot: """ - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): return { "abc": "def", "var123": 456, @@ -1617,7 +1617,7 @@ class TestScopedSlot: """ - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): return { "slot_name": "my_slot", "abc": "def", @@ -1653,7 +1653,7 @@ class TestScopedSlot: """ - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): return { "slot_props": { "name": "my_slot", @@ -1692,7 +1692,7 @@ class TestScopedSlot: """ - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): return { "abc": "xyz", "var123": 456, @@ -1728,7 +1728,7 @@ class TestScopedSlot: """ - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): return { "abc": "def", "var123": 456, @@ -1759,7 +1759,7 @@ class TestScopedSlot: """ - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): return { "abc": "def", "var123": 456, @@ -1811,7 +1811,7 @@ class TestScopedSlot: """ - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): return { "abc": "def", "var123": 456, @@ -1837,7 +1837,7 @@ class TestScopedSlot: """ - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): return { "abc": "def", "var123": 456, @@ -1880,7 +1880,7 @@ class TestScopedSlot: """ - def get_context_data(self): + def get_template_data(self, args, kwargs, slots, context): return { "abc": "def", "var123": 456, @@ -1925,10 +1925,10 @@ class TestScopedSlot: """ - def get_context_data(self, input): + def get_template_data(self, args, kwargs, slots, context): return { "abc": "def", - "input": input, + "input": kwargs["input"], } template_str: types.django_html = """ @@ -1974,9 +1974,9 @@ class TestDuplicateSlot: """ - def get_context_data(self, name: Optional[str] = None) -> Dict[str, Any]: + def get_template_data(self, args, kwargs, slots, context): return { - "name": name, + "name": kwargs.get("name", None), } return DuplicateSlotComponent @@ -2001,9 +2001,9 @@ class TestDuplicateSlot: """ - def get_context_data(self, items: List) -> Dict[str, Any]: + def get_template_data(self, args, kwargs, slots, context): return { - "items": items, + "items": kwargs["items"], } return DuplicateSlotNestedComponent @@ -2243,9 +2243,9 @@ class TestSlotBehavior: """ - def get_context_data(self, name: Optional[str] = None) -> Dict[str, Any]: + def get_template_data(self, args, kwargs, slots, context): return { - "name": name, + "name": kwargs.get("name", None), } registry.register("test", SlottedComponent) @@ -2360,7 +2360,7 @@ class TestSlotBehavior: class TestSlotInput: @djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR) def test_slots_accessible_when_python_render(self, components_settings): - slots: Dict = {} + seen_slots: Dict = {} @register("test") class SlottedComponent(Component): @@ -2371,12 +2371,12 @@ class TestSlotInput: """ - def get_context_data(self, input: Optional[int] = None) -> Dict[str, Any]: - nonlocal slots - slots = self.input.slots + def get_template_data(self, args, kwargs, slots, context): + nonlocal seen_slots + seen_slots = slots return {} - assert slots == {} + assert seen_slots == {} template_str: types.django_html = """ {% load component_tags %} @@ -2390,14 +2390,14 @@ class TestSlotInput: template = Template(template_str) template.render(Context()) - assert list(slots.keys()) == ["header", "main"] - assert callable(slots["header"]) - assert callable(slots["main"]) - assert "footer" not in slots + assert list(seen_slots.keys()) == ["header", "main"] + assert callable(seen_slots["header"]) + assert callable(seen_slots["main"]) + assert "footer" not in seen_slots @djc_test(parametrize=PARAMETRIZE_CONTEXT_BEHAVIOR) def test_slots_normalized_as_slot_instances(self, components_settings): - slots: Dict[str, Slot] = {} + seen_slots: Dict[str, Slot] = {} @register("test") class SlottedComponent(Component): @@ -2408,12 +2408,12 @@ class TestSlotInput: """ - def get_context_data(self, input: Optional[int] = None) -> Dict[str, Any]: - nonlocal slots - slots = self.input.slots + def get_template_data(self, args, kwargs, slots, context): + nonlocal seen_slots + seen_slots = slots return {} - assert slots == {} + assert seen_slots == {} header_slot = Slot(lambda *a, **kw: "HEADER_SLOT") main_slot_str = "MAIN_SLOT" @@ -2427,11 +2427,11 @@ class TestSlotInput: } ) - assert isinstance(slots["header"], Slot) - assert slots["header"](Context(), None, None) == "HEADER_SLOT" # type: ignore[arg-type] + assert isinstance(seen_slots["header"], Slot) + assert seen_slots["header"](Context(), None, None) == "HEADER_SLOT" # type: ignore[arg-type] - assert isinstance(slots["main"], Slot) - assert slots["main"](Context(), None, None) == "MAIN_SLOT" # type: ignore[arg-type] + assert isinstance(seen_slots["main"], Slot) + assert seen_slots["main"](Context(), None, None) == "MAIN_SLOT" # type: ignore[arg-type] - assert isinstance(slots["footer"], Slot) - assert slots["footer"](Context(), None, None) == "FOOTER_SLOT" # type: ignore[arg-type] + assert isinstance(seen_slots["footer"], Slot) + assert seen_slots["footer"](Context(), None, None) == "FOOTER_SLOT" # type: ignore[arg-type] diff --git a/tests/test_templatetags_templating.py b/tests/test_templatetags_templating.py index 3ec6a120..c78f9749 100644 --- a/tests/test_templatetags_templating.py +++ b/tests/test_templatetags_templating.py @@ -1,7 +1,5 @@ """This file tests various ways how the individual tags can be combined inside the templates""" -from typing import Any, Dict, Optional - from django.template import Context, Template from pytest_django.asserts import assertHTMLEqual @@ -103,9 +101,9 @@ class TestNestedSlot: """ - def get_context_data(self, name: Optional[str] = None) -> Dict[str, Any]: + def get_template_data(self, args, kwargs, slots, context): return { - "name": name, + "name": kwargs.get("name", None), } registry.clear() @@ -168,8 +166,8 @@ class TestConditionalSlot: {% endif %} """ - def get_context_data(self, branch=None): - return {"branch": branch} + def get_template_data(self, args, kwargs, slots, context): + return {"branch": kwargs.get("branch", None)} return ConditionalComponent @@ -267,9 +265,9 @@ class TestSlotIteration: {% endfor %} """ - def get_context_data(self, objects, *args, **kwargs) -> dict: + def get_template_data(self, args, kwargs, slots, context): return { - "objects": objects, + "objects": kwargs["objects"], } return ComponentSimpleSlotInALoop @@ -303,7 +301,7 @@ class TestSlotIteration: assertHTMLEqual(rendered, expected) # NOTE: Second arg in tuple is expected result. In isolated mode, while loops should NOT leak, - # we should still have access to root context (returned from get_context_data) + # we should still have access to root context (returned from get_template_data) @djc_test( parametrize=( ["components_settings", "expected"], @@ -376,7 +374,7 @@ class TestSlotIteration: assertHTMLEqual(rendered, expected) # NOTE: Second arg in tuple is expected result. In isolated mode, while loops should NOT leak, - # we should still have access to root context (returned from get_context_data) + # we should still have access to root context (returned from get_template_data) @djc_test( parametrize=( ["components_settings", "expected"], @@ -662,9 +660,9 @@ class TestComponentNesting: """ - def get_context_data(self, name: Optional[str] = None) -> Dict[str, Any]: + def get_template_data(self, args, kwargs, slots, context): return { - "name": name, + "name": kwargs.get("name", None), } registry.register("test", SlottedComponent) @@ -817,8 +815,8 @@ class TestComponentNesting: {% endfor %} """ - def get_context_data(self, items, *args, **kwargs) -> Dict[str, Any]: - return {"items": items} + def get_template_data(self, args, kwargs, slots, context): + return {"items": kwargs["items"]} template_str: types.django_html = """ {% load component_tags %}