Skip to content

Commit

Permalink
chore: Type hint all the things
Browse files Browse the repository at this point in the history
  • Loading branch information
marksweb committed Oct 26, 2023
1 parent b353fca commit 7abf719
Show file tree
Hide file tree
Showing 13 changed files with 114 additions and 80 deletions.
2 changes: 1 addition & 1 deletion .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,5 @@ Use 'x' to check each item: [x] I have ...
* [ ] I have opened this pull request against ``master``
* [ ] I have added or modified the tests when changing logic
* [ ] I have followed [the conventional commits guidelines](https://www.conventionalcommits.org/) to add meaningful information into the changelog
* [ ] I have read the [contribution guidelines ](https://github.com/django-cms/django-cms/blob/develop/CONTRIBUTING.rst) and I have joined #workgroup-pr-review on
* [ ] I have read the [contribution guidelines ](https://github.com/django-cms/django-cms/blob/develop/CONTRIBUTING.rst) and I have joined #workgroup-pr-review on
[Slack](https://www.django-cms.org/slack) to find a “pr review buddy” who is going to review my pull request.
20 changes: 12 additions & 8 deletions aldryn_config.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from typing import Any

from aldryn_client import forms


Expand All @@ -11,16 +13,18 @@ class Form(forms.BaseForm):
required=False,
)
enable_search = forms.CheckboxField(
'Enable snippet content to be searchable.',
"Enable snippet content to be searchable.",
required=False,
initial=False,
)

def to_settings(self, data, settings):
if data['editor_theme']:
settings['DJANGOCMS_SNIPPET_THEME'] = data['editor_theme']
if data['editor_mode']:
settings['DJANGOCMS_SNIPPET_MODE'] = data['editor_mode']
if data['enable_search']:
settings['DJANGOCMS_SNIPPET_SEARCH'] = data['enable_search']
def to_settings(
self, data: dict[str, Any], settings: dict[str, Any]
) -> dict[str, Any]:
if data["editor_theme"]:
settings["DJANGOCMS_SNIPPET_THEME"] = data["editor_theme"]
if data["editor_mode"]:
settings["DJANGOCMS_SNIPPET_MODE"] = data["editor_mode"]
if data["enable_search"]:
settings["DJANGOCMS_SNIPPET_SEARCH"] = data["enable_search"]
return settings
3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,9 @@ ignore = [
"__init__.py" = [
"F401" # unused-import
]
"snippet_tags.py" = [
"FBT001" # Boolean positional arg in function definition
]

[tool.ruff.isort]
combine-as-imports = true
Expand Down
2 changes: 1 addition & 1 deletion src/djangocms_snippet/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class Media:

list_display = ("slug", "name")
search_fields: ClassVar[list[str]] = ["slug", "name"]
prepopulated_fields: ClassVar[dict[str, list[str]]] = {"slug": ("name",)}
prepopulated_fields: ClassVar[dict[str, tuple[str]]] = {"slug": ("name",)}
change_form_template = "djangocms_snippet/admin/change_form.html"
text_area_attrs: ClassVar[dict[str, Any]] = {
"rows": 20,
Expand Down
11 changes: 10 additions & 1 deletion src/djangocms_snippet/cms_plugins.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
from typing import Any

from cms.models import Placeholder
from cms.plugin_base import CMSPluginBase
from cms.plugin_pool import plugin_pool
from django import template
from django.conf import settings
from django.template.context import BaseContext
from django.utils.html import escape
from django.utils.safestring import mark_safe
from django.utils.translation import gettext_lazy as _
Expand All @@ -19,7 +23,12 @@ class SnippetPlugin(CMSPluginBase):
text_editor_preview = False
cache = CACHE_ENABLED

def render(self, context, instance, placeholder):
def render(
self,
context: BaseContext,
instance: SnippetPtr,
placeholder: Placeholder,
) -> dict[str, Any]:
try:
if instance.snippet.template:
context = context.flatten()
Expand Down
11 changes: 7 additions & 4 deletions src/djangocms_snippet/migrations/0003_auto_data_fill_slug.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
from collections import Counter
import typing

from django.db import migrations, models
from django.db import migrations
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
from django.db.migrations.state import StateApps
from django.utils.text import slugify


def auto_fill_slugs(apps, schema_editor):
def auto_fill_slugs(apps: StateApps, schema_editor: BaseDatabaseSchemaEditor) -> None:
"""
Go through every snippet to fill them a slug if not any
"""
Snippet = apps.get_model("djangocms_snippet", "Snippet")
SlugCounter = Counter()
SlugCounter: typing.Counter[str] = Counter()
for snippet_item in Snippet.objects.all(): # pragma: no cover
if not snippet_item.slug:
snippet_item.slug = slugify(snippet_item.name)
# Avoid duplicate slug, adding slug occurence count to the slug
# Avoid duplicate slug, adding slug occurrence count to the slug
if snippet_item.slug in SlugCounter:
snippet_item.slug = f"{snippet_item.slug}-{str(SlugCounter[snippet_item.slug])}"
SlugCounter[snippet_item.slug] += 1
Expand Down
4 changes: 2 additions & 2 deletions src/djangocms_snippet/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class Meta:
verbose_name = _("Snippet")
verbose_name_plural = _("Snippets")

def __str__(self):
def __str__(self) -> str:
return self.name


Expand Down Expand Up @@ -77,6 +77,6 @@ class Meta:
verbose_name = _("Snippet Ptr")
verbose_name_plural = _("Snippet Ptrs")

def __str__(self):
def __str__(self) -> str:
# Return the referenced snippet's name rather than the default (ID #)
return self.snippet.name
28 changes: 16 additions & 12 deletions src/djangocms_snippet/templatetags/snippet_tags.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
"""
Snippet template tags
"""
from collections.abc import Generator
from contextlib import contextmanager
from typing import Any

from django import template
from django.template.base import Parser, Token
from django.template.context import BaseContext
from django.utils.html import escape
from django.utils.safestring import mark_safe
from django.utils.translation import gettext_lazy as _
Expand All @@ -16,17 +20,19 @@


@contextmanager
def exceptionless(truth):
# Accepts one truth parameter, when 'False' normal behavior
# when 'True' any expection will be suppressed
def exceptionless(truth: bool) -> Generator[None, None, None]:
"""
Accepts one truth parameter, when 'False' normal behavior
when 'True' any exception will be suppressed
"""
try:
yield
except Exception:
if truth:
# WARNING: suppressing exception
pass
else:
# Reraising exception
# Re-raising exception
raise


Expand All @@ -35,7 +41,7 @@ class SnippetFragment(template.Node):
Get a snippet HTML fragment
"""

def __init__(self, snippet_id_varname, *args):
def __init__(self, snippet_id_varname: str, *args: Any):
"""
:type insert_instance_varname: string or object
``django.db.models.Model``
Expand All @@ -53,7 +59,7 @@ def __init__(self, snippet_id_varname, *args):
self.parse_until = True
self.nodelist = args[1]

def render(self, context):
def render(self, context: BaseContext) -> str:
"""
:type context: dict
:param context: Context tag object
Expand All @@ -75,11 +81,9 @@ def render(self, context):
self.get_content_render(context, snippet_instance)
)

# Rely on the fact that manager something went wrong
# render the fallback template
return self.nodelist.render(context)

def get_content_render(self, context, instance):
def get_content_render(
self, context: BaseContext, instance: Snippet
) -> str:
"""
Render the snippet HTML, using a template if defined in its instance
"""
Expand Down Expand Up @@ -113,7 +117,7 @@ def get_content_render(self, context, instance):


@register.tag(name="snippet_fragment")
def do_snippet_fragment(parser, token):
def do_snippet_fragment(parser: Parser, token: Token) -> SnippetFragment:
"""
Display a snippet HTML fragment
Expand Down
25 changes: 14 additions & 11 deletions tests/settings.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,26 @@
#!/usr/bin/env python
HELPER_SETTINGS = {
'INSTALLED_APPS': [
'tests.utils',
"INSTALLED_APPS": [
"tests.utils",
],
'CMS_LANGUAGES': {
1: [{
'code': 'en',
'name': 'English',
}]
"CMS_LANGUAGES": {
1: [
{
"code": "en",
"name": "English",
}
]
},
'LANGUAGE_CODE': 'en',
'ALLOWED_HOSTS': ['localhost'],
"LANGUAGE_CODE": "en",
"ALLOWED_HOSTS": ["localhost"],
}


def run():
from app_helper import runner
runner.cms('djangocms_snippet')

runner.cms("djangocms_snippet")

if __name__ == '__main__':

if __name__ == "__main__":
run()
17 changes: 8 additions & 9 deletions tests/test_migrations.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,23 @@


class MigrationTestCase(TestCase):

@override_settings(MIGRATION_MODULES={})
def test_for_missing_migrations(self):
output = StringIO()
options = {
'interactive': False,
'dry_run': True,
'stdout': output,
'check_changes': True,
"interactive": False,
"dry_run": True,
"stdout": output,
"check_changes": True,
}

try:
call_command('makemigrations', **options)
call_command("makemigrations", **options)
except SystemExit as e:
status_code = str(e)
else:
# the "no changes" exit code is 0
status_code = '0'
status_code = "0"

if status_code == '1':
self.fail('There are missing migrations:\n {}'.format(output.getvalue()))
if status_code == "1":
self.fail(f"There are missing migrations:\n {output.getvalue()}")
1 change: 0 additions & 1 deletion tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@


class SnippetModelTestCase(TestCase):

def setUp(self):
pass

Expand Down
34 changes: 25 additions & 9 deletions tests/test_plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@


class SnippetPluginsTestCase(CMSTestCase):

def setUp(self):
self.language = "en"
self.home = create_page(
Expand All @@ -29,7 +28,9 @@ def tearDown(self):
self.superuser.delete()

def test_html_rendering(self):
request_url = self.page.get_absolute_url(self.language) + "?toolbar_off=true"
request_url = (
self.page.get_absolute_url(self.language) + "?toolbar_off=true"
)
snippet = Snippet.objects.create(
name="plugin_snippet",
html="<p>Hello World</p>",
Expand All @@ -52,7 +53,9 @@ def test_html_rendering(self):
self.assertIn(b"<p>Hello World</p>", response.content)

def test_failing_html_rendering(self):
request_url = self.page.get_absolute_url(self.language) + "?toolbar_off=true"
request_url = (
self.page.get_absolute_url(self.language) + "?toolbar_off=true"
)
snippet = Snippet.objects.create(
name="plugin_snippet",
html="{% import weirdness %}",
Expand All @@ -70,10 +73,14 @@ def test_failing_html_rendering(self):
response = self.client.get(request_url)

self.assertContains(response, "Invalid block tag on line 1")
self.assertContains(response, "Did you forget to register or load this tag?")
self.assertContains(
response, "Did you forget to register or load this tag?"
)

def test_template_rendering(self):
request_url = self.page.get_absolute_url(self.language) + "?toolbar_off=true"
request_url = (
self.page.get_absolute_url(self.language) + "?toolbar_off=true"
)
template = "snippet.html"
snippet = Snippet.objects.create(
name="plugin_snippet",
Expand All @@ -94,13 +101,22 @@ def test_template_rendering(self):
with self.login_user_context(self.superuser):
response = self.client.get(request_url)

self.assertNotIn("Template {} does not exist".format(template).encode(), response.content)
self.assertNotIn(b"context must be a dict rather than Context", response.content)
self.assertNotIn(b"context must be a dict rather than PluginContext", response.content)
self.assertNotIn(
f"Template {template} does not exist".encode(), response.content
)
self.assertNotIn(
b"context must be a dict rather than Context", response.content
)
self.assertNotIn(
b"context must be a dict rather than PluginContext",
response.content,
)
self.assertContains(response, "<p>Hello World Template</p>")

def test_failing_template_rendering(self):
request_url = self.page.get_absolute_url(self.language) + "?toolbar_off=true"
request_url = (
self.page.get_absolute_url(self.language) + "?toolbar_off=true"
)
template = "some_template"
snippet = Snippet.objects.create(
name="plugin_snippet",
Expand Down
Loading

0 comments on commit 7abf719

Please sign in to comment.