Skip to content

Commit

Permalink
Django's version is now "3.0".
Browse files Browse the repository at this point in the history
Notes:
 - django.utils.encoding.force_text() => force_str()
 - django.utils.html.escape() converts now ' to ' instead of '.
 - django.utils.http.urlquote() => urllib.parse.quote()
 - django.utils.http.is_safe_url() => url_has_allowed_host_and_scheme()
 - Use the old ContentType__str__() method.
 - The decorator @xframe_options_sameorigin has been used on views which are designed to be displayed in <iframe> (HTML bodies of emails).
  • Loading branch information
genglert committed Feb 22, 2021
1 parent c888f8b commit 3f1f435
Show file tree
Hide file tree
Showing 38 changed files with 202 additions and 133 deletions.
15 changes: 15 additions & 0 deletions CHANGELOG.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,22 @@
== Version 2.3 Work in progress (not released -- this is a draft) ==

UPGRADE NOTE :
- You should create a all new virtual environment based on Python 3.6+
(eg: "mkvirtualenv -p /usr/bin/python3XX" if you use 'mkvirtualenv')
and populate it with "pip install -e .[mysql|pgsql]" of course.
- Execute the well known commands "migrate", "generatemedia" & "creme_populate".

Users side :
------------
# The version of Django has been upgraded to 3.0.


Developers side :
-----------------
- The version of Django is now "3.0".
You should probably read the following releases notes for Django versions :
- https://docs.djangoproject.com/en/3.2/releases/3.0/


Non breaking changes :
----------------------
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ virtual env, in order to keep the old one working).
- These python packages :
(exact versions of Python packages are indicated in the 'setup.cfg' file)
- Mandatory :
- Django 2.2
- Django 3.0
- redis 3.4
- python-dateutil 2.8
- bleach 3.1
Expand All @@ -92,7 +92,7 @@ Installation with 'pip':
- You should probably use "virtualenv" (on a Python >= 3.6).
- Creme should be installed using 'pip install -e .'
- About DB server :
- If you use MySQL, you must add the 'mysql' flag:
- If you use MySQL/MariaDB, you must add the 'mysql' flag:
'pip install .[mysql]'
- For PostGreSQL, use 'pip install .[pgsql]' instead.
- SQLite doesn't require a specific flag (see RECOMMENDATIONS).
Expand Down
5 changes: 3 additions & 2 deletions creme/activities/tests/test_activity.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from django.forms import ModelMultipleChoiceField
from django.forms.utils import ValidationError
from django.urls import reverse
from django.utils.encoding import force_text
from django.utils.encoding import force_str # force_text
from django.utils.timezone import now
from django.utils.translation import gettext as _

Expand Down Expand Up @@ -2325,7 +2325,8 @@ def test_dl_ical(self):
self.assertEqual('text/calendar', response['Content-Type'])
self.assertEqual('attachment; filename=Calendar.ics', response['Content-Disposition'])

