Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade django version from 4.2 to 5.1 #375

Open
wants to merge 1 commit into
base: development
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ classifiers = [
"Environment :: Web Environment",
"License :: OSI Approved :: Apache License, Version 2.0",
"Programming Language :: Python :: 3.11",
"Framework :: Django :: 4.2",
"Framework :: Django :: 5.1",
]
dependencies = [
'Django==4.2.*',
'Django==5.1.*',
'djangorestframework==3.15.*',
'python-dateutil==2.9.*',
'isoweek',
Expand Down Expand Up @@ -103,7 +103,7 @@ dependencies = [
[project.optional-dependencies]
memcached = ["pylibmc"]
dev = [
'django-debug-toolbar==4.0.*',
'django-debug-toolbar==4.4.*',
'pycodestyle==2.12.*',
'pyflakes==3.2.*',
'flake8==7.1.*',
Expand Down
104 changes: 104 additions & 0 deletions src/pretix/base/js_catalog_template.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
js_catalog_template = r"""
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (complexity): Consider refactoring the large template string into smaller, more manageable pieces.

While the internationalization functionality is crucial, the current implementation mixes Python and JavaScript in a way that could lead to maintainability issues. Consider the following improvements:

  1. Break down the large template string into smaller, more manageable pieces:
js_catalog_template = r"""
{% autoescape off %}
'use strict';
{{ django_object }}
{{ gettext_functions }}
{{ formatting_functions }}
{{ global_assignments }}
{% endautoescape %}
"""

django_object = r"""
const globals = this;
const django = globals.django || (globals.django = {});
"""

gettext_functions = r"""
django.gettext = function(msgid) {
    // ... (existing implementation)
};

django.ngettext = function(singular, plural, count) {
    // ... (existing implementation)
};

// ... (other gettext-related functions)
"""

formatting_functions = r"""
django.formats = {{ formats_str }};

django.get_format = function(format_type) {
    // ... (existing implementation)
};
"""

global_assignments = r"""
globals.pluralidx = django.pluralidx;
globals.gettext = django.gettext;
// ... (other global assignments)

django.jsi18n_initialized = true;
"""
  1. Use a template engine or string formatting to combine these pieces:
from string import Template

js_catalog_template = Template(js_catalog_template).safe_substitute(
    django_object=django_object,
    gettext_functions=gettext_functions,
    formatting_functions=formatting_functions,
    global_assignments=global_assignments
)

This approach maintains the benefits of keeping related logic together while significantly improving readability and maintainability. It allows for easier updates to specific parts of the internationalization logic and makes the code more modular without necessarily splitting it into separate files.

{% autoescape off %}
'use strict';
{
const globals = this;
const django = globals.django || (globals.django = {});

{% if plural %}
django.pluralidx = function(n) {
const v = {{ plural }};
if (typeof v === 'boolean') {
return v ? 1 : 0;
} else {
return v;
}
};
{% else %}
django.pluralidx = function(count) { return (count == 1) ? 0 : 1; };
{% endif %}

/* gettext library */

django.catalog = django.catalog || {};
{% if catalog_str %}
const newcatalog = {{ catalog_str }};
for (const key in newcatalog) {
django.catalog[key] = newcatalog[key];
}
{% endif %}

if (!django.jsi18n_initialized) {
django.gettext = function(msgid) {
const value = django.catalog[msgid];
if (typeof value === 'undefined') {
return msgid;
} else {
return (typeof value === 'string') ? value : value[0];
}
};

django.ngettext = function(singular, plural, count) {
const value = django.catalog[singular];
if (typeof value === 'undefined') {
return (count == 1) ? singular : plural;
} else {
return value.constructor === Array ? value[django.pluralidx(count)] : value;
}
};

django.gettext_noop = function(msgid) { return msgid; };

django.pgettext = function(context, msgid) {
let value = django.gettext(context + '\x04' + msgid);
if (value.includes('\x04')) {
value = msgid;
}
return value;
};

django.npgettext = function(context, singular, plural, count) {
let value = django.ngettext(context + '\x04' + singular, context + '\x04' + plural, count);
if (value.includes('\x04')) {
value = django.ngettext(singular, plural, count);
}
return value;
};

django.interpolate = function(fmt, obj, named) {
if (named) {
return fmt.replace(/%\(\w+\)s/g, function(match){return String(obj[match.slice(2,-2)])});
} else {
return fmt.replace(/%s/g, function(match){return String(obj.shift())});
}
};


/* formatting library */

django.formats = {{ formats_str }};

django.get_format = function(format_type) {
const value = django.formats[format_type];
if (typeof value === 'undefined') {
return format_type;
} else {
return value;
}
};

/* add to global namespace */
globals.pluralidx = django.pluralidx;
globals.gettext = django.gettext;
globals.ngettext = django.ngettext;
globals.gettext_noop = django.gettext_noop;
globals.pgettext = django.pgettext;
globals.npgettext = django.npgettext;
globals.interpolate = django.interpolate;
globals.get_format = django.get_format;

django.jsi18n_initialized = true;
}
};
{% endautoescape %}
""" # NOQA
26 changes: 10 additions & 16 deletions src/pretix/base/signals.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,16 @@ def _populate_app_cache():
class EventPluginSignal(django.dispatch.Signal):
"""
This is an extension to Django's built-in signals which differs in a way that it sends
out it's events only to receivers which belong to plugins that are enabled for the given
out its events only to receivers which belong to plugins that are enabled for the given
Event.
"""

def get_live_receivers(self, sender):
receivers = self._live_receivers(sender)
if not receivers:
return []
return receivers[0]

def _is_active(self, sender, receiver):
if sender is None:
# Send to all events!
Expand Down Expand Up @@ -65,7 +71,7 @@ def send(self, sender: Event, **named) -> List[Tuple[Callable, Any]]:
if not app_cache:
_populate_app_cache()

for receiver in self._sorted_receivers(sender):
for receiver in self.get_live_receivers(sender):
if self._is_active(sender, receiver):
response = receiver(signal=self, sender=sender, **named)
responses.append((receiver, response))
Expand All @@ -89,7 +95,7 @@ def send_chained(self, sender: Event, chain_kwarg_name, **named) -> List[Tuple[C
if not app_cache:
_populate_app_cache()

for receiver in self._sorted_receivers(sender):
for receiver in self.get_live_receivers(sender):
if self._is_active(sender, receiver):
named[chain_kwarg_name] = response
response = receiver(signal=self, sender=sender, **named)
Expand All @@ -116,7 +122,7 @@ def send_robust(self, sender: Event, **named) -> List[Tuple[Callable, Any]]:
if not app_cache:
_populate_app_cache()

for receiver in self._sorted_receivers(sender):
for receiver in self.get_live_receivers(sender):
if self._is_active(sender, receiver):
try:
response = receiver(signal=self, sender=sender, **named)
Expand All @@ -126,18 +132,6 @@ def send_robust(self, sender: Event, **named) -> List[Tuple[Callable, Any]]:
responses.append((receiver, response))
return responses

def _sorted_receivers(self, sender):
orig_list = self._live_receivers(sender)
sorted_list = sorted(
orig_list,
key=lambda receiver: (
0 if any(receiver.__module__.startswith(m) for m in settings.CORE_MODULES) else 1,
receiver.__module__,
receiver.__name__,
)
)
return sorted_list


class GlobalSignal(django.dispatch.Signal):
def send_chained(self, sender: Event, chain_kwarg_name, **named) -> List[Tuple[Callable, Any]]:
Expand Down
3 changes: 2 additions & 1 deletion src/pretix/presale/views/widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,12 @@
from django.views.decorators.gzip import gzip_page
from django.views.decorators.http import condition
from django.views.i18n import (
JavaScriptCatalog, get_formats, js_catalog_template,
JavaScriptCatalog, get_formats,
)
from lxml import html

from pretix.base.i18n import language
from pretix.base.js_catalog_template import js_catalog_template
from pretix.base.models import CartPosition, Event, Quota, SubEvent, Voucher
from pretix.base.services.cart import error_messages
from pretix.base.settings import GlobalSettingsObject
Expand Down
Loading