From 9e26e51cc414bd1309654cd13140cfa75daa9b1e Mon Sep 17 00:00:00 2001 From: Samy Saad Date: Tue, 28 May 2024 10:55:58 +0200 Subject: [PATCH 1/9] [CHG] Added global context accessibility in template tags Updated tests --- firm_info/factories.py | 32 +++++++++++++- firm_info/templatetags/firm_info.py | 54 +++++++++++++---------- tests/admin.py | 12 ++--- tests/conftest.py | 67 ++++------------------------ tests/constantes.py | 42 ++++++++++++++++++ tests/serializers.py | 35 ++++++++++++--- tests/templatetags.py | 68 +++++++++++++++++++---------- 7 files changed, 193 insertions(+), 117 deletions(-) create mode 100644 tests/constantes.py diff --git a/firm_info/factories.py b/firm_info/factories.py index 72d6384..f2c705a 100644 --- a/firm_info/factories.py +++ b/firm_info/factories.py @@ -7,7 +7,7 @@ import factory from firm_info.models import Tracking -from .models import AppsBanner +from .models import AppsBanner, FirmContact def create_image_file(filename=None, size=(100, 100), color="blue", @@ -104,3 +104,33 @@ def image(self): """ return create_image_file() + + +class FirmContactFactory(factory.django.DjangoModelFactory): + """ + Factory to create instance of a FirmContact. + """ + + phone_number = factory.Faker("phone_number") + email = factory.Faker("email") + address = factory.Faker("address") + postal_code = factory.Faker("postcode") + city = factory.Faker("city") + country = factory.Faker("country") + baseline = factory.Faker("text", max_nb_chars=255) + short_description = factory.Faker("text") + + class Meta: + model = FirmContact + + @factory.lazy_attribute + def logo(self): + return create_image_file() + + @factory.lazy_attribute + def logo_invert(self): + return create_image_file() + + @factory.lazy_attribute + def favicon(self): + return create_image_file() diff --git a/firm_info/templatetags/firm_info.py b/firm_info/templatetags/firm_info.py index 32eacfa..e1423dc 100644 --- a/firm_info/templatetags/firm_info.py +++ b/firm_info/templatetags/firm_info.py @@ -13,8 +13,8 @@ register = Library() -@register.simple_tag(name="firm_contact") -def firm_contact(template_path): +@register.simple_tag(takes_context=True, name="firm_contact") +def firm_contact(context, template_path): """ Renders the template which path is provided as param using FirmContact only instance serialized contact data. @@ -36,15 +36,16 @@ def firm_contact(template_path): qs_firm_info = FirmContact.objects.all() if qs_firm_info.exists(): template = loader.get_template(template_path) - context = serialize_firm_info(qs_firm_info) - rendered = template.render(context) + specific_context = serialize_firm_info(qs_firm_info) + combined_context = {**context.flatten(), **specific_context} + rendered = template.render(combined_context) return rendered else: return '' -@register.simple_tag(name="firm_social_links") -def firm_social_links(template_path): +@register.simple_tag(takes_context=True, name="firm_social_links") +def firm_social_links(context, template_path): """ Renders the template which path is provided as param using all social network link objects serialized data @@ -67,15 +68,16 @@ def firm_social_links(template_path): links = Link.objects.all() if links.exists(): template = loader.get_template(template_path) - context = serialize_firm_social(links) - rendered = template.render(context) + specific_context = serialize_firm_social(links) + combined_context = {**context.flatten(), **specific_context} + rendered = template.render(combined_context) return rendered else: return '' -@register.simple_tag(name="firm_description") -def firm_description(template_path): +@register.simple_tag(takes_context=True, name="firm_description") +def firm_description(context, template_path): """ Renders the template which path is provided as param using FirmContact only instance serialized description data. @@ -97,15 +99,16 @@ def firm_description(template_path): qs_firm_info = FirmContact.objects.all() if qs_firm_info.exists(): template = loader.get_template(template_path) - context = serialize_firm_description(qs_firm_info) - rendered = template.render(context) + specific_context = serialize_firm_description(qs_firm_info) + combined_context = {**context.flatten(), **specific_context} + rendered = template.render(combined_context) return rendered else: return '' -@register.simple_tag(name="firm_logos") -def firm_logos(template_path): +@register.simple_tag(takes_context=True, name="firm_logos") +def firm_logos(context, template_path): """ Renders the firm logos using the specified template. @@ -126,19 +129,20 @@ def firm_logos(template_path): firm_instance = FirmContact.objects.first() if firm_instance: template = loader.get_template(template_path) - context = { + specific_context = { "logo": getattr(firm_instance, "logo", None), "logo_invert": getattr(firm_instance, "logo_invert", None), "favicon": getattr(firm_instance, "favicon", None), } - rendered = template.render(context) + combined_context = {**context.flatten(), **specific_context} + rendered = template.render(combined_context) return rendered else: return '' -@register.simple_tag(name="firm_social_shares") -def firm_social_shares(template_path): +@register.simple_tag(takes_context=True, name="firm_social_shares") +def firm_social_shares(context, template_path): """ Renders the template which path is provided as param using all social network shares link objects serialized data @@ -162,8 +166,9 @@ def firm_social_shares(template_path): if social_shares: template = loader.get_template(template_path) - context = serialize_firm_social_sharing(social_shares) - rendered = template.render(context) + specific_context = serialize_firm_social_sharing(social_shares) + combined_context = {**context.flatten(), **specific_context} + rendered = template.render(combined_context) return rendered else: @@ -193,8 +198,8 @@ def firm_tag_analytic(value=None): return Tracking.objects.first().tag_analytic if Tracking.objects.exists() else "" -@register.simple_tag(name="app_banner") -def app_banner(app_type, template_path): +@register.simple_tag(takes_context=True, name="app_banner") +def app_banner(context, app_type, template_path): """ Renders the app banner using the specified template and application type. @@ -218,7 +223,8 @@ def app_banner(app_type, template_path): with contextlib.suppress(ObjectDoesNotExist): app_banner = AppsBanner.objects.get(application_type=app_type) - context = serialize_firm_apps_banner(app_banner) - rendered = template.render(context) + specific_context = serialize_firm_apps_banner(app_banner) + combined_context = {**context.flatten(), **specific_context} + rendered = template.render(combined_context) return rendered diff --git a/tests/admin.py b/tests/admin.py index ad04517..a7d0c95 100644 --- a/tests/admin.py +++ b/tests/admin.py @@ -5,6 +5,8 @@ from firm_info.models import FirmContact from tests.utils import get_admin_add_url +from .constantes import RAW_CONTACT + User = get_user_model() @@ -23,7 +25,7 @@ def admin_client(client, admin_user): return client -def test_firm_contact_create(db, admin_client, raw_contact): +def test_firm_contact_create(db, admin_client): # Check that admin client can access the admin interface url = reverse("admin:index") response = admin_client.get(url) @@ -35,11 +37,11 @@ def test_firm_contact_create(db, admin_client, raw_contact): assert response.status_code == 200 # needed for post in admin chg - raw_contact.update({ + RAW_CONTACT.update({ "link_set-TOTAL_FORMS": 1, "link_set-INITIAL_FORMS": 0 }) - response = admin_client.post(url, raw_contact) + response = admin_client.post(url, RAW_CONTACT) assert response.status_code == 302 # Check that the FirmContact instance was created @@ -55,11 +57,11 @@ def test_firm_contact_create(db, admin_client, raw_contact): ) assert qs_firm_contact_values is not None assert all(( - item in raw_contact.items() + item in RAW_CONTACT.items() for item in qs_firm_contact_values[0].items() )) # Check that the admin can't create another instance - response = admin_client.post(url, raw_contact) + response = admin_client.post(url, RAW_CONTACT) assert response.status_code == 403 assert FirmContact.objects.filter().count() == 1 diff --git a/tests/conftest.py b/tests/conftest.py index 8df74d7..b394eea 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,67 +1,18 @@ import pytest -from firm_info.models import FirmContact, Link +from firm_info.factories import FirmContactFactory +from firm_info.models import Link +from .constantes import RAW_SOCIAL_LINKS -@pytest.fixture -def raw_contact(): - return { - "phone_number": "1234567890", - "email": "contact@example.com", - "address": "1234 Main St", - "postal_code": "12345", - "city": "Anytown", - "country": "USA", - "baseline": "Non eram nescius, Brute, cum, quae summis ingeniis", - "short_description": "Quamquam, si plane sic verterem Platonem" - } +@pytest.fixture() +def firm_contact_obj(db): + return FirmContactFactory() -@pytest.fixture -def raw_social_links(): - return [ - {"name": "facebook", "url": "http://facebook.com/example"}, - {"name": "twitter", "url": "http://twitter.com/example"}, - ] - - -@pytest.fixture -def serialized_contact(): - return { - "email": "contact@example.com", - "phone": "1234567890", - 'address': '1234 Main St', - 'city': 'Anytown', - 'country': 'USA', - 'full_address': '1234 Main St, 12345 Anytown USA', - 'postal_code': '12345', - } - - -@pytest.fixture -def serialized_social_links(): - return { - "facebook": "http://facebook.com/example", - "twitter": "http://twitter.com/example", - } - - -@pytest.fixture -def serialized_firm_description(): - return { - "baseline": "Non eram nescius, Brute, cum, quae summis ingeniis", - "short_description": "Quamquam, si plane sic verterem Platonem" - } - - -@pytest.fixture -def firm_contact_obj(raw_contact): - return FirmContact.objects.create(**raw_contact) - - -@pytest.fixture -def firm_social_links_objs(firm_contact_obj, raw_social_links): +@pytest.fixture() +def firm_social_links_objs(db, firm_contact_obj): links = [ - Link(client_contact=firm_contact_obj, **data) for data in raw_social_links + Link(client_contact=firm_contact_obj, **data) for data in RAW_SOCIAL_LINKS ] Link.objects.bulk_create(links) return Link.objects.filter(client_contact=firm_contact_obj) diff --git a/tests/constantes.py b/tests/constantes.py new file mode 100644 index 0000000..1170a26 --- /dev/null +++ b/tests/constantes.py @@ -0,0 +1,42 @@ +RAW_CONTACT = { + "phone_number": "1234567890", + "email": "contact@example.com", + "address": "1234 Main St", + "postal_code": "12345", + "city": "Anytown", + "country": "USA", + "baseline": "Non eram nescius, Brute, cum, quae summis ingeniis", + "short_description": "Quamquam, si plane sic verterem Platonem", + "logo": "", + "logo_invert": "", + "favicon": "", +} + + +RAW_SOCIAL_LINKS = [ + {"name": "facebook", "url": "http://facebook.com/example"}, + {"name": "twitter", "url": "http://twitter.com/example"}, +] + + +SERIALIZED_CONTACT = { + "email": "contact@example.com", + "phone": "1234567890", + 'address': '1234 Main St', + 'city': 'Anytown', + 'country': 'USA', + 'full_address': '1234 Main St, 12345 Anytown USA', + 'postal_code': '12345', +} + + +SERILAIZED_SOCIAL_LINKS = { + "facebook": "http://facebook.com/example", + "twitter": "http://twitter.com/example", +} + + +SERIALIZED_FIRM_DESCRIPTION = { + "baseline": "Non eram nescius, Brute, cum, quae summis ingeniis", + "short_description": "Quamquam, si plane sic verterem Platonem" +} diff --git a/tests/serializers.py b/tests/serializers.py index b3951e6..bce03b5 100644 --- a/tests/serializers.py +++ b/tests/serializers.py @@ -1,24 +1,47 @@ from firm_info.models import FirmContact, Link from firm_info.serializers import ( + _format_address, serialize_firm_description, serialize_firm_info, serialize_firm_social, ) +from .constantes import ( + SERILAIZED_SOCIAL_LINKS +) + -def test_serialize_firm_info(db, firm_contact_obj, serialized_contact): +def test_serialize_firm_info(db, firm_contact_obj): queryset = FirmContact.objects.all() - expected_output = serialized_contact + assert queryset.count() == 1 + expected_output = { + "email": firm_contact_obj.email, + "phone": firm_contact_obj.phone_number, + "address": firm_contact_obj.address, + "city": firm_contact_obj.city, + "country": firm_contact_obj.country, + "full_address": _format_address( + queryset + .values( + "phone_number", "email", "address", "postal_code", "city", "country" + ) + .first() + ), + "postal_code": firm_contact_obj.postal_code, + } assert serialize_firm_info(queryset) == expected_output -def test_serialize_firm_social(db, firm_social_links_objs, serialized_social_links): +def test_serialize_firm_social(db, firm_social_links_objs): queryset = Link.objects.all() - expected_output = serialized_social_links + expected_output = SERILAIZED_SOCIAL_LINKS assert serialize_firm_social(queryset) == expected_output -def test_serialize_firm_description(db, firm_contact_obj, serialized_firm_description): +def test_serialize_firm_description(db, firm_contact_obj): queryset = FirmContact.objects.all() - expected_output = serialized_firm_description + expected_output = { + "baseline": firm_contact_obj.baseline, + "short_description": firm_contact_obj.short_description, + } assert serialize_firm_description(queryset) == expected_output diff --git a/tests/templatetags.py b/tests/templatetags.py index 09cf19d..c039b3c 100644 --- a/tests/templatetags.py +++ b/tests/templatetags.py @@ -1,5 +1,7 @@ +from django.test import RequestFactory import pytest -from django.template import Context, Template + +from django.template import RequestContext, Template from firm_info.models import FirmContact, Link from firm_info.factories import TrackingFactory from firm_info.templatetags.firm_info import ( @@ -9,50 +11,67 @@ firm_tag_analytic, ) +from .constantes import SERILAIZED_SOCIAL_LINKS + -def test_firm_contact_tag(db, firm_contact_obj, serialized_contact): +def test_firm_contact_tag(db, firm_contact_obj): template_path = "tests/templatetags/firm_info/test_firm_contact.html" - context = Context() + + request = RequestFactory().get('/') + context = RequestContext(request) + context["firm"] = firm_contact_obj - output = firm_contact(template_path) + output = firm_contact(context, template_path) template = Template(output) rendered = template.render(context) expected_output = "\n".join([ - f"

Email: {serialized_contact['email']}

", - f"

Phone: {serialized_contact['phone']}

", - f"

Full address: {serialized_contact['full_address']}

", - f"

Address: {serialized_contact['address']}

", - f"

city: {serialized_contact['city']}

", - f"

postal code: {serialized_contact['postal_code']}

", - f"

country: {serialized_contact['country']}

" + "

Email: {}

".format(firm_contact_obj.email), + "

Phone: {}

".format(firm_contact_obj.phone_number), + "

Full address: {}, {} {} {}

".format( + firm_contact_obj.address, + firm_contact_obj.postal_code, + firm_contact_obj.city, + firm_contact_obj.country, + ), + "

Address: {}

".format(firm_contact_obj.address), + "

city: {}

".format(firm_contact_obj.city), + "

postal code: {}

".format(firm_contact_obj.postal_code), + "

country: {}

".format(firm_contact_obj.country) ]) assert rendered == expected_output -def test_firm_social_links_tag(db, firm_social_links_objs, serialized_social_links): +def test_firm_social_links_tag(db, firm_social_links_objs): template_path = "tests/templatetags/firm_info/test_links.html" - context = Context() + + request = RequestFactory().get('/') + context = RequestContext(request) + context["links"] = firm_social_links_objs - output = firm_social_links(template_path) + output = firm_social_links(context, template_path) template = Template(output) rendered = template.render(context) expected_output = "\n".join([ - f"facebook
", - f"twitter
" + f"facebook
", + f"twitter
" ]) assert rendered == expected_output -def test_firm_description_tag(db, firm_contact_obj, serialized_firm_description): +def test_firm_description_tag(firm_contact_obj): template_path = "tests/templatetags/firm_info/test_firm_description.html" - context = Context() + + factory = RequestFactory() + request = factory.get('/') + context = RequestContext(request) + context["description"] = firm_contact_obj - output = firm_description(template_path) + output = firm_description(context, template_path) template = Template(output) rendered = template.render(context) expected_output = "\n".join([ - f"

Baseline: {serialized_firm_description['baseline']}

", - f"

Short_description: {serialized_firm_description['short_description']}

", + f"

Baseline: {firm_contact_obj.baseline}

", + f"

Short_description: {firm_contact_obj.short_description}

", ]) assert rendered == expected_output @@ -67,9 +86,12 @@ def test_firm_description_tag(db, firm_contact_obj, serialized_firm_description) ) def test_not_rendered_without_objs(db, template_path, Model): template_path = template_path - context = Context() + + request = RequestFactory().get('/') + context = RequestContext(request) + context["firm"] = Model.objects.none() - output = firm_contact(template_path) + output = firm_contact(context, template_path) template = Template(output) rendered = template.render(context) assert rendered == "" From 147a3d224f1a5e3968e657914e67e1ac3011799c Mon Sep 17 00:00:00 2001 From: Samy Saad Date: Tue, 28 May 2024 10:56:30 +0200 Subject: [PATCH 2/9] [DOC] Added exceptions and manager documentation --- docs/firm_info/exceptions.rst | 9 +++++++++ docs/firm_info/index.rst | 4 ++++ docs/firm_info/managers.rst | 9 +++++++++ docs/firm_info/serializers.rst | 2 +- 4 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 docs/firm_info/exceptions.rst create mode 100644 docs/firm_info/managers.rst diff --git a/docs/firm_info/exceptions.rst b/docs/firm_info/exceptions.rst new file mode 100644 index 0000000..68213e8 --- /dev/null +++ b/docs/firm_info/exceptions.rst @@ -0,0 +1,9 @@ +.. _intro_firm-info_exceptions: + +========== +Exceptions +========== + +.. automodule:: firm_info.exceptions + :members: SerializeFirmError + :exclude-members: MyAppBaseException \ No newline at end of file diff --git a/docs/firm_info/index.rst b/docs/firm_info/index.rst index 7746d92..19fa759 100644 --- a/docs/firm_info/index.rst +++ b/docs/firm_info/index.rst @@ -12,3 +12,7 @@ Django firm info serializers.rst templatetags.rst + + exceptions.rst + + managers.rst \ No newline at end of file diff --git a/docs/firm_info/managers.rst b/docs/firm_info/managers.rst new file mode 100644 index 0000000..c8a07d9 --- /dev/null +++ b/docs/firm_info/managers.rst @@ -0,0 +1,9 @@ +.. _intro_firm-info_managers: + +======= +Manager +======= + +.. autoclass:: firm_info.managers.SingletonManager + :members: + :exclude-members: create diff --git a/docs/firm_info/serializers.rst b/docs/firm_info/serializers.rst index ab8b98a..066a60f 100644 --- a/docs/firm_info/serializers.rst +++ b/docs/firm_info/serializers.rst @@ -5,5 +5,5 @@ Serializers =========== .. automodule:: firm_info.serializers - :members: SerializeFirmError, _format_address, serialize_firm_info, serialize_firm_social, serialize_firm_description, serialize_firm_social_sharing, serialize_firm_apps_banner + :members: _format_address, serialize_firm_info, serialize_firm_social, serialize_firm_description, serialize_firm_social_sharing, serialize_firm_apps_banner :exclude-members: DoesNotExist, MultipleObjectsReturned \ No newline at end of file From adbcff9576efca6393063baa9e911c4fbbb36fc3 Mon Sep 17 00:00:00 2001 From: Samy Saad Date: Tue, 28 May 2024 10:57:20 +0200 Subject: [PATCH 3/9] [FIX] Added default autofield in settings --- sandbox/settings/base.py | 1 + 1 file changed, 1 insertion(+) diff --git a/sandbox/settings/base.py b/sandbox/settings/base.py index 7d5b83e..3e13a30 100644 --- a/sandbox/settings/base.py +++ b/sandbox/settings/base.py @@ -7,6 +7,7 @@ SECRET_KEY = "***TOPSECRET***" +DEFAULT_AUTO_FIELD = "django.db.models.AutoField" # Root of project repository BASE_DIR = Path(__file__).parents[2] From 5acbb147daae1faa8d1f0218aaa1e1e9fe8ed32a Mon Sep 17 00:00:00 2001 From: Samy Saad Date: Tue, 28 May 2024 10:58:10 +0200 Subject: [PATCH 4/9] [CHG] Moved serializer exception to proper module --- firm_info/exceptions.py | 5 +++-- firm_info/serializers.py | 3 +-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/firm_info/exceptions.py b/firm_info/exceptions.py index c82c4df..79087fe 100644 --- a/firm_info/exceptions.py +++ b/firm_info/exceptions.py @@ -13,8 +13,9 @@ class MyAppBaseException(Exception): pass -class DummyError(MyAppBaseException): +class SerializeFirmError(MyAppBaseException): """ - Dummy exception sample to raise from your code. + Exceptions related to FirmContact serialization errors + during template tag generation. """ pass diff --git a/firm_info/serializers.py b/firm_info/serializers.py index 9e211c2..19a5867 100644 --- a/firm_info/serializers.py +++ b/firm_info/serializers.py @@ -1,5 +1,4 @@ -class SerializeFirmError(Exception): - pass +from firm_info.exceptions import SerializeFirmError def _format_address(firm_info: dict) -> str: From 68b8e7ee0c21fa8803e55c7021bd4570beb09711 Mon Sep 17 00:00:00 2001 From: Samy Saad Date: Tue, 28 May 2024 10:58:36 +0200 Subject: [PATCH 5/9] [DOC] Added singleton manager docstring --- firm_info/managers.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/firm_info/managers.py b/firm_info/managers.py index 92932a7..7ab60d5 100644 --- a/firm_info/managers.py +++ b/firm_info/managers.py @@ -3,6 +3,17 @@ class SingletonManager(models.Manager): + """ + A manager to ensure that only one instance of the model exists. + + This manager overrides the `create` method to enforce a singleton pattern + on the associated model. If an instance of the model already exists, + attempting to create another instance will raise a `ValueError`. + + Methods: + create(**kwargs): Creates a new instance of the model if none exists. + Raises `ValueError` if an instance already exists. + """ def create(self, **kwargs): if self.model.objects.exists(): error_message = _("Model {model_name} has already one instance") From 7dc1708e657855ac819fda33c87b8b9fef2aae83 Mon Sep 17 00:00:00 2001 From: Samy Saad Date: Tue, 28 May 2024 10:59:41 +0200 Subject: [PATCH 6/9] [CHG] Reworked flake8 exclusions --- sandbox/settings/tests.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sandbox/settings/tests.py b/sandbox/settings/tests.py index b04f3e8..c22362d 100644 --- a/sandbox/settings/tests.py +++ b/sandbox/settings/tests.py @@ -1,7 +1,8 @@ """ Django settings for tests """ -from sandbox.settings.base import * # noqa: F403 +# flake8: noqa: F403,F405 +from sandbox.settings.base import * DATABASES = { "default": { @@ -12,4 +13,4 @@ # Media directory dedicated to tests to avoid polluting other environment # media directory -MEDIA_ROOT = VAR_PATH / "media-tests" # noqa: F405 +MEDIA_ROOT = VAR_PATH / "media-tests" From 8c12a628da6d03f24b54ec9be104e457a59cee7d Mon Sep 17 00:00:00 2001 From: Samy Saad Date: Tue, 28 May 2024 11:00:00 +0200 Subject: [PATCH 7/9] [CHG] Added frozen deps --- frozen.txt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 frozen.txt diff --git a/frozen.txt b/frozen.txt new file mode 100644 index 0000000..07e2871 --- /dev/null +++ b/frozen.txt @@ -0,0 +1,15 @@ +# Frozen requirement versions from '0.1.4' installation +Django==4.2.13 +django-smart-media==0.3.1 +djangocms-text-ckeditor==5.1.5 +factory-boy==3.3.0 +flake8==7.0.0 +freezegun==1.5.1 +livereload==2.6.3 +pyquery==2.0.0 +pytest==8.2.1 +pytest-django==4.8.0 +Sphinx==5.3.0 +sphinx-rtd-theme==1.1.0 +tox==4.15.0 +twine==5.1.0 \ No newline at end of file From 59f2f8963c8cd051a45e2728506c56f105dc5c01 Mon Sep 17 00:00:00 2001 From: Samy Saad Date: Thu, 30 May 2024 11:35:18 +0200 Subject: [PATCH 8/9] [FIX] Fixed rtd build --- .readthedocs.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.readthedocs.yml b/.readthedocs.yml index edd98c3..1fe041e 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -4,6 +4,10 @@ # Required version: 2 +build: + os: ubuntu-20.04 + tools: + python: "3.8" # Build documentation in the docs/ directory with Sphinx sphinx: @@ -11,6 +15,5 @@ sphinx: # Optionally set the version of Python and requirements required to build your docs python: - version: 3.8 install: - requirements: docs/requirements.txt From 6baf21f1b78e3f225fd96cad2b1f05b4861477aa Mon Sep 17 00:00:00 2001 From: Samy Saad Date: Thu, 30 May 2024 12:00:16 +0200 Subject: [PATCH 9/9] [FIX] Fixed failing test for py310-django42 rendered html was not escaped --- tests/constantes.py | 2 +- tests/serializers.py | 4 ++-- tests/templatetags.py | 23 +++++++++++++---------- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/tests/constantes.py b/tests/constantes.py index 1170a26..bd77ed0 100644 --- a/tests/constantes.py +++ b/tests/constantes.py @@ -30,7 +30,7 @@ } -SERILAIZED_SOCIAL_LINKS = { +SERIALIZED_SOCIAL_LINKS = { "facebook": "http://facebook.com/example", "twitter": "http://twitter.com/example", } diff --git a/tests/serializers.py b/tests/serializers.py index bce03b5..924808e 100644 --- a/tests/serializers.py +++ b/tests/serializers.py @@ -7,7 +7,7 @@ ) from .constantes import ( - SERILAIZED_SOCIAL_LINKS + SERIALIZED_SOCIAL_LINKS ) @@ -34,7 +34,7 @@ def test_serialize_firm_info(db, firm_contact_obj): def test_serialize_firm_social(db, firm_social_links_objs): queryset = Link.objects.all() - expected_output = SERILAIZED_SOCIAL_LINKS + expected_output = SERIALIZED_SOCIAL_LINKS assert serialize_firm_social(queryset) == expected_output diff --git a/tests/templatetags.py b/tests/templatetags.py index c039b3c..e4e76ad 100644 --- a/tests/templatetags.py +++ b/tests/templatetags.py @@ -1,7 +1,10 @@ -from django.test import RequestFactory import pytest +from html import escape + from django.template import RequestContext, Template +from django.test import RequestFactory + from firm_info.models import FirmContact, Link from firm_info.factories import TrackingFactory from firm_info.templatetags.firm_info import ( @@ -11,7 +14,7 @@ firm_tag_analytic, ) -from .constantes import SERILAIZED_SOCIAL_LINKS +from .constantes import SERIALIZED_SOCIAL_LINKS def test_firm_contact_tag(db, firm_contact_obj): @@ -33,10 +36,10 @@ def test_firm_contact_tag(db, firm_contact_obj): firm_contact_obj.city, firm_contact_obj.country, ), - "

Address: {}

".format(firm_contact_obj.address), - "

city: {}

".format(firm_contact_obj.city), - "

postal code: {}

".format(firm_contact_obj.postal_code), - "

country: {}

".format(firm_contact_obj.country) + "

Address: {}

".format(escape(firm_contact_obj.address)), + "

city: {}

".format(escape(firm_contact_obj.city)), + "

postal code: {}

".format(escape(firm_contact_obj.postal_code)), + "

country: {}

".format(escape(firm_contact_obj.country)) ]) assert rendered == expected_output @@ -52,8 +55,8 @@ def test_firm_social_links_tag(db, firm_social_links_objs): template = Template(output) rendered = template.render(context) expected_output = "\n".join([ - f"facebook
", - f"twitter
" + f"facebook
", + f"twitter
" ]) assert rendered == expected_output @@ -70,8 +73,8 @@ def test_firm_description_tag(firm_contact_obj): template = Template(output) rendered = template.render(context) expected_output = "\n".join([ - f"

Baseline: {firm_contact_obj.baseline}

", - f"

Short_description: {firm_contact_obj.short_description}

", + f"

Baseline: {escape(firm_contact_obj.baseline)}

", + f"

Short_description: {escape(firm_contact_obj.short_description)}

", ]) assert rendered == expected_output