content = force_text(response.content)
# content = force_text(response.content)
content = force_str(response.content)
self.assertStartsWith(
content,
'BEGIN:VCALENDAR\nVERSION:2.0\nPRODID:-//CremeCRM//CremeCRM//EN\n'
Expand Down
7 changes: 4 additions & 3 deletions creme/billing/tests/test_convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from django.contrib.contenttypes.models import ContentType
from django.db.models.query_utils import Q
from django.urls import reverse
from django.utils.encoding import force_text
from django.utils.encoding import force_str # force_text
from django.utils.timezone import now
from django.utils.translation import gettext as _

Expand Down Expand Up @@ -214,8 +214,9 @@ def test_convert02_ajax(self):
self.assertEqual(1, SalesOrder.objects.count())

self.assertEqual(
force_text(response.content),
SalesOrder.objects.first().get_absolute_url()
# force_text(response.content),
force_str(response.content),
SalesOrder.objects.first().get_absolute_url(),
)

@skipIfCustomQuote
Expand Down
4 changes: 4 additions & 0 deletions creme/creme_core/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,10 @@ def ready(self):
for fname in ('app_label', 'model'):
get_ct_field(fname).set_tags(viewable=False)

# NB: the original prefix with app's name => ugly choices for final users
# => use gettext+context had smooth translation instead
ContentType.__str__ = lambda this: this.name


class CremeAppConfig(AppConfig):
# True => App can be used by some services
Expand Down
5 changes: 3 additions & 2 deletions creme/creme_core/management/commands/build_secret_key.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def handle(self, **options):
from hashlib import sha256
from time import time

from django.utils.encoding import force_text
from django.utils.encoding import force_str # force_text

choice = random.choice

Expand All @@ -66,7 +66,8 @@ def handle(self, **options):

random.seed(
sha256(
f'{random.getstate()}{time()}{force_text(kb_seed)}'.encode('utf-8')
# f'{random.getstate()}{time()}{force_text(kb_seed)}'.encode('utf-8')
f'{random.getstate()}{time()}{force_str(kb_seed)}'.encode('utf-8')
).digest()
)

Expand Down
5 changes: 3 additions & 2 deletions creme/creme_core/management/commands/creme_uninstall.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
from django.db import DEFAULT_DB_ALIAS, connections
from django.db.migrations.recorder import MigrationRecorder
from django.dispatch import receiver
from django.utils.encoding import force_text
from django.utils.encoding import force_str # force_text

from creme.creme_core.core.setting_key import setting_key_registry
from creme.creme_core.gui.bricks import Brick
Expand Down Expand Up @@ -470,7 +470,8 @@ def _delete_tables(self, app_config, app_label, verbosity):
' [KO] Original error: {error}.\n'
'Remaining tables:\n'
'{models}\n'.format(
error=force_text(e), # PostGreSQL returns localized errors...
# error=force_text(e), # PostGreSQL returns localized errors...
error=force_str(e), # PostGreSQL returns localized errors...
models='\n'.join(model._meta.db_table for model in models),
)
)
Expand Down
1 change: 0 additions & 1 deletion creme/creme_core/management/commands/entity_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,6 @@ class Command(BaseCommand):

SQL_OPTIMISERS = {
'django.db.backends.mysql': OptimizeMySQLContext,
'django.db.backends.postgresql_psycopg2': OptimizePGSQLContext,
'django.db.backends.postgresql': OptimizePGSQLContext,
# TODO: other DBRMS ?
}
Expand Down
6 changes: 3 additions & 3 deletions creme/creme_core/management/commands/i18n_overload.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

################################################################################
#
# Copyright (c) 2009-2020 Hybird
# Copyright (c) 2009-2021 Hybird
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
Expand Down Expand Up @@ -32,7 +32,7 @@
from django.apps import apps
from django.conf import settings
from django.core.management.base import BaseCommand, CommandError
from django.utils.encoding import smart_text
from django.utils.encoding import smart_str

APP_NAME = 'locale_overload' # TODO: can configure it with command options ??

Expand Down Expand Up @@ -181,7 +181,7 @@ def _overload_terms(self, language, verbosity, polib, file_name, *args):
.localize(datetime.now()) \
.strftime('%Y-%m-%d %H:%M%z')

terms = [smart_text(arg) for arg in args]
terms = [smart_str(arg) for arg in args]
entry_count = 0

for app_pofile in self._iter_pofiles(language, polib, file_name):
Expand Down
14 changes: 8 additions & 6 deletions creme/creme_core/middleware/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

################################################################################
# Creme is a free/open-source Customer Relationship Management software
# Copyright (C) 2009-2020 Hybird
# Copyright (C) 2009-2021 Hybird
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
Expand All @@ -25,7 +25,7 @@
from django.http import Http404, HttpResponse
from django.shortcuts import render
from django.utils.deprecation import MiddlewareMixin
from django.utils.encoding import smart_text
from django.utils.encoding import smart_str # smart_text

from creme.creme_core.core import exceptions as creme_exceptions

