diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 784cf69d..3ff02078 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -11,4 +11,4 @@ repos: rev: 7.0.0 hooks: - id: flake8 - + additional_dependencies: [flake8-pyproject] diff --git a/README.md b/README.md index 0dae5fab..ad42a5aa 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ A way to create simple reusable template components in Django. It lets you create "template components", that contains both the template, the Javascript and the CSS needed to generate the front end code you need for a modern app. Components look like this: ```htmldjango -{% component "calendar" date="2015-06-19" %} +{% component "calendar" date="2015-06-19" %}{% endcomponent %} ``` And this is what gets rendered (plus the CSS and Javascript you've specified): @@ -20,17 +20,21 @@ Read on to learn about the details! ## Release notes -*Version 0.34* adds components as views, which allows you to handle requests and render responses from within a component. See the [documentation](#components-as-views) for more details. +🚨📢 **Version 0.5** CHANGES THE SYNTAX for components. `component_block` is now `component`, and `component` blocks need an ending `endcomponent` tag. The new `python manage.py upgradecomponent` command can be used to upgrade a directory (use --path argument to point to each dir) of components to the new syntax automatically. -*Version 0.28* introduces 'implicit' slot filling and the `default` option for `slot` tags. +This change is done to simplify the API in anticipation of a 1.0 release of django_components. After 1.0 we intend to be stricter with big changes like this in point releases. -*Version 0.27* adds a second installable app: *django_components.safer_staticfiles*. It provides the same behavior as *django.contrib.staticfiles* but with extra security guarantees (more info below in Security Notes). +**Version 0.34** adds components as views, which allows you to handle requests and render responses from within a component. See the [documentation](#components-as-views) for more details. -*Version 0.26* changes the syntax for `{% slot %}` tags. From now on, we separate defining a slot (`{% slot %}`) from filling a slot with content (`{% fill %}`). This means you will likely need to change a lot of slot tags to fill. We understand this is annoying, but it's the only way we can get support for nested slots that fill in other slots, which is a very nice feature to have access to. Hoping that this will feel worth it! +**Version 0.28** introduces 'implicit' slot filling and the `default` option for `slot` tags. -*Version 0.22* starts autoimporting all files inside components subdirectores, to simplify setup. An existing project might start to get AlreadyRegistered-errors because of this. To solve this, either remove your custom loading of components, or set "autodiscover": False in settings.COMPONENTS. +**Version 0.27** adds a second installable app: *django_components.safer_staticfiles*. It provides the same behavior as *django.contrib.staticfiles* but with extra security guarantees (more info below in Security Notes). -*Version 0.17* renames `Component.context` and `Component.template` to `get_context_data` and `get_template_name`. The old methods still work, but emit a deprecation warning. This change was done to sync naming with Django's class based views, and make using django-components more familiar to Django users. `Component.context` and `Component.template` will be removed when version 1.0 is released. +**Version 0.26** changes the syntax for `{% slot %}` tags. From now on, we separate defining a slot (`{% slot %}`) from filling a slot with content (`{% fill %}`). This means you will likely need to change a lot of slot tags to fill. We understand this is annoying, but it's the only way we can get support for nested slots that fill in other slots, which is a very nice featuPpre to have access to. Hoping that this will feel worth it! + +**Version 0.22** starts autoimporting all files inside components subdirectores, to simplify setup. An existing project might start to get AlreadyRegistered-errors because of this. To solve this, either remove your custom loading of components, or set "autodiscover": False in settings.COMPONENTS. + +**Version 0.17** renames `Component.context` and `Component.template` to `get_context_data` and `get_template_name`. The old methods still work, but emit a deprecation warning. This change was done to sync naming with Django's class based views, and make using django-components more familiar to Django users. `Component.context` and `Component.template` will be removed when version 1.0 is released. ## Security notes 🚨 @@ -220,7 +224,7 @@ First load the `component_tags` tag library, then use the `component_[js/css]_de {% component_css_dependencies %}
- {% component "calendar" date="2015-06-19" %} + {% component "calendar" date="2015-06-19" %}{% endcomponent %} {% component_js_dependencies %} @@ -300,7 +304,7 @@ This mechanism makes components more reusable and composable. In the example below we introduce two block tags that work hand in hand to make this work. These are... - `{% slotvalue=1;calls=1
', rendered - ) + self.assertEqual(rendered, 'value=1;calls=1
', rendered) def test_one_context_call_with_simple_component_and_arg(self): - template = Template( - "{% load component_tags %}{% component name='incrementer' value='2' %}" - ) + template = Template("{% load component_tags %}{% component name='incrementer' value='2' %}{% endcomponent %}") rendered = template.render(Context()).strip() - self.assertEqual( - rendered, 'value=3;calls=1
', rendered - ) + self.assertEqual(rendered, 'value=3;calls=1
', rendered) - def test_one_context_call_with_component_block(self): - template = Template( - "{% load component_tags %}" - "{% component_block 'incrementer' %}{% endcomponent_block %}" - ) + def test_one_context_call_with_component(self): + template = Template("{% load component_tags %}" "{% component 'incrementer' %}{% endcomponent %}") rendered = template.render(Context()).strip() - self.assertEqual( - rendered, 'value=1;calls=1
', rendered - ) + self.assertEqual(rendered, 'value=1;calls=1
', rendered) - def test_one_context_call_with_component_block_and_arg(self): - template = Template( - "{% load component_tags %}" - "{% component_block 'incrementer' value='3' %}{% endcomponent_block %}" - ) + def test_one_context_call_with_component_and_arg(self): + template = Template("{% load component_tags %}" "{% component 'incrementer' value='3' %}{% endcomponent %}") rendered = template.render(Context()).strip() - self.assertEqual( - rendered, 'value=4;calls=1
', rendered - ) + self.assertEqual(rendered, 'value=4;calls=1
', rendered) def test_one_context_call_with_slot(self): template = Template( "{% load component_tags %}" - "{% component_block 'incrementer' %}{% fill 'content' %}" - "slot
{% endfill %}{% endcomponent_block %}" + "{% component 'incrementer' %}{% fill 'content' %}" + "slot
{% endfill %}{% endcomponent %}" ) rendered = template.render(Context()).strip() @@ -389,8 +281,8 @@ class ContextCalledOnceTests(SimpleTestCase): def test_one_context_call_with_slot_and_arg(self): template = Template( "{% load component_tags %}" - "{% component_block 'incrementer' value='3' %}{% fill 'content' %}" - "slot
{% endfill %}{% endcomponent_block %}" + "{% component 'incrementer' value='3' %}{% fill 'content' %}" + "slot
{% endfill %}{% endcomponent %}" ) rendered = template.render(Context()).strip() @@ -405,11 +297,9 @@ class ComponentsCanAccessOuterContext(SimpleTestCase): def test_simple_component_can_use_outer_context(self): template = Template( "{% load component_tags %}{% component_dependencies %}" - "{% component 'simple_component' %}" + "{% component 'simple_component' %}{% endcomponent %}" ) - rendered = template.render( - Context({"variable": "outer_value"}) - ).strip() + rendered = template.render(Context({"variable": "outer_value"})).strip() self.assertIn("outer_value", rendered, rendered) @@ -417,21 +307,17 @@ class IsolatedContextTests(SimpleTestCase): def test_simple_component_can_pass_outer_context_in_args(self): template = Template( "{% load component_tags %}{% component_dependencies %}" - "{% component 'simple_component' variable only %}" + "{% component 'simple_component' variable only %}{% endcomponent %}" ) - rendered = template.render( - Context({"variable": "outer_value"}) - ).strip() + rendered = template.render(Context({"variable": "outer_value"})).strip() self.assertIn("outer_value", rendered, rendered) def test_simple_component_cannot_use_outer_context(self): template = Template( "{% load component_tags %}{% component_dependencies %}" - "{% component 'simple_component' only %}" + "{% component 'simple_component' only %}{% endcomponent %}" ) - rendered = template.render( - Context({"variable": "outer_value"}) - ).strip() + rendered = template.render(Context({"variable": "outer_value"})).strip() self.assertNotIn("outer_value", rendered, rendered) @@ -452,7 +338,7 @@ class IsolatedContextSettingTests(SimpleTestCase): ): template = Template( "{% load component_tags %}{% component_dependencies %}" - "{% component 'simple_component' variable %}" + "{% component 'simple_component' variable %}{% endcomponent %}" ) rendered = template.render(Context({"variable": "outer_value"})) self.assertIn("outer_value", rendered, rendered) @@ -462,29 +348,29 @@ class IsolatedContextSettingTests(SimpleTestCase): ): template = Template( "{% load component_tags %}{% component_dependencies %}" - "{% component 'simple_component' %}" + "{% component 'simple_component' %}{% endcomponent %}" ) rendered = template.render(Context({"variable": "outer_value"})) self.assertNotIn("outer_value", rendered, rendered) - def test_component_block_includes_variable_with_isolated_context_from_settings( + def test_component_includes_variable_with_isolated_context_from_settings( self, ): template = Template( "{% load component_tags %}{% component_dependencies %}" - "{% component_block 'simple_component' variable %}" - "{% endcomponent_block %}" + "{% component 'simple_component' variable %}" + "{% endcomponent %}" ) rendered = template.render(Context({"variable": "outer_value"})) self.assertIn("outer_value", rendered, rendered) - def test_component_block_excludes_variable_with_isolated_context_from_settings( + def test_component_excludes_variable_with_isolated_context_from_settings( self, ): template = Template( "{% load component_tags %}{% component_dependencies %}" - "{% component_block 'simple_component' %}" - "{% endcomponent_block %}" + "{% component 'simple_component' %}" + "{% endcomponent %}" ) rendered = template.render(Context({"variable": "outer_value"})) self.assertNotIn("outer_value", rendered, rendered) @@ -494,19 +380,7 @@ class OuterContextPropertyTests(SimpleTestCase): def test_outer_context_property_with_component(self): template = Template( "{% load component_tags %}{% component_dependencies %}" - "{% component 'outer_context_component' only %}" + "{% component 'outer_context_component' only %}{% endcomponent %}" ) - rendered = template.render( - Context({"variable": "outer_value"}) - ).strip() - self.assertIn("outer_value", rendered, rendered) - - def test_outer_context_property_with_component_block(self): - template = Template( - "{% load component_tags %}{% component_dependencies %}" - "{% component_block 'outer_context_component' only %}{% endcomponent_block %}" - ) - rendered = template.render( - Context({"variable": "outer_value"}) - ).strip() + rendered = template.render(Context({"variable": "outer_value"})).strip() self.assertIn("outer_value", rendered, rendered) diff --git a/tests/test_dependency_rendering.py b/tests/test_dependency_rendering.py index 74a647f3..b91ce8be 100644 --- a/tests/test_dependency_rendering.py +++ b/tests/test_dependency_rendering.py @@ -52,9 +52,7 @@ class ComponentMediaRenderingTests(SimpleTestCase): def test_no_dependencies_when_no_components_used(self): component.registry.register(name="test", component=SimpleComponent) - template = Template( - "{% load component_tags %}{% component_dependencies %}" - ) + template = Template("{% load component_tags %}{% component_dependencies %}") rendered = create_and_process_template_response(template) self.assertInHTML('