Expand All @@ -41,7 +41,8 @@ class _AlternativeErrorMiddleware(MiddlewareMixin):

def process_exception(self, request, exception):
if self.error is None or isinstance(exception, self.error):
msg = smart_text(exception)
# msg = smart_text(exception)
msg = smart_str(exception)

if request.is_ajax():
if self.log_ajax:
Expand All @@ -52,9 +53,10 @@ def process_exception(self, request, exception):
if self.template is None:
return

return render(request, self.template,
{'error_message': msg}, status=self.status,
)
return render(
request, self.template,
{'error_message': msg}, status=self.status,
)


class BadRequestMiddleware(_AlternativeErrorMiddleware):
Expand Down
1 change: 1 addition & 0 deletions creme/creme_core/models/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ def formfield(self, **kwargs):


# TODO: factorise with CTypeForeignKey
# (NB: using <descriptor_class> is harder than just move __get__/__set__ in a class...)
class CTypeOneToOneField(models.OneToOneField):
def __init__(self, **kwargs):
kwargs['to'] = 'contenttypes.ContentType'
Expand Down
5 changes: 3 additions & 2 deletions creme/creme_core/templatetags/creme_core_tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
from django.template import Template, TemplateSyntaxError
from django.template.defaulttags import TemplateLiteral
from django.template.library import token_kwargs
from django.utils.encoding import force_text
from django.utils.encoding import force_str # force_text
from django.utils.html import escape, format_html_join
from django.utils.safestring import mark_safe

Expand Down Expand Up @@ -658,7 +658,8 @@ def render(self, context):
logger.warning('jsondatablock tag do not accept custom "type" attribute')

attrs = ''.join(
f' {k}="{escape(force_text(v.resolve(context)))}"'
# f' {k}="{escape(force_text(v.resolve(context)))}"'
f' {k}="{escape(force_str(v.resolve(context)))}"'
for k, v in kwargs.items()
)

Expand Down
6 changes: 4 additions & 2 deletions creme/creme_core/tests/gui/test_field_printers.py
Original file line number Diff line number Diff line change
Expand Up @@ -1119,7 +1119,8 @@ def test_registry_fk(self):
self.assertEqual(str(casca.image), get_csv_val(casca, 'image', user))

self.assertEqual(
'<p>Casca&#39;s selfie</p>',
# '<p>Casca&#39;s selfie</p>',
'<p>Casca&#x27;s selfie</p>',
get_html_val(casca, 'image__description', user)
)
self.assertEqual(
Expand Down Expand Up @@ -1310,7 +1311,8 @@ def test_registry_credentials(self):
get_html_val(judo, 'image', user)
)
self.assertEqual(
'<p>Judo&#39;s selfie</p>',
# '<p>Judo&#39;s selfie</p>',
'<p>Judo&#x27;s selfie</p>',
get_html_val(judo, 'image__description', user)
)

Expand Down
5 changes: 3 additions & 2 deletions creme/creme_core/tests/models/test_custom_field.py
Original file line number Diff line number Diff line change
Expand Up @@ -517,12 +517,13 @@ def test_multi_enum02(self):
entity=orga,
)

with self.assertNumQueries(3):
# with self.assertNumQueries(3):
with self.assertNumQueries(2):
cf_value.set_value_n_save([enum_value1, enum_value2])

self.assertSetEqual(
{enum_value1, enum_value2},
{*self.refresh(cf_value).value.all()}
{*self.refresh(cf_value).value.all()},
)

def test_delete(self):
Expand Down
4 changes: 2 additions & 2 deletions creme/creme_core/tests/views/test_job.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from django.db.models import Max
from django.test.utils import override_settings
from django.urls import reverse
from django.utils.encoding import smart_text
from django.utils.encoding import smart_str
from django.utils.formats import date_format
from django.utils.timezone import localtime, now
from django.utils.translation import gettext as _
Expand Down Expand Up @@ -51,7 +51,7 @@ def tearDown(self):

# TODO: move to base class ?
def _assertCount(self, response, found, count):
self.assertEqual(count, smart_text(response.content).count(found))
self.assertEqual(count, smart_str(response.content).count(found))

def _build_enable_url(self, job):
return reverse('creme_core__enable_job', args=(job.id,))
Expand Down
23 changes: 15 additions & 8 deletions creme/creme_core/tests/views/test_listview.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@
from functools import partial
from json import dumps as json_dump
from random import shuffle
from urllib.parse import quote
from xml.etree.ElementTree import tostring as html_tostring

from django.conf import settings
from django.contrib.contenttypes.models import ContentType
from django.db.models import Q
from django.test.utils import override_settings
from django.urls import reverse
from django.utils.encoding import force_text
from django.utils.http import urlquote
from django.utils.encoding import force_str # force_text
# from django.utils.http import urlquote
from django.utils.timezone import now
from django.utils.translation import gettext as _
from django.utils.translation import pgettext
Expand Down Expand Up @@ -429,7 +430,8 @@ def post(selection):
self.assertInHTML(
f'<input class="lv-state-field" value="{selection}" '
f'name="selection" type="hidden" />',
force_text(response.content),
# force_text(response.content),
force_str(response.content),
)

post('none')
Expand All @@ -450,7 +452,8 @@ def get(selection):
self.assertInHTML(
f'<input class="lv-state-field" value="{selection}" '
f'name="selection" type="hidden" />',
force_text(response.content),
# force_text(response.content),
force_str(response.content),
)

get('none')
Expand Down Expand Up @@ -1003,7 +1006,8 @@ def test_ordering_fastmode_01(self):
r'.creme_core_fakecontact.\..birthday. ASC( NULLS FIRST)?, '
r'.creme_core_fakecontact.\..last_name. ASC( NULLS FIRST)?, '
r'.creme_core_fakecontact.\..first_name. ASC( NULLS FIRST)?, '
r'.creme_core_fakecontact.\..cremeentity_ptr_id. ASC( NULLS FIRST)? LIMIT'
# r'.creme_core_fakecontact.\..cremeentity_ptr_id. ASC( NULLS FIRST)? LIMIT'
r'.creme_core_fakecontact.\..cremeentity_ptr_id. ASC( NULLS FIRST)? LIMIT'
)

@override_settings(FAST_QUERY_MODE_THRESHOLD=2)
Expand All @@ -1014,7 +1018,8 @@ def test_ordering_fastmode_02(self):
sql,
r'ORDER BY'
r' .creme_core_fakecontact.\..birthday. ASC( NULLS FIRST)?,'
r' .creme_core_fakecontact.\..cremeentity_ptr_id. ASC( NULLS FIRST)? LIMIT'
# r' .creme_core_fakecontact.\..cremeentity_ptr_id. ASC( NULLS FIRST)? LIMIT'
r' .creme_core_fakecontact.\..cremeentity_ptr_id. ASC( NULLS FIRST)? LIMIT'
)

def test_efilter01(self):
Expand Down Expand Up @@ -1176,8 +1181,10 @@ def test_header_buttons(self):
dl_uri = data_hrefs[1]
self.assertStartsWith(dl_uri, dl_url)
self.assertIn(f'hfilter={hf.id}', dl_uri)
self.assertIn(f'&extra_q={urlquote(q_filter)}', dl_uri)
self.assertIn(f'&search-regular_field-phone={urlquote(searched_phone)}', dl_uri)
# self.assertIn(f'&extra_q={urlquote(q_filter)}', dl_uri)
self.assertIn(f'&extra_q={quote(q_filter)}', dl_uri)
# self.assertIn(f'&search-regular_field-phone={urlquote(searched_phone)}', dl_uri)
self.assertIn(f'&search-regular_field-phone={quote(searched_phone)}', dl_uri)

dl_header_uri = data_hrefs[2]
self.assertStartsWith(dl_header_uri, dl_url)
Expand Down
Loading

0 comments on commit 3f1f435

Please sign in to comment.