diff --git a/askbot/admin.py b/askbot/admin.py index c5e2ce6555..61103f832d 100644 --- a/askbot/admin.py +++ b/askbot/admin.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ :synopsis: connector to standard Django admin interface diff --git a/askbot/bin/generate_modules.py b/askbot/bin/generate_modules.py index ddaf557d12..fcba59060e 100755 --- a/askbot/bin/generate_modules.py +++ b/askbot/bin/generate_modules.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Miville # Copyright (C) 2008 Société des arts technologiques (SAT) # http://www.sat.qc.ca @@ -39,7 +38,7 @@ def create_file_name(base, opts): """Create file name from base name, path and suffix""" - return os.path.join(opts.destdir, "%s.%s" % (base, opts.suffix)) + return os.path.join(opts.destdir, f"{base}.{opts.suffix}") def write_automodule_directive(module): @@ -61,13 +60,13 @@ def write_heading(module, kind='Module'): def write_sub(module, kind='Module'): """Create the module subtitle""" - sub = title_line('The :mod:`%s` %s' % (module, kind), '-') + sub = title_line(f'The :mod:`{module}` {kind}', '-') return sub def title_line(title, char): """ Underline the title with the character pass, with the right length.""" - return ':mod:`%s`\n%s\n\n' % (title, len(title) * char) + return f':mod:`{title}`\n{len(title) * char}\n\n' def create_module_content(module): @@ -108,7 +107,7 @@ def create_package_content(package, py_files, sub_packages): # __init__.py of the current module continue py_file = os.path.splitext(py_file)[0] - text += '* :ref:`%s.%s`\n' % (package, py_file) + text += f'* :ref:`{package}.{py_file}`\n' text += '\n' # create links to sub-packages @@ -119,7 +118,7 @@ def create_package_content(package, py_files, sub_packages): text += '\n' for sub in sub_packages: # TODO - add description here - text += '* :ref:`%s.%s`\n' % (package, sub) + text += f'* :ref:`{package}.{sub}`\n' return text # build toctree for the package page # text += '.. toctree::\n\n' @@ -149,7 +148,7 @@ def check_for_code(module): """ Check if there's at least one class or one function in the module. """ - fd = open(module, 'r') + fd = open(module) for line in fd: if line.startswith('def ') or line.startswith('class '): fd.close() diff --git a/askbot/conf/settings_wrapper.py b/askbot/conf/settings_wrapper.py index 194b67eedb..2f26491f4f 100644 --- a/askbot/conf/settings_wrapper.py +++ b/askbot/conf/settings_wrapper.py @@ -45,7 +45,7 @@ def assert_setting_info_correct(info): assert isinstance(info[2], bool) -class ConfigSettings(object): +class ConfigSettings: """A very simple Singleton wrapper for settings a limitation is that all settings names using this class must be distinct, even though they might belong @@ -139,7 +139,7 @@ def get_setting_url(self, data): 'livesettings_group', setting_name, # TODO: better use description kwargs={'group': group_name}, - anchor='id_%s__%s__%s' % (group_name, setting_name, get_language()) + anchor=f'id_{group_name}__{setting_name}__{get_language()}' ) if len(data) == 4: return force_str(format_lazy('{} ({})',link, data[3])) @@ -227,7 +227,7 @@ def prime_cache(cls, cache_key, **kwargs): else: setting_value = cls.__instance[key] if setting_value.localized: - db_key = '{}_{}'.format(key, format_setting_name(get_language())) + db_key = f'{key}_{format_setting_name(get_language())}' else: db_key = key diff --git a/askbot/const/__init__.py b/askbot/const/__init__.py index 02a535d447..c1ab40ffc6 100644 --- a/askbot/const/__init__.py +++ b/askbot/const/__init__.py @@ -1,4 +1,3 @@ -# encoding:utf-8 """ All constants could be used in other modules For reasons that models, views can't have unicode @@ -179,7 +178,7 @@ TAG_CHARS = r'\wp{M}+.#-' TAG_FIRST_CHARS = r'[\wp{M}]' TAG_FORBIDDEN_FIRST_CHARS = r'#' -TAG_REGEX_BARE = r'%s[%s]+' % (TAG_FIRST_CHARS, TAG_CHARS) +TAG_REGEX_BARE = rf'{TAG_FIRST_CHARS}[{TAG_CHARS}]+' TAG_REGEX = r'^%s$' % TAG_REGEX_BARE TAG_STRIP_CHARS = ', ' diff --git a/askbot/deployment/deployers/file_deployer.py b/askbot/deployment/deployers/file_deployer.py index aaab8b9976..f41c710127 100644 --- a/askbot/deployment/deployers/file_deployer.py +++ b/askbot/deployment/deployers/file_deployer.py @@ -27,7 +27,7 @@ def get_template_parameters(self): # pylint: disable=no-self-use def get_template(self): """Returns string representation of the template""" - return open(get_askbot_module_path(self.template_path), 'r').read() + return open(get_askbot_module_path(self.template_path)).read() def deploy_file(self, contents): """Writes contents into the target file""" diff --git a/askbot/deployment/deployers/settings_py_admins_snippet.py b/askbot/deployment/deployers/settings_py_admins_snippet.py index caef9fc77d..a3424f5b5f 100644 --- a/askbot/deployment/deployers/settings_py_admins_snippet.py +++ b/askbot/deployment/deployers/settings_py_admins_snippet.py @@ -9,4 +9,4 @@ def render(self): """--admin-settings override the default""" if self.params['admin_settings']: return self.params['admin_settings'] - return super(SettingsPyAdminsSnippet, self).render() + return super().render() diff --git a/askbot/deployment/deployers/settings_py_caching_snippet.py b/askbot/deployment/deployers/settings_py_caching_snippet.py index d8a073534a..51d1dbf828 100644 --- a/askbot/deployment/deployers/settings_py_caching_snippet.py +++ b/askbot/deployment/deployers/settings_py_caching_snippet.py @@ -7,4 +7,4 @@ class SettingsPyCachingSnippet(FileDeployer): # pylint: disable=missing-class-do def render(self): if self.params['caching_settings']: return self.params['caching_settings'] - return super(SettingsPyCachingSnippet, self).render() + return super().render() diff --git a/askbot/deployment/deployers/settings_py_databases_snippet.py b/askbot/deployment/deployers/settings_py_databases_snippet.py index 29112ea048..e253f01def 100644 --- a/askbot/deployment/deployers/settings_py_databases_snippet.py +++ b/askbot/deployment/deployers/settings_py_databases_snippet.py @@ -10,4 +10,4 @@ def render(self): `database_settings` parameter""" if self.params['database_settings']: return self.params['database_settings'] - return super(SettingsPyDatabasesSnippet, self).render() + return super().render() diff --git a/askbot/deployment/deployers/settings_py_email_snippet.py b/askbot/deployment/deployers/settings_py_email_snippet.py index 20edfa263c..018445ca13 100644 --- a/askbot/deployment/deployers/settings_py_email_snippet.py +++ b/askbot/deployment/deployers/settings_py_email_snippet.py @@ -11,4 +11,4 @@ def render(self): parameter""" if self.params['email_settings']: return self.params['email_settings'] - return super(SettingsPyEmailSnippet, self).render() + return super().render() diff --git a/askbot/deployment/deployers/settings_py_languages_snippet.py b/askbot/deployment/deployers/settings_py_languages_snippet.py index 948553638d..499f7940ee 100644 --- a/askbot/deployment/deployers/settings_py_languages_snippet.py +++ b/askbot/deployment/deployers/settings_py_languages_snippet.py @@ -9,4 +9,4 @@ def render(self): the override with the `language_settings` parameter""" if self.params['language_settings']: return self.params['language_settings'] - return super(SettingsPyLanguagesSnippet, self).render() + return super().render() diff --git a/askbot/deployment/deployers/settings_py_logging_snippet.py b/askbot/deployment/deployers/settings_py_logging_snippet.py index 2ea902174a..e646a2cc9e 100644 --- a/askbot/deployment/deployers/settings_py_logging_snippet.py +++ b/askbot/deployment/deployers/settings_py_logging_snippet.py @@ -9,4 +9,4 @@ def render(self): allows override with the --logging-settings parameter""" if self.params['logging_settings']: return self.params['logging_settings'] - return super(SettingsPyLoggingSnippet, self).render() + return super().render() diff --git a/askbot/deployment/path_utils.py b/askbot/deployment/path_utils.py index dd015f07d9..5ab035a47a 100644 --- a/askbot/deployment/path_utils.py +++ b/askbot/deployment/path_utils.py @@ -17,7 +17,7 @@ def dir_has_django_project(directory): if file_name.endswith(os.path.sep + 'manage.py'): #a hack allowing to install into the project directory continue - with open(file_name, 'r') as py_file: + with open(file_name) as py_file: for line in py_file: if IMPORT_RE1.match(line) or IMPORT_RE2.match(line): return True diff --git a/askbot/deployment/validators/proj_dir_validator.py b/askbot/deployment/validators/proj_dir_validator.py index 9e3b985b26..c89fa382b5 100644 --- a/askbot/deployment/validators/proj_dir_validator.py +++ b/askbot/deployment/validators/proj_dir_validator.py @@ -8,7 +8,7 @@ class ProjDirValidator(DirValidator): """Implements the .clean method for the proj_name parameter""" def __init__(self, console, parser, root_dir): - super(ProjDirValidator, self).__init__(console, parser) + super().__init__(console, parser) self.user_prompt = f'Enter {const.PROJ_NAME_HELP}.' self.option_name = 'proj_name' self.root_dir = root_dir diff --git a/askbot/deployment/validators/root_dir_validator.py b/askbot/deployment/validators/root_dir_validator.py index b3e89da30e..1474972fdc 100644 --- a/askbot/deployment/validators/root_dir_validator.py +++ b/askbot/deployment/validators/root_dir_validator.py @@ -10,7 +10,7 @@ class RootDirValidator(DirValidator): by providing the .clean method""" def __init__(self, console, parser): - super(RootDirValidator, self).__init__(console, parser) + super().__init__(console, parser) self.user_prompt = f'Enter {const.ROOT_DIR_HELP}.' self.option_name = 'root_dir' self.default = './' + const.DEFAULT_PROJECT_NAME diff --git a/askbot/deps/django_authopenid/__init__.py b/askbot/deps/django_authopenid/__init__.py index d854887892..3940cc6137 100644 --- a/askbot/deps/django_authopenid/__init__.py +++ b/askbot/deps/django_authopenid/__init__.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2007, 2008, Benoît Chesneau # # All rights reserved. diff --git a/askbot/deps/django_authopenid/admin.py b/askbot/deps/django_authopenid/admin.py index c8ec1aa448..2d4154ed71 100644 --- a/askbot/deps/django_authopenid/admin.py +++ b/askbot/deps/django_authopenid/admin.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.contrib import admin from askbot.deps.django_authopenid.models import UserAssociation diff --git a/askbot/deps/django_authopenid/backends.py b/askbot/deps/django_authopenid/backends.py index b0e594cb7a..d0b2eab362 100644 --- a/askbot/deps/django_authopenid/backends.py +++ b/askbot/deps/django_authopenid/backends.py @@ -18,7 +18,7 @@ LOG = logging.getLogger(__name__) -class AuthBackend(object): +class AuthBackend: """Authenticator's authentication backend class for more info, see django doc page: http://docs.djangoproject.com/en/dev/topics/auth/#writing-an-authentication-backend @@ -31,7 +31,7 @@ class AuthBackend(object): """ def __init__(self, *args, **kwargs): self.login_providers = util.get_enabled_login_providers() - super(AuthBackend, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) def authenticate(self, request, method=None, provider_name=None, **kwargs): """this authentication function supports many login methods""" @@ -143,7 +143,7 @@ def auth_by_external_password(self, provider_name, username, password, request): else: #have username collision - so make up a more unique user name #bug: - if user already exists with the new username - we are in trouble - new_username = '%s@%s' % (username, provider_name) + new_username = f'{username}@{provider_name}' user = User.objects.create_user(new_username, '', password) user_registered.send(None, user=user, request=request) message = _( diff --git a/askbot/deps/django_authopenid/forms.py b/askbot/deps/django_authopenid/forms.py index b0c7112f6f..a3c625f36d 100644 --- a/askbot/deps/django_authopenid/forms.py +++ b/askbot/deps/django_authopenid/forms.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2007, 2008, Benoît Chesneau # # All rights reserved. @@ -53,7 +52,7 @@ class ConsentField(forms.BooleanField): def __init__(self, *args, **kwargs): - super(ConsentField, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.label = _('I have read and agree with the terms of service') self.required = True self.error_messages['required'] = _( @@ -68,7 +67,7 @@ class LoginProviderField(forms.CharField): def __init__(self, *args, **kwargs): kwargs['max_length'] = 64 - super(LoginProviderField, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) def clean(self, value): """makes sure that login provider name @@ -301,7 +300,7 @@ class RegistrationForm(forms.Form): def __init__(self, *args, **kwargs): self.request = kwargs.pop('request', None) - super(RegistrationForm, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) email_required = not askbot_settings.BLANK_EMAIL_ALLOWED self.fields['email'] = UserEmailField(required=email_required) if askbot_settings.TERMS_CONSENT_REQUIRED: @@ -313,7 +312,7 @@ def __init__(self, *args, **kwargs): def clean(self): if askbot_settings.NEW_REGISTRATIONS_DISABLED: raise forms.ValidationError(askbot_settings.NEW_REGISTRATIONS_DISABLED_MESSAGE) - return super(RegistrationForm, self).clean() + return super().clean() class PasswordRegistrationForm(RegistrationForm, SetPasswordForm): @@ -361,7 +360,7 @@ class ChangeEmailForm(forms.Form): """ change email form """ def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None, \ initial=None, user=None): - super(ChangeEmailForm, self).__init__(data, files, auto_id, + super().__init__(data, files, auto_id, prefix, initial) email_required = not askbot_settings.BLANK_EMAIL_ALLOWED self.fields['email'] = UserEmailField(skip_clean=True, required=email_required) @@ -416,7 +415,7 @@ class ChangeopenidForm(forms.Form): def __init__(self, data=None, user=None, *args, **kwargs): if user is None: raise TypeError("Keyword argument 'user' must be supplied") - super(ChangeopenidForm, self).__init__(data, *args, **kwargs) + super().__init__(data, *args, **kwargs) self.user = user @@ -428,7 +427,7 @@ class DeleteForm(forms.Form): def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None, initial=None, user=None): - super(DeleteForm, self).__init__(data, files, auto_id, prefix, initial) + super().__init__(data, files, auto_id, prefix, initial) self.test_openid = False self.user = user @@ -449,7 +448,7 @@ class EmailPasswordForm(forms.Form): def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None, initial=None): - super(EmailPasswordForm, self).__init__(data, files, auto_id, + super().__init__(data, files, auto_id, prefix, initial) self.user_cache = None diff --git a/askbot/deps/django_authopenid/ldap_auth.py b/askbot/deps/django_authopenid/ldap_auth.py index ee11a3c6e6..7d7c3e7f7c 100644 --- a/askbot/deps/django_authopenid/ldap_auth.py +++ b/askbot/deps/django_authopenid/ldap_auth.py @@ -187,7 +187,7 @@ def ldap_create_user_default(user_info, request): user.is_active = True user.save() user_registered.send(None, user=user, request=request) - LOG.info('Created New User : [{0}]'.format(user_info['ldap_username'])) + LOG.info('Created New User : [{}]'.format(user_info['ldap_username'])) assoc = UserAssociation() assoc.user = user diff --git a/askbot/deps/django_authopenid/middleware.py b/askbot/deps/django_authopenid/middleware.py index 8439ba5073..85f63e4752 100644 --- a/askbot/deps/django_authopenid/middleware.py +++ b/askbot/deps/django_authopenid/middleware.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from askbot.deps.django_authopenid import mimeparse from django.http import HttpResponseRedirect from django.urls import reverse @@ -6,7 +5,7 @@ __all__ = ["OpenIDMiddleware"] -class OpenIDMiddleware(object): +class OpenIDMiddleware: """ Populate request.openid. This comes either from cookie or from session, depending on the presence of OPENID_USE_SESSIONS. diff --git a/askbot/deps/django_authopenid/models.py b/askbot/deps/django_authopenid/models.py index 2b8432842b..c8eb5727de 100644 --- a/askbot/deps/django_authopenid/models.py +++ b/askbot/deps/django_authopenid/models.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- import datetime from django.conf import settings @@ -36,7 +35,7 @@ class Association(models.Model): assoc_type = models.TextField(max_length=64) def __str__(self): - return "Association: %s, %s" % (self.server_url, self.handle) + return f"Association: {self.server_url}, {self.handle}" class UserAssociation(models.Model): """ @@ -52,14 +51,14 @@ class UserAssociation(models.Model): provider_name = models.CharField(max_length=64, default='unknown') last_used_timestamp = models.DateTimeField(null=True) - class Meta(object): + class Meta: unique_together = ( ('user','provider_name'), ('openid_url', 'provider_name') ) def __str__(self): - return "Openid %s with user %s" % (self.openid_url, self.user) + return f"Openid {self.openid_url} with user {self.user}" def update_timestamp(self): self.last_used_timestamp = datetime.datetime.now() @@ -72,7 +71,7 @@ def get_new_confirm_key(self): # The random module is seeded when this Apache child is created. # Use SECRET_KEY as added salt. while 1: - confirm_key = hashlib.md5("%s%s%s%s" % ( + confirm_key = hashlib.md5("{}{}{}{}".format( random.randint(0, sys.maxsize - 1), os.getpid(), time.time(), settings.SECRET_KEY)).hexdigest() try: @@ -108,7 +107,7 @@ def save(self, *args, **kwargs): self.expires_on = timezone.now() + \ datetime.timedelta(VERIFIER_EXPIRE_DAYS) - super(UserEmailVerifier, self).save(*args, **kwargs) + super().save(*args, **kwargs) def has_expired(self): now = timezone.now() diff --git a/askbot/deps/django_authopenid/protocols/base.py b/askbot/deps/django_authopenid/protocols/base.py index 42761b16f7..319b56be04 100644 --- a/askbot/deps/django_authopenid/protocols/base.py +++ b/askbot/deps/django_authopenid/protocols/base.py @@ -1,4 +1,4 @@ -class BaseProtocol(object): +class BaseProtocol: """Base class for all authentication protocols""" def __iter__(self): diff --git a/askbot/deps/django_authopenid/protocols/oauth1.py b/askbot/deps/django_authopenid/protocols/oauth1.py index bbd00633c0..9646f79bfc 100644 --- a/askbot/deps/django_authopenid/protocols/oauth1.py +++ b/askbot/deps/django_authopenid/protocols/oauth1.py @@ -123,9 +123,9 @@ def send_request(self, client=None, url=None, method='GET', params=None, **kwarg if parsed_response: return parsed_response else: - raise OAuthError('error obtaining request token {0}'.format(content)) + raise OAuthError(f'error obtaining request token {content}') else: - raise OAuthError('response is {0}'.format(response)) + raise OAuthError(f'response is {response}') def get_token(self): return self.request_token diff --git a/askbot/deps/django_authopenid/providers/discourse.py b/askbot/deps/django_authopenid/providers/discourse.py index 9f86c2a435..c357c572fe 100644 --- a/askbot/deps/django_authopenid/providers/discourse.py +++ b/askbot/deps/django_authopenid/providers/discourse.py @@ -32,7 +32,7 @@ def get_sso_login_url(request, success_url): # (where the Discourse will redirect user after verification). # Payload should look like: nonce=NONCE&return_sso_url=RETURN_URL return_url = site_url(reverse('user_complete_discourse_signin')) - payload = 'nonce={}&return_sso_url={}'.format(nonce, return_url) + payload = f'nonce={nonce}&return_sso_url={return_url}' # Base64 encode the above raw payload. -> BASE64_PAYLOAD base64_payload = base64.b64encode(payload) # URL encode the above BASE64_PAYLOAD. @@ -52,7 +52,7 @@ class DiscourseSsoForm(forms.Form): def __init__(self, *args, **kwargs): self.expected_nonce = kwargs.pop('nonce', None) - super(DiscourseSsoForm, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) def clean(self): sso = self.cleaned_data['sso'] diff --git a/askbot/deps/django_authopenid/urls.py b/askbot/deps/django_authopenid/urls.py index 4b55111eb2..e5e4a3ab95 100644 --- a/askbot/deps/django_authopenid/urls.py +++ b/askbot/deps/django_authopenid/urls.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.conf import settings as django_settings from django.urls import re_path @@ -18,11 +17,11 @@ re_path(r'^%s$' % pgettext('urls', 'signout/'), OpenidViews.signout, name='user_signout'), #this view is "complete-openid" signin re_path( - r'^%s%s$' % (pgettext('urls', 'signin/'), pgettext('urls', 'complete/')), + r'^{}{}$'.format(pgettext('urls', 'signin/'), pgettext('urls', 'complete/')), OpenidViews.complete_openid_signin, name='user_complete_openid_signin'), re_path( - r'^%s%s$' % (pgettext('urls', 'signin/'), pgettext('urls', 'complete-cas/')), + r'^{}{}$'.format(pgettext('urls', 'signin/'), pgettext('urls', 'complete-cas/')), OpenidViews.complete_cas_signin, name='user_complete_cas_signin'), re_path( diff --git a/askbot/deps/django_authopenid/util.py b/askbot/deps/django_authopenid/util.py index 52487a2af0..6fdcc02561 100644 --- a/askbot/deps/django_authopenid/util.py +++ b/askbot/deps/django_authopenid/util.py @@ -184,7 +184,7 @@ def get_provider_name_by_endpoint(openid_url): providers. Returns None if no matching url was found. """ parsed_uri = urllib.parse.urlparse(openid_url) - base_url = '{uri.scheme}://{uri.netloc}'.format(uri=parsed_uri) + base_url = f'{parsed_uri.scheme}://{parsed_uri.netloc}' enabled_providers = get_enabled_login_providers() for provider_data in enabled_providers.values(): openid_url_match = (provider_data['type'].startswith('openid') and @@ -961,7 +961,7 @@ class OAuthConnection: def __new__(cls, provider_name): if provider_name == 'mediawiki': return providers.mediawiki.Provider() - return super(OAuthConnection, cls).__new__(cls) + return super().__new__(cls) def __init__(self, provider_name): """initializes oauth connection""" diff --git a/askbot/deps/django_authopenid/views.py b/askbot/deps/django_authopenid/views.py index 38de894a44..2bdb4bf428 100644 --- a/askbot/deps/django_authopenid/views.py +++ b/askbot/deps/django_authopenid/views.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2007, 2008, Benoît Chesneau # Copyright (c) 2007 Simon Willison, original work on django-openid # @@ -192,7 +191,7 @@ def ask_openid( auth_request = consumer.begin(openid_url) except DiscoveryFailure: openid_url = html.escape(openid_url) - msg = _("OpenID %(openid_url)s is invalid" % {'openid_url':openid_url}) # pylint: disable=consider-using-f-string + msg = _("OpenID {openid_url} is invalid".format(openid_url=openid_url)) # pylint: disable=consider-using-f-string logging.debug(msg) return signin_failure(request, msg) @@ -486,7 +485,7 @@ def signin(request): if next_url == reverse('user_signin'): # the sticky signin page - next_url = '%(next_url)s?next=%(next_jwt)s' % {'next_url': next_url, 'next_jwt': next_jwt} + next_url = f'{next_url}?next={next_jwt}' login_form = forms.LoginForm(initial={'next': next_jwt}) diff --git a/askbot/deps/group_messaging/disabled_tests.py b/askbot/deps/group_messaging/disabled_tests.py index 3eb3641014..2a7a7f577b 100644 --- a/askbot/deps/group_messaging/disabled_tests.py +++ b/askbot/deps/group_messaging/disabled_tests.py @@ -11,7 +11,7 @@ from django.contrib.auth.models import User, Group from django.test import TestCase from django.utils import timezone -from mock import Mock +from unittest.mock import Mock import time import urllib.parse diff --git a/askbot/deps/group_messaging/models.py b/askbot/deps/group_messaging/models.py index b6851e7eb6..58b2e2f94e 100644 --- a/askbot/deps/group_messaging/models.py +++ b/askbot/deps/group_messaging/models.py @@ -224,7 +224,7 @@ def create(self, **kwargs): kwargs['headline'] = headline[:MAX_HEADLINE_LENGTH] kwargs['html'] = parse_message(kwargs['text']) - message = super(MessageManager, self).create(**kwargs) + message = super().create(**kwargs) #creator of message saw it by definition #crate a "seen" memo for the sender, because we #don't want to inform the user about his/her own post diff --git a/askbot/deps/group_messaging/views.py b/askbot/deps/group_messaging/views.py index 5cb289e4ce..c6b0100330 100644 --- a/askbot/deps/group_messaging/views.py +++ b/askbot/deps/group_messaging/views.py @@ -214,7 +214,7 @@ class DeleteOrRestoreThread(ThreadsList): def __init__(self, action, *args, **kwargs): self.thread_action = action or 'delete' - super(DeleteOrRestoreThread, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) def post(self, request, thread_id=None): """process the post request: diff --git a/askbot/doc/source/conf.py b/askbot/doc/source/conf.py index 2813025e76..f0ac876202 100644 --- a/askbot/doc/source/conf.py +++ b/askbot/doc/source/conf.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # # Askbot documentation build configuration file, created by # sphinx-quickstart on Wed Jun 16 19:22:51 2010. diff --git a/askbot/exceptions.py b/askbot/exceptions.py index 61587c576f..b8cc10d019 100644 --- a/askbot/exceptions.py +++ b/askbot/exceptions.py @@ -13,7 +13,7 @@ class LoginRequired(exceptions.PermissionDenied): def __init__(self, msg=None): if msg is None: msg = _('Sorry, but anonymous visitors cannot access this function') - super(LoginRequired, self).__init__(msg) + super().__init__(msg) class InsufficientReputation(exceptions.PermissionDenied): diff --git a/askbot/feed.py b/askbot/feed.py index ffda2f6c8d..36486ee510 100644 --- a/askbot/feed.py +++ b/askbot/feed.py @@ -102,9 +102,9 @@ def item_title(self, item): if item.post_type == "question": title = item.thread.title elif item.post_type == "answer": - title = 'Answer by %s for %s ' % (item.author, item.thread._question_post().summary) + title = f'Answer by {item.author} for {item.thread._question_post().summary} ' elif item.post_type == "comment": - title = 'Comment by %s for %s' % (item.author, item.parent.summary) + title = f'Comment by {item.author} for {item.parent.summary}' return title def item_description(self, item): @@ -196,4 +196,4 @@ def items(self, item): # hack to get the request object into the Feed class def get_feed(self, obj, request): self.request = request - return super(RssLastestQuestionsFeed, self).get_feed(obj, request) + return super().get_feed(obj, request) diff --git a/askbot/forms.py b/askbot/forms.py index 2954ec7919..1c45d4672c 100644 --- a/askbot/forms.py +++ b/askbot/forms.py @@ -192,7 +192,7 @@ def __init__(self, *args, **kwargs): country_choices = (('unknown', _('select country')),) + tuple(country_choices) kwargs['choices'] = kwargs.pop('choices', country_choices) kwargs['label'] = kwargs.pop('label', _('Country')) - super(CountryField, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) def clean(self, value): """Handles case of 'unknown' country selection @@ -213,7 +213,7 @@ def __init__(self, min_words=0, max_words=9999, field_name=None, self.min_words = min_words self.max_words = max_words self.field_name = field_name - super(CountedWordsField, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) def clean(self, value): # TODO: this field must be adapted to work with Chinese, etc. @@ -244,7 +244,7 @@ class AskbotReCaptchaField(ReCaptchaField): def __init__(self, *args, **kwargs): kwargs.setdefault('private_key', askbot_settings.RECAPTCHA_SECRET) kwargs.setdefault('public_key', askbot_settings.RECAPTCHA_KEY) - super(AskbotReCaptchaField, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) class LanguageField(forms.ChoiceField): @@ -252,7 +252,7 @@ class LanguageField(forms.ChoiceField): def __init__(self, *args, **kwargs): kwargs['choices'] = django_settings.LANGUAGES kwargs['label'] = _('Select language') - super(LanguageField, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) class LanguageForm(forms.Form): @@ -275,7 +275,7 @@ class TranslateUrlForm(forms.Form): class SuppressEmailField(forms.BooleanField): def __init__(self): - super(SuppressEmailField, self).__init__() + super().__init__() self.required = False self.label = _("minor edit (don't send alerts)") @@ -298,7 +298,7 @@ def clean(self, value): class TitleField(forms.CharField): """Field receiving question title""" def __init__(self, *args, **kwargs): - super(TitleField, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.required = kwargs.get('required', True) self.widget = forms.TextInput( attrs={'size': 70, 'autocomplete': 'off'}) @@ -353,7 +353,7 @@ def __init__(self, *args, **kwargs): widget_attrs = kwargs.pop('attrs', {}) widget_attrs.setdefault('id', 'editor') - super(EditorField, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.required = True if askbot_settings.EDITOR_TYPE == 'markdown': self.widget = forms.Textarea(attrs=widget_attrs) @@ -389,7 +389,7 @@ class QuestionEditorField(EditorField): def __init__(self, *args, **kwargs): user = kwargs.pop('user', None) - super(QuestionEditorField, self).__init__( + super().__init__( user=user, *args, **kwargs) self.min_length = askbot_settings.MIN_QUESTION_BODY_LENGTH @@ -398,7 +398,7 @@ class AnswerEditorField(EditorField): """Editor field for answers""" def __init__(self, *args, **kwargs): - super(AnswerEditorField, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.min_length = askbot_settings.MIN_ANSWER_BODY_LENGTH @@ -447,7 +447,7 @@ class TagNamesField(forms.CharField): """field that receives AskBot tag names""" def __init__(self, *args, **kwargs): - super(TagNamesField, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.required = kwargs.get('required', askbot_settings.TAGS_ARE_REQUIRED) self.widget = forms.TextInput( @@ -469,7 +469,7 @@ def __init__(self, *args, **kwargs): def clean(self, value): from askbot import models - value = super(TagNamesField, self).clean(value) + value = super().clean(value) data = value.strip(const.TAG_STRIP_CHARS) if not data: if askbot_settings.TAGS_ARE_REQUIRED: @@ -516,7 +516,7 @@ class WikiField(forms.BooleanField): """ def __init__(self, *args, **kwargs): - super(WikiField, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.required = False self.initial = False self.label = _( @@ -532,7 +532,7 @@ class PageField(forms.IntegerField): def __init__(self, *args, **kwargs): self.required = False - super(PageField, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) def clean(self, value): try: @@ -545,7 +545,7 @@ def clean(self, value): class SortField(forms.ChoiceField): def __init__(self, *args, **kwargs): self.default = kwargs.pop('default', '') - super(SortField, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) def clean(self, value): value = value or self.default @@ -557,7 +557,7 @@ def clean(self, value): class SummaryField(forms.CharField): def __init__(self, *args, **kwargs): - super(SummaryField, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.required = False self.widget = forms.TextInput( attrs={'size': 50, 'autocomplete': 'off'}) @@ -575,7 +575,7 @@ class EditorForm(forms.Form): in the __init__() function""" def __init__(self, attrs=None, user=None, editor_attrs=None): - super(EditorForm, self).__init__() + super().__init__() editor_attrs = editor_attrs or {} self.fields['editor'] = EditorField(attrs=attrs, editor_attrs=editor_attrs, @@ -602,7 +602,7 @@ class ShowQuestionForm(forms.Form): page = PageField() def __init__(self, *args, **kwargs): - super(ShowQuestionForm, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) # uses livesettings for the default so the 'sort' field # must be added in the __init__ self.fields['sort'] = SortField( @@ -724,7 +724,7 @@ def __init__(self, *arg, **kwarg): moderator = kwarg.pop('moderator') subject = kwarg.pop('subject') - super(ChangeUserStatusForm, self).__init__(*arg, **kwarg) + super().__init__(*arg, **kwarg) # Select user_status_choices depending on status of the moderator if moderator.is_authenticated: @@ -827,7 +827,7 @@ class FeedbackForm(forms.Form): next = NextUrlField() def __init__(self, user=None, *args, **kwargs): - super(FeedbackForm, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.user = user if should_use_recaptcha(user): self.fields['recaptcha'] = AskbotReCaptchaField() @@ -846,7 +846,7 @@ def clean_name(self): return name def clean(self): - super(FeedbackForm, self).clean() + super().clean() if self.user and self.user.is_anonymous: need_email = not bool(self.cleaned_data.get('no_email', False)) email = self.cleaned_data.get('email', '').strip() @@ -857,7 +857,7 @@ def clean(self): return self.cleaned_data -class FormWithHideableFields(object): +class FormWithHideableFields: """allows to swap a field widget to HiddenInput() and back""" def hide_field(self, name): @@ -889,7 +889,7 @@ class PostPrivatelyForm(forms.Form, FormWithHideableFields): def __init__(self, *args, **kwargs): user = kwargs.pop('user', None) self._user = user - super(PostPrivatelyForm, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) if self.allows_post_privately() == False: self.hide_field('post_privately') @@ -1002,7 +1002,7 @@ class AskForm(PostAsSomeoneForm, PostPrivatelyForm): def __init__(self, *args, **kwargs): user = kwargs.get('user', None) - super(AskForm, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) # It's important that this field is set up dynamically self.fields['title'] = TitleField() self.fields['tags'] = TagNamesField() @@ -1048,7 +1048,7 @@ class AskWidgetForm(forms.Form, FormWithHideableFields): def __init__(self, include_text=True, *args, **kwargs): user = kwargs.pop('user', None) - super(AskWidgetForm, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.fields['title'] = TitleField() # hide ask_anonymously field if user.is_anonymous or not askbot_settings.ALLOW_ASK_ANONYMOUSLY: @@ -1073,7 +1073,7 @@ class CreateAskWidgetForm(forms.Form, FormWithHideableFields): def __init__(self, *args, **kwargs): from askbot.models import Group, Tag - super(CreateAskWidgetForm, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.fields['group'] = forms.ModelChoiceField( queryset=Group.objects.exclude_personal(), required=False) self.fields['tag'] = forms.ModelChoiceField( @@ -1094,7 +1094,7 @@ class CreateQuestionWidgetForm(forms.Form, FormWithHideableFields): def __init__(self, *args, **kwargs): from askbot.models import Group - super(CreateQuestionWidgetForm, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.fields['tagnames'] = TagNamesField() self.fields['group'] = forms.ModelChoiceField( queryset=Group.objects.exclude(name__startswith='_internal'), @@ -1130,7 +1130,7 @@ class AskByEmailForm(forms.Form): def __init__(self, *args, **kwargs): user = kwargs.pop('user', None) - super(AskByEmailForm, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.fields['body_text'] = QuestionEditorField(user=user) def clean_sender(self): @@ -1191,7 +1191,7 @@ class AnswerForm(PostAsSomeoneForm, PostPrivatelyForm): widget=forms.TextInput(attrs={'size': 40, 'class': 'openid-input'})) def __init__(self, *args, **kwargs): - super(AnswerForm, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) user = kwargs['user'] # empty label on purpose self.fields['text'] = AnswerEditorField(label='', user=user) @@ -1233,7 +1233,7 @@ def clean_cancel_vote(self): class CloseForm(forms.Form): def __init__(self, *args, **kwargs): - super(CloseForm, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) reasons = askbot_settings.QUESTION_CLOSE_REASONS close_choices = tuple([tuple([reason, reason]) for reason in reasons]) self.fields['reason'] = forms.ChoiceField(choices=close_choices) @@ -1243,7 +1243,7 @@ class RetagQuestionForm(forms.Form): def __init__(self, question, *args, **kwargs): """initialize the default values""" - super(RetagQuestionForm, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.fields['tags'] = TagNamesField() self.fields['tags'].initial = question.thread.tagnames @@ -1255,15 +1255,14 @@ class RevisionForm(forms.Form): revision = forms.ChoiceField(widget=forms.Select()) def __init__(self, post, latest_revision, *args, **kwargs): - super(RevisionForm, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) revisions = post.revisions.values_list( 'revision', 'author__username', 'revised_at', 'summary' ) date_format = '%c' rev_choices = list() for r in revisions: - rev_details = '%s - %s (%s) %s' % ( - r[0], r[1], r[2].strftime(date_format), r[3]) + rev_details = f'{r[0]} - {r[1]} ({r[2].strftime(date_format)}) {r[3]}' rev_choices.append((r[0], rev_details)) self.fields['revision'].choices = rev_choices @@ -1278,7 +1277,7 @@ class EditAnswerForm(PostAsSomeoneForm, PostPrivatelyForm): def __init__(self, answer, revision, *args, **kwargs): self.answer = answer user = kwargs.get('user', None) - super(EditAnswerForm, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) # it is important to add this field dynamically # label is empty on purpose self.fields['text'] = AnswerEditorField(label='', user=user) @@ -1289,7 +1288,7 @@ def __init__(self, answer, revision, *args, **kwargs): self.fields['recaptcha'] = AskbotReCaptchaField() def has_changed(self): - if super(EditAnswerForm, self).has_changed(): + if super().has_changed(): return True if askbot_settings.GROUPS_ENABLED: return self.answer.is_private() \ @@ -1336,7 +1335,7 @@ class EditUserForm(forms.Form): widget=forms.TextInput(attrs={'size': 35})) def __init__(self, user, *args, **kwargs): - super(EditUserForm, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) logging.debug('initializing the form') if askbot_settings.EDITABLE_SCREEN_NAME: @@ -1396,7 +1395,7 @@ class TagFilterSelectionForm(forms.ModelForm): widget=forms.RadioSelect) def __init__(self, *args, **kwargs): - super(TagFilterSelectionForm, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) choices = get_tag_email_filter_strategy_choices() self.fields['email_tag_filter_strategy'].choices = choices @@ -1406,7 +1405,7 @@ class Meta: def save(self): before = self.instance.email_tag_filter_strategy - super(TagFilterSelectionForm, self).save() + super().save() after = self.instance.email_tag_filter_strategy return before != after @@ -1415,7 +1414,7 @@ class EmailFeedSettingField(forms.ChoiceField): def __init__(self, *arg, **kwarg): kwarg['choices'] = kwarg.get('choices', const.NOTIFICATION_DELIVERY_SCHEDULE_CHOICES) kwarg['widget'] = forms.RadioSelect - super(EmailFeedSettingField, self).__init__(*arg, **kwarg) + super().__init__(*arg, **kwarg) class EditUserEmailFeedsForm(forms.Form): @@ -1445,7 +1444,7 @@ class EditUserEmailFeedsForm(forms.Form): } def __init__(self, *args, **kwargs): - super(EditUserEmailFeedsForm, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.fields = OrderedDict(( ('asked_by_me', EmailFeedSettingField(label=askbot_settings.WORDS_ASKED_BY_ME)), ('answered_by_me', EmailFeedSettingField(label=askbot_settings.WORDS_ANSWERED_BY_ME)), @@ -1548,13 +1547,13 @@ def __init__(self, **kwargs): ('n', _('no %(sitename)s email please, thanks') % {'sitename': askbot_settings.APP_SHORT_NAME}) ) - super(SubscribeForEmailUpdatesField, self).__init__(**kwargs) + super().__init__(**kwargs) class SimpleEmailSubscribeForm(forms.Form): def __init__(self, *args, **kwargs): - super(SimpleEmailSubscribeForm, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.fields['subscribe'] = SubscribeForEmailUpdatesField() def save(self, user=None): @@ -1628,7 +1627,7 @@ class BulkTagSubscriptionForm(forms.Form): def __init__(self, *args, **kwargs): from askbot.models import BulkTagSubscription, Tag, Group - super(BulkTagSubscriptionForm, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.fields['users'] = forms.ModelMultipleChoiceField(queryset=User.objects.all()) self.fields['tags'] = TagNamesField(label=_("Tags"), help_text=' ') if askbot_settings.GROUPS_ENABLED: @@ -1696,7 +1695,7 @@ class NewCommentForm(forms.Form): avatar_size = forms.IntegerField() def __init__(self, *args, **kwargs): - super(NewCommentForm, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.fields['comment'] = forms.CharField( max_length=askbot_settings.MAX_COMMENT_LENGTH) diff --git a/askbot/importers/stackexchange/management/__init__.py b/askbot/importers/stackexchange/management/__init__.py index 3c575cb6b1..2858194e65 100644 --- a/askbot/importers/stackexchange/management/__init__.py +++ b/askbot/importers/stackexchange/management/__init__.py @@ -6,7 +6,7 @@ class ImporterThread(threading.Thread): def __init__(self, dump_file = None): self.dump_file = dump_file - super(ImporterThread, self).__init__() + super().__init__() def run(self): management.call_command('load_stackexchange', self.dump_file) diff --git a/askbot/importers/stackexchange/management/commands/load_stackexchange.py b/askbot/importers/stackexchange/management/commands/load_stackexchange.py index 4b1cca9231..6725d94d46 100644 --- a/askbot/importers/stackexchange/management/commands/load_stackexchange.py +++ b/askbot/importers/stackexchange/management/commands/load_stackexchange.py @@ -63,7 +63,7 @@ COMMENT = {} NUMBERED_NAME_RE = re.compile(r'^(.*)\*(\d+)\*$') -class X(object):# +class X:# """class with methods for handling some details of SE --> ASKBOT mapping """ @@ -155,7 +155,7 @@ def get_message_text(cls, se_m): if se_m.user.id == -1: return None url = cls.get_user(se_m.user).get_profile_url() - return '%s' % (url,text) + return f'{text}' return None @classmethod @@ -199,7 +199,7 @@ def get_post_revision_group_types(cls, rev_group): if len(rev_types) > 1 and all([t in exclusive for t in rev_types]): tstr = ','.join(rev_types) gstr = ','.join([str(rev.id) for rev in rev_group]) - msg = 'incompatible revision types %s in PostHistory %s' % (tstr,gstr) + msg = f'incompatible revision types {tstr} in PostHistory {gstr}' raise Exception(msg) return rev_types @@ -872,7 +872,7 @@ def load_xml_file(self, item): xml_data = self.zipfile.read(xml_path) tree = et.fromstring(xml_data) - print('loading from %s to %s' % (xml_path, table_name)) + print(f'loading from {xml_path} to {table_name}') model = models.get_model('stackexchange', table_name) i = 0 rows = tree.findall('.//row') @@ -915,7 +915,7 @@ def transfer_users(self): if se_u.password_id is not None: pw = se.Password.objects.get(id = se_u.password_id) - u.password = 'sha1$%s$%s' % (pw.salt, pw.password) + u.password = f'sha1${pw.salt}${pw.password}' else: u.set_unusable_password() diff --git a/askbot/importers/stackexchange/parse_models.py b/askbot/importers/stackexchange/parse_models.py index c521631af6..052744de9e 100644 --- a/askbot/importers/stackexchange/parse_models.py +++ b/askbot/importers/stackexchange/parse_models.py @@ -50,7 +50,7 @@ def get_table_name(name): out += '2'.join(bits) return out -class DjangoModel(object): +class DjangoModel: def __init__(self, name): self.name = get_table_name(name) self.fields = [] @@ -63,7 +63,7 @@ def __str__(self): out += ' %s\n' % str(f) return out -class DjangoField(object): +class DjangoField: def __init__(self, name, type, restriction = None): self.name = camel_to_python(name) if self.name == 'class': @@ -74,10 +74,10 @@ def __init__(self, name, type, restriction = None): self.relation = None def __str__(self): - out = '%s = %s(' % (self.name, types[self.type]) + out = f'{self.name} = {types[self.type]}(' if self.type == 'FK': out += "'%s'" % self.relation - out += ", related_name='%s_by_%s_set'" % (self.table.name, self.name) + out += f", related_name='{self.table.name}_by_{self.name}_set'" out += ', null=True'#nullable to make life easier elif self.type == 'PK': out += 'primary_key=True' @@ -105,7 +105,7 @@ def __init__(self, source_name): bits = source_name.split('Id') if len(bits) == 2 and bits[1] == '': name = bits[0] - super(DjangoFK, self).__init__(name, 'FK') + super().__init__(name, 'FK') self.set_relation(name) def set_relation(self, name): diff --git a/askbot/importers/zendesk/management/commands/import_zendesk.py b/askbot/importers/zendesk/management/commands/import_zendesk.py index 9e326c7f44..8af8ef5ddc 100644 --- a/askbot/importers/zendesk/management/commands/import_zendesk.py +++ b/askbot/importers/zendesk/management/commands/import_zendesk.py @@ -712,7 +712,7 @@ def read_xml_file(self, todo: support blank values vs. nulls for strings """ cursor = connection.cursor() - cursor.execute('TRUNCATE TABLE "{0}" CASCADE'.format(model._meta.db_table)) + cursor.execute(f'TRUNCATE TABLE "{model._meta.db_table}" CASCADE') xml = self.get_file(file_name) items_saved = 0 for xml_entry in xml.findall(entry_name): @@ -999,7 +999,7 @@ def import_forums(self, forums, tags, date_filter): if tags: print("Filtering forum posts by tags: %s" % tags) if date_filter: - print("Filtering forum post by dates between %s and %s" % (date_filter[0], date_filter[1])) + print(f"Filtering forum post by dates between {date_filter[0]} and {date_filter[1]}") print("Importing forums... ") print("="*64) for forum in forums: @@ -1069,7 +1069,7 @@ def import_tickets(self, tags, date_filter): if tags: print("Filtering tickets by tags: %s" % tags) if date_filter: - print("Filtering tickets by dates between %s and %s" % (date_filter[0], date_filter[1])) + print(f"Filtering tickets by dates between {date_filter[0]} and {date_filter[1]}") sys.stdout.write("Importing tickets: ") ticket_count = 0 for ticket in zendesk_models.Ticket.objects.all(): diff --git a/askbot/mail/__init__.py b/askbot/mail/__init__.py index cc7674fae3..83ad2a90b2 100644 --- a/askbot/mail/__init__.py +++ b/askbot/mail/__init__.py @@ -218,7 +218,7 @@ def process_attachment(attachment): file storage object """ file_url = store_file(attachment.name, attachment) - markdown_link = '[%s](%s) ' % (attachment.name, file_url) + markdown_link = f'[{attachment.name}]({file_url}) ' file_extension = os.path.splitext(attachment.name)[1] #todo: this is a hack - use content type if file_extension.lower() in ('.png', '.jpg', '.jpeg', '.gif'): diff --git a/askbot/mail/messages.py b/askbot/mail/messages.py index 5006e96726..cf8538d8be 100644 --- a/askbot/mail/messages.py +++ b/askbot/mail/messages.py @@ -29,7 +29,7 @@ def get_question(): return Post.objects.filter(post_type='question')[0] -class BaseEmail(object): +class BaseEmail: """Base class for templated emails. Besides sending formatted emails, @@ -303,27 +303,27 @@ def get_thread_headers(self, post, orig_post, update): that emails appear as threaded conversations in gmail""" suffix_id = django_settings.SERVER_EMAIL if update == const.TYPE_ACTIVITY_ASK_QUESTION: - msg_id = "" % (post.id, suffix_id) + msg_id = f"" headers = {'Message-ID': msg_id} elif update == const.TYPE_ACTIVITY_ANSWER: - msg_id = "" % (post.id, suffix_id) - orig_id = "" % (orig_post.id, suffix_id) + msg_id = f"" + orig_id = f"" headers = {'Message-ID': msg_id, 'In-Reply-To': orig_id} elif update == const.TYPE_ACTIVITY_UPDATE_QUESTION: - msg_id = "" % (post.id, post.last_edited_at, suffix_id) - orig_id = "" % (orig_post.id, suffix_id) + msg_id = f"" + orig_id = f"" headers = {'Message-ID': msg_id, 'In-Reply-To': orig_id} elif update == const.TYPE_ACTIVITY_COMMENT_QUESTION: - msg_id = "" % (post.id, suffix_id) - orig_id = "" % (orig_post.id, suffix_id) + msg_id = f"" + orig_id = f"" headers = {'Message-ID': msg_id, 'In-Reply-To': orig_id} elif update == const.TYPE_ACTIVITY_UPDATE_ANSWER: - msg_id = "" % (post.id, post.last_edited_at, suffix_id) - orig_id = "" % (orig_post.id, suffix_id) + msg_id = f"" + orig_id = f"" headers = {'Message-ID': msg_id, 'In-Reply-To': orig_id} elif update == const.TYPE_ACTIVITY_COMMENT_ANSWER: - msg_id = "" % (post.id, suffix_id) - orig_id = "" % (orig_post.id, suffix_id) + msg_id = f"" + orig_id = f"" headers = {'Message-ID': msg_id, 'In-Reply-To': orig_id} else: # Unknown type -> Can't set headers diff --git a/askbot/mail/parsing.py b/askbot/mail/parsing.py index 2653075213..25874f66b4 100644 --- a/askbot/mail/parsing.py +++ b/askbot/mail/parsing.py @@ -125,7 +125,7 @@ def strip_leading_empties(text): def strip_trailing_sender_references(text, email_address): server_email = 'ask@' + askbot_settings.REPLY_BY_EMAIL_HOSTNAME - email_pattern = '(%s|%s)' % (email_address, server_email) + email_pattern = f'({email_address}|{server_email})' pattern = r'\n[^\n]*%s[^\n]*$' % email_pattern return re.sub(pattern, '', text, re.IGNORECASE) diff --git a/askbot/management/commands/apply_hinted_tags.py b/askbot/management/commands/apply_hinted_tags.py index b2c777745c..2b68ba8726 100644 --- a/askbot/management/commands/apply_hinted_tags.py +++ b/askbot/management/commands/apply_hinted_tags.py @@ -32,7 +32,7 @@ def handle(self, *args, **kwargs): raise CommandError('parameter --tags-file is required') try: tags_input = open(kwargs['tags_file']).read() - except IOError: + except OSError: raise CommandError('file "%s" not found' % kwargs['tags_file']) tags_list = [v.strip() for v in tags_input.split('\n')] diff --git a/askbot/management/commands/askbot_add_osqa_content.py b/askbot/management/commands/askbot_add_osqa_content.py index 0630f25f49..15e9fdda48 100644 --- a/askbot/management/commands/askbot_add_osqa_content.py +++ b/askbot/management/commands/askbot_add_osqa_content.py @@ -108,7 +108,7 @@ def handle(self, *args, **options): self.redirect_format = self.get_redirect_format(options['redirect_format']) dump_file_name = options['xml_file'] - xml = open(dump_file_name, 'r').read() + xml = open(dump_file_name).read() self.soup = BeautifulSoup(xml, ['lxml', 'xml', 'lxml-xml']) # site settings diff --git a/askbot/management/commands/askbot_add_test_content.py b/askbot/management/commands/askbot_add_test_content.py index 53b2007696..63f44abecf 100644 --- a/askbot/management/commands/askbot_add_test_content.py +++ b/askbot/management/commands/askbot_add_test_content.py @@ -165,7 +165,7 @@ def create_questions(self, users): tags = tags, ) - self.print_if_verbose("Created Question '%s' with tags: '%s'" % ( + self.print_if_verbose("Created Question '{}' with tags: '{}'".format( active_question.thread.title, tags,) ) return active_question diff --git a/askbot/management/commands/askbot_add_user.py b/askbot/management/commands/askbot_add_user.py index 5e5c0eb6b3..c5ece6eeac 100644 --- a/askbot/management/commands/askbot_add_user.py +++ b/askbot/management/commands/askbot_add_user.py @@ -74,8 +74,7 @@ def handle(self, *args, **options): status = options['status'] if status not in 'wamdsb': raise CommandError( - 'Illegal value of --status %s. Allowed user statuses are: %s' \ - % (status, STATUS_INFO) + f'Illegal value of --status {status}. Allowed user statuses are: {STATUS_INFO}' ) user = models.User.objects.create_user(username, email) diff --git a/askbot/management/commands/askbot_add_xml_content.py b/askbot/management/commands/askbot_add_xml_content.py index ef50dfc7a3..a28e8fa070 100644 --- a/askbot/management/commands/askbot_add_xml_content.py +++ b/askbot/management/commands/askbot_add_xml_content.py @@ -200,7 +200,7 @@ def import_users(self): #copy the data if from_user.username != to_user.username: names = (from_user.username, to_user.username) - log_info['notify_user'].append('Your user name has changed from %s to %s' % names) + log_info['notify_user'].append('Your user name has changed from {} to {}'.format(*names)) self.copy_string_parameter(from_user, to_user, 'first_name') self.copy_string_parameter(from_user, to_user, 'last_name') diff --git a/askbot/management/commands/askbot_deduplicate_localized_profiles.py b/askbot/management/commands/askbot_deduplicate_localized_profiles.py index f3f77cb84b..09b21c5222 100644 --- a/askbot/management/commands/askbot_deduplicate_localized_profiles.py +++ b/askbot/management/commands/askbot_deduplicate_localized_profiles.py @@ -26,4 +26,4 @@ def handle(self, *args, **kwargs): item.delete() deleted_count += 1 - print('deleted {} items'.format(deleted_count)) + print(f'deleted {deleted_count} items') diff --git a/askbot/management/commands/askbot_delete_orphan_group_memberships.py b/askbot/management/commands/askbot_delete_orphan_group_memberships.py index 6530ffcc16..5b84b4766f 100644 --- a/askbot/management/commands/askbot_delete_orphan_group_memberships.py +++ b/askbot/management/commands/askbot_delete_orphan_group_memberships.py @@ -14,7 +14,7 @@ def handle(self, *args, **kwargs): #pylint: disable=unused-argument group_ids = Group.objects.values_list('pk', flat=True) #3) calc the diff missing_group_ids = set(memb_group_ids) - set(group_ids) - print('Found {} missing groups'.format(len(missing_group_ids))) + print(f'Found {len(missing_group_ids)} missing groups') bad_gms = GroupMembership.objects.filter(group_id__in=missing_group_ids) print('Deleting bad group memberships') bad_gms.delete() diff --git a/askbot/management/commands/askbot_export_user_data.py b/askbot/management/commands/askbot_export_user_data.py index c3b7b31584..990dab5ffd 100644 --- a/askbot/management/commands/askbot_export_user_data.py +++ b/askbot/management/commands/askbot_export_user_data.py @@ -37,7 +37,7 @@ def handle(self, *args, **options): # pylint: disable=too-many-locals try: user = User.objects.get(pk=uid) except User.DoesNotExist: # pylint: disable=no-member - raise CommandError('User with id {} does not exist'.format(uid)) + raise CommandError(f'User with id {uid} does not exist') lang_data = dict() for profile in user.localized_askbot_profiles.all(): @@ -104,7 +104,7 @@ def zip_tempdir(cls, temp_dir, file_name): """Zip contents of the temp directory into the desired target file""" if os.path.exists(file_name): - raise CommandError('File {} already exists'.format(file_name)) + raise CommandError(f'File {file_name} already exists') zip_path = os.path.abspath(file_name) file_paths = list_directory_files(temp_dir) diff --git a/askbot/management/commands/askbot_fix_thread_points.py b/askbot/management/commands/askbot_fix_thread_points.py index 64da325361..e9086964a3 100644 --- a/askbot/management/commands/askbot_fix_thread_points.py +++ b/askbot/management/commands/askbot_fix_thread_points.py @@ -16,7 +16,7 @@ def handle(self, *args, **kwargs): .exclude(points=F('thread__points')) .select_related('thread')) - self.stdout.write('Fixing {0} threads...'.format(questions.count())) + self.stdout.write(f'Fixing {questions.count()} threads...') for post in questions: with override(post.thread.language_code): diff --git a/askbot/management/commands/askbot_import_jive.py b/askbot/management/commands/askbot_import_jive.py index e31e940a48..d0da01babe 100644 --- a/askbot/management/commands/askbot_import_jive.py +++ b/askbot/management/commands/askbot_import_jive.py @@ -148,7 +148,7 @@ def add_arguments(self, parser): ) def __init__(self, *args, **kwargs): - super(Command, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) #relax certain settings askbot_settings.update('LIMIT_ONE_ANSWER_PER_USER', False) askbot_settings.update('MAX_COMMENT_LENGTH', 1000000) @@ -165,7 +165,7 @@ def handle(self, *args, **kwargs): translation.activate(django_settings.LANGUAGE_CODE) assert len(args) == 1, 'Dump file name is required' dump_file_name = args[0] - xml = open(dump_file_name, 'r').read() + xml = open(dump_file_name).read() soup = BeautifulSoup(xml, ['lxml', 'xml']) self.soup = soup url_prop = self.soup.find('Property', attrs={'name': 'jiveURL'}) @@ -194,7 +194,7 @@ def add_legacy_links(self): for question in ProgressBar(questions.iterator(), count, message): thread_id = question.old_question_id jive_url = self.jive_url - old_url = '%s/thread.jspa?threadID=%s' % (jive_url, thread_id) + old_url = f'{jive_url}/thread.jspa?threadID={thread_id}' question.text += template % old_url question.save() transaction.commit() @@ -309,7 +309,7 @@ def add_attachments_to_post(self, post, attachments): dest_file = os.path.join(django_settings.MEDIA_ROOT, file_name) shutil.copyfile(source_file, dest_file) # add link to file to the post text - post.text += '# [%s|%s%s]\n' % (name, django_settings.MEDIA_URL, file_name) + post.text += f'# [{name}|{django_settings.MEDIA_URL}{file_name}]\n' def import_thread(self, thread, tag_name): """import individual thread""" diff --git a/askbot/management/commands/base.py b/askbot/management/commands/base.py index 6a0078f5f2..235120ed65 100644 --- a/askbot/management/commands/base.py +++ b/askbot/management/commands/base.py @@ -73,7 +73,7 @@ def read_xml_file(self, filename): """reads xml data int BeautifulSoup instance""" if not os.path.isfile(filename): raise CommandError(f'File {filename} does not exist') % filename - xml = open(filename, 'r', encoding='utf-8').read() + xml = open(filename, encoding='utf-8').read() self.soup = BeautifulSoup(xml, ['lxml', 'xml']) def remember_message_ids(self): diff --git a/askbot/management/commands/build_thread_summary_cache.py b/askbot/management/commands/build_thread_summary_cache.py index b07950581f..58446471dc 100644 --- a/askbot/management/commands/build_thread_summary_cache.py +++ b/askbot/management/commands/build_thread_summary_cache.py @@ -20,7 +20,7 @@ def handle(self, **options): languages = options['language'] or (django_settings.LANGUAGE_CODE,) for l in languages: translation.activate(l) - message = 'Rebuilding {0} thread summary cache'.format(l.upper()) + message = f'Rebuilding {l.upper()} thread summary cache' count = Thread.objects.count() for thread in ProgressBar(Thread.objects.iterator(), count, message): diff --git a/askbot/management/commands/create_tag_synonyms.py b/askbot/management/commands/create_tag_synonyms.py index 282f1473a4..a4998ba093 100644 --- a/askbot/management/commands/create_tag_synonyms.py +++ b/askbot/management/commands/create_tag_synonyms.py @@ -85,8 +85,8 @@ def handle(self, *args, **options): source_tag = models.Tag.objects.get(name=source_tag_name, language_code=options['lang']) except models.Tag.DoesNotExist: if not options.get('is_force', False): - prompt = """source tag %s doesn't exist, are you sure you want to create a TagSynonym - %s ==> %s?""" % (source_tag_name, source_tag_name, target_tag_name) + prompt = """source tag {} doesn't exist, are you sure you want to create a TagSynonym + {} ==> {}?""".format(source_tag_name, source_tag_name, target_tag_name) choice = console.choice_dialog(prompt, choices=('yes', 'no')) if choice == 'no': print('Cancled') @@ -107,9 +107,8 @@ def handle(self, *args, **options): language_code=options['lang'] ) if not options.get('is_force', False): - prompt = """There exists a TagSynonym %s ==> %s, - hence we will create a tag synonym %s ==> %s instead. Proceed?""" % (tag_synonym_tmp.source_tag_name, tag_synonym_tmp.target_tag_name, - source_tag_name, tag_synonym_tmp.target_tag_name) + prompt = f"""There exists a TagSynonym {tag_synonym_tmp.source_tag_name} ==> {tag_synonym_tmp.target_tag_name}, + hence we will create a tag synonym {source_tag_name} ==> {tag_synonym_tmp.target_tag_name} instead. Proceed?""" choice = console.choice_dialog(prompt, choices=('yes', 'no')) if choice == 'no': print('Cancled') diff --git a/askbot/management/commands/export_osqa.py b/askbot/management/commands/export_osqa.py index 69d3c99fbd..73ee3db702 100644 --- a/askbot/management/commands/export_osqa.py +++ b/askbot/management/commands/export_osqa.py @@ -100,7 +100,7 @@ def handle(self, *app_labels, **options): continue model = apps.get_model(app_label, model_label) if model is None: - raise CommandError("Unknown model: %s.%s" % (app_label, model_label)) + raise CommandError(f"Unknown model: {app_label}.{model_label}") if app in list(app_list.keys()): if app_list[app] and model not in app_list[app]: @@ -205,7 +205,7 @@ def sort_dependencies(app_list): skipped.append((model, deps)) if not changed: raise CommandError("Can't resolve dependencies for %s in serialized app list." % - ', '.join('%s.%s' % (model._meta.app_label, model._meta.object_name) + ', '.join(f'{model._meta.app_label}.{model._meta.object_name}' for model, deps in sorted(skipped, key=lambda obj: obj[0].__name__)) ) model_dependencies = skipped diff --git a/askbot/management/commands/fix_inbox_counts.py b/askbot/management/commands/fix_inbox_counts.py index 09871a16da..42b115cacd 100644 --- a/askbot/management/commands/fix_inbox_counts.py +++ b/askbot/management/commands/fix_inbox_counts.py @@ -30,4 +30,4 @@ def __init__(self, *args, **kwargs): 'changed_count_message': 'Corrected records for %d users', 'nothing_changed_message': 'No problems found' },) - super(Command, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) diff --git a/askbot/management/commands/fix_superuser_status.py b/askbot/management/commands/fix_superuser_status.py index 14201217d4..4579b4a3f2 100644 --- a/askbot/management/commands/fix_superuser_status.py +++ b/askbot/management/commands/fix_superuser_status.py @@ -37,4 +37,4 @@ def handle(self, *args, **kwargs): rebuild_profile_caches(profiles) - self.stdout.write('Fixed the status of {0} users.'.format(fixed)) + self.stdout.write(f'Fixed the status of {fixed} users.') diff --git a/askbot/management/commands/jinja2_makemessages.py b/askbot/management/commands/jinja2_makemessages.py index fb772ed94e..c0278d1ae0 100644 --- a/askbot/management/commands/jinja2_makemessages.py +++ b/askbot/management/commands/jinja2_makemessages.py @@ -50,7 +50,7 @@ def handle(self, *args, **options): trans_real.plural_re.pattern + '|' + r"""^-?\s*pluralize(\s+\w+)?\s*-?$""") try: - super(Command, self).handle(*args, **options) + super().handle(*args, **options) finally: trans_real.endblock_re = old_endblock_re trans_real.block_re = old_block_re diff --git a/askbot/management/commands/rename_tags.py b/askbot/management/commands/rename_tags.py index d9b9a5c342..837186df4e 100644 --- a/askbot/management/commands/rename_tags.py +++ b/askbot/management/commands/rename_tags.py @@ -21,9 +21,9 @@ def get_admin(seed_user_id = None): if admin.id != seed_user_id: if seed_user_id is None: - prompt = """You have not provided user id for the moderator + prompt = f"""You have not provided user id for the moderator who to assign as the performer this operation, the default moderator is -%s, id=%s. Will that work?""" % (admin.username, admin.id) +{admin.username}, id={admin.id}. Will that work?""" else: prompt = """User with id=%s is not a moderator would you like to select default moderator %s, id=%d diff --git a/askbot/management/commands/rename_tags_id.py b/askbot/management/commands/rename_tags_id.py index 41e6143945..beda7826e4 100644 --- a/askbot/management/commands/rename_tags_id.py +++ b/askbot/management/commands/rename_tags_id.py @@ -27,8 +27,7 @@ def get_tags_by_ids(tag_ids): def get_similar_tags_from_strings(tag_strings, tag_name): """returns a list of tags, similar to tag_name from a set of questions""" - grab_pattern = r'\b([%(ch)s]*%(nm)s[%(ch)s]*)\b' % \ - {'ch': const.TAG_CHARS, 'nm': tag_name} + grab_pattern = rf'\b([{const.TAG_CHARS}]*{tag_name}[{const.TAG_CHARS}]*)\b' grab_re = re.compile(grab_pattern, re.IGNORECASE) similar_tags = set() @@ -148,13 +147,13 @@ def handle(self, *args, **options): formatted_to_tag_names = format_tag_name_list(to_tags) if not options.get('is_force', False): - prompt = 'Rename tags %s --> %s?' % (formatted_from_tag_names, formatted_to_tag_names) + prompt = f'Rename tags {formatted_from_tag_names} --> {formatted_to_tag_names}?' choice = console.choice_dialog(prompt, choices=('yes', 'no')) if choice == 'no': print('Canceled') sys.exit() else: - print('Renaming tags %s --> %s' % (formatted_from_tag_names, formatted_to_tag_names)) + print(f'Renaming tags {formatted_from_tag_names} --> {formatted_to_tag_names}') sys.stdout.write('Processing:') from_tag_names = get_tag_names(from_tags) @@ -167,7 +166,7 @@ def handle(self, *args, **options): source_tag_name=to_tag_name, language_code=lang ) - raise CommandError('You gave %s as --to argument, but TagSynonym: %s -> %s exists, probably you want to provide %s as --to argument' % (to_tag_name, tag_synonym.source_tag_name, tag_synonym.target_tag_name, tag_synonym.target_tag_name)) + raise CommandError(f'You gave {to_tag_name} as --to argument, but TagSynonym: {tag_synonym.source_tag_name} -> {tag_synonym.target_tag_name} exists, probably you want to provide {tag_synonym.target_tag_name} as --to argument') except models.TagSynonym.DoesNotExist: pass diff --git a/askbot/management/commands/send_accept_answer_reminders.py b/askbot/management/commands/send_accept_answer_reminders.py index f6fa7f2c3d..5be861c83a 100644 --- a/askbot/management/commands/send_accept_answer_reminders.py +++ b/askbot/management/commands/send_accept_answer_reminders.py @@ -66,7 +66,6 @@ def handle(self, **options): }) if DEBUG_THIS_COMMAND: - print("User: %s
\nSubject:%s
\nText: %s
\n" % \ - (user.email, email.render_subject(), email.render_body())) + print(f"User: {user.email}
\nSubject:{email.render_subject()}
\nText: {email.render_body()}
\n") else: email.send([user.email],) diff --git a/askbot/management/commands/send_email_alerts.py b/askbot/management/commands/send_email_alerts.py index f307f1a51e..4cbbb2a6c9 100644 --- a/askbot/management/commands/send_email_alerts.py +++ b/askbot/management/commands/send_email_alerts.py @@ -119,14 +119,14 @@ def report_exception(self, user): print(message) admin_email = askbot_settings.ADMIN_EMAIL try: - subject_line = "Error processing daily/weekly notification for User '%s' for Site '%s'" % (user.username, SITE_ID) + subject_line = f"Error processing daily/weekly notification for User '{user.username}' for Site '{SITE_ID}'" send_mail( subject_line=subject_line.encode('utf-8'), body_text=message, recipient_list=[admin_email,] ) except: - message = "ERROR: was unable to report this exception to %s: %s" % (admin_email, traceback.format_exc()) + message = f"ERROR: was unable to report this exception to {admin_email}: {traceback.format_exc()}" print(self.format_debug_msg(user, message)) else: message = "Sent email reporting this exception to %s" % admin_email diff --git a/askbot/management/commands/send_unanswered_question_reminders.py b/askbot/management/commands/send_unanswered_question_reminders.py index f1bc9c0c22..6d41dc5f4f 100644 --- a/askbot/management/commands/send_unanswered_question_reminders.py +++ b/askbot/management/commands/send_unanswered_question_reminders.py @@ -58,8 +58,7 @@ def send_email(user, questions): email = UnansweredQuestionsReminder({'recipient_user': user, 'questions': questions}) if DEBUG_THIS_COMMAND: - print("User: %s
\nSubject:%s
\nText: %s
\n" % \ - (user.email, email.render_subject(), email.render_body())) + print(f"User: {user.email}
\nSubject:{email.render_subject()}
\nText: {email.render_body()}
\n") else: email.send([user.email,]) diff --git a/askbot/management/commands/update_avatar_data.py b/askbot/management/commands/update_avatar_data.py index 926b92c198..6fd354fbcf 100644 --- a/askbot/management/commands/update_avatar_data.py +++ b/askbot/management/commands/update_avatar_data.py @@ -11,8 +11,7 @@ def handle(self, **options): users = User.objects.all() has_avatar = User.objects.exclude(askbot_profile__avatar_type='n').count() total_users = users.count() - print('%s users in total, %s have valid avatar' \ - % (total_users, has_avatar)) + print(f'{total_users} users in total, {has_avatar} have valid avatar') for count, user in enumerate(users): users_left = total_users - count @@ -23,5 +22,4 @@ def handle(self, **options): print('Updated all the users') has_avatar = User.objects.exclude(askbot_profile__avatar_type='n').count() - print('%s users in total, %s have real avatar image' \ - % (total_users, has_avatar)) + print(f'{total_users} users in total, {has_avatar} have real avatar image') diff --git a/askbot/middleware/anon_user.py b/askbot/middleware/anon_user.py index 6e1a5fdba7..e3b275b9e8 100644 --- a/askbot/middleware/anon_user.py +++ b/askbot/middleware/anon_user.py @@ -12,7 +12,7 @@ from askbot.user_messages import create_message, get_and_delete_messages from askbot.conf import settings as askbot_settings -class AnonymousMessageManager(object): +class AnonymousMessageManager: """message manager for the anonymous user""" def __init__(self, request): self.request = request @@ -41,7 +41,7 @@ def connect_messages_to_anon_user(request): request.user.message_set.get_and_delete -class ConnectToSessionMessagesMiddleware(object): +class ConnectToSessionMessagesMiddleware: """Middleware that attaches messages to anonymous users, and makes sure that anonymous user greeting is shown just once. Middleware does not do anything if the anonymous user greeting diff --git a/askbot/middleware/cache.py b/askbot/middleware/cache.py index e09978b7e6..ba05bd01b0 100644 --- a/askbot/middleware/cache.py +++ b/askbot/middleware/cache.py @@ -49,7 +49,7 @@ learn_cache_key, patch_response_headers) -class UpdateCacheMiddleware(object): +class UpdateCacheMiddleware: """ Response-phase cache middleware that updates the cache if the response is cacheable. @@ -127,7 +127,7 @@ def process_response(self, request, response): return response -class FetchFromCacheMiddleware(object): +class FetchFromCacheMiddleware: """ Request-phase cache middleware that fetches a page from the cache. diff --git a/askbot/middleware/cancel.py b/askbot/middleware/cancel.py index 4d4885bd82..d2b87a12c1 100644 --- a/askbot/middleware/cancel.py +++ b/askbot/middleware/cancel.py @@ -3,7 +3,7 @@ from askbot.utils.forms import get_next_url from askbot.utils.http import get_request_params -class CancelActionMiddleware(object): +class CancelActionMiddleware: """Django middleware that redirects to the next url if the request has "cancel" parameter.""" diff --git a/askbot/middleware/forum_mode.py b/askbot/middleware/forum_mode.py index 7b5b6b7d5e..bb93d1ee7f 100644 --- a/askbot/middleware/forum_mode.py +++ b/askbot/middleware/forum_mode.py @@ -30,7 +30,7 @@ def is_view_allowed(func): return view_path in ALLOWED_VIEWS -class ForumModeMiddleware(object): +class ForumModeMiddleware: """protects forum views is the closed forum mode""" def __init__(self, get_response=None): # i think get_reponse is never None. If it's not another middleware it's the view, I think @@ -67,7 +67,7 @@ def process_request(self, request): _('Please log in to use %s') % \ askbot_settings.APP_SHORT_NAME ) - redirect_url = '%s?next=%s' % ( + redirect_url = '{}?next={}'.format( url_utils.get_login_url(), encode_jwt({'next_url': request.get_full_path()}) ) diff --git a/askbot/middleware/locale.py b/askbot/middleware/locale.py index fa17fc6033..3e7c202b62 100644 --- a/askbot/middleware/locale.py +++ b/askbot/middleware/locale.py @@ -4,7 +4,7 @@ from django.utils import translation from askbot.conf import settings -class LocaleMiddleware(object): +class LocaleMiddleware: """ This is a very simple middleware that parses a request and decides what translation object to install in the current diff --git a/askbot/middleware/remote_ip.py b/askbot/middleware/remote_ip.py index e30ffdd30e..c12e62b5a4 100644 --- a/askbot/middleware/remote_ip.py +++ b/askbot/middleware/remote_ip.py @@ -8,7 +8,7 @@ 'askbot.middleware.remote_ip.SetRemoteIPFromXForwardedFor', """ -class SetRemoteIPFromXForwardedFor(object): +class SetRemoteIPFromXForwardedFor: def __init__(self, get_response=None): # i think get_reponse is never None. If it's not another middleware it's the view, I think if get_response is None: get_response = lambda x:x diff --git a/askbot/middleware/view_log.py b/askbot/middleware/view_log.py index 15d3e529fe..a8249d2494 100644 --- a/askbot/middleware/view_log.py +++ b/askbot/middleware/view_log.py @@ -7,7 +7,7 @@ from django.utils import timezone -class ViewLogMiddleware(object): +class ViewLogMiddleware: """ ViewLogMiddleware sends the site_visited signal diff --git a/askbot/models/__init__.py b/askbot/models/__init__.py index ce52c4e1f5..ccf6a69381 100644 --- a/askbot/models/__init__.py +++ b/askbot/models/__init__.py @@ -146,7 +146,7 @@ def get_users_by_text_query(search_query, users_query_set = None): # models.Q(localized_user_profiles__about__search = search_query) # ) -class RelatedObjectSimulator(object): +class RelatedObjectSimulator: '''Objects that simulates the "messages_set" related field somehow django does not creates it automatically in django1.4.1''' @@ -272,7 +272,7 @@ def user_get_absolute_url(self, language_code=None): def user_get_unsubscribe_url(self): url = reverse('user_unsubscribe') email_key = self.get_or_create_email_key() - return '{0}?key={1}&email={2}'.format(url, email_key, self.email) + return f'{url}?key={email_key}&email={self.email}' def user_get_subscriptions_url(self): @@ -2640,14 +2640,14 @@ def user_get_anonymous_name(self): def user_get_anonymized_name(self): """Returns name that can be used for anonymized account""" - anonymized_name = 'anonymous{}'.format(self.pk) + anonymized_name = f'anonymous{self.pk}' attempt = 0 if self.username == anonymized_name: return anonymized_name while User.objects.filter(username=anonymized_name).exists(): - seed_name = 'anonymous{}{}'.format(self.pk, attempt) + seed_name = f'anonymous{self.pk}{attempt}' attempt += 1 return anonymized_name @@ -2918,8 +2918,7 @@ def user_get_languages(self): def get_profile_link(self, text=None): - profile_link = '%s' \ - % (self.get_profile_url(), escape(text or self.username)) + profile_link = f'{escape(text or self.username)}' return mark_safe(profile_link) diff --git a/askbot/models/badges.py b/askbot/models/badges.py index 7a000f3cc6..2b0f34b90d 100644 --- a/askbot/models/badges.py +++ b/askbot/models/badges.py @@ -34,7 +34,7 @@ from askbot.utils.loading import load_module -class Badge(object): +class Badge: """base class for the badges badges must implement method consider_award @@ -133,7 +133,7 @@ def __init__(self): description = _( 'Deleted own post with %(votes)s or more upvotes' ) % {'votes': askbot_settings.DISCIPLINED_BADGE_MIN_UPVOTES} - super(Disciplined, self).__init__( + super().__init__( name=_('Disciplined'), description=description, level=const.BRONZE_BADGE, multiple=True) @@ -152,7 +152,7 @@ def __init__(self): description = _( 'Deleted own post with %(votes)s or more downvotes' ) % {'votes': askbot_settings.PEER_PRESSURE_BADGE_MIN_DOWNVOTES} - super(PeerPressure, self).__init__( + super().__init__( name=_('Peer Pressure'), description=description, level=const.BRONZE_BADGE, multiple=True) @@ -175,7 +175,7 @@ def __init__(self): 'votes': askbot_settings.TEACHER_BADGE_MIN_UPVOTES, 'answer_voted_up': askbot_settings.WORDS_ANSWER_VOTED_UP } - super(Teacher, self).__init__( + super().__init__( name=_('Teacher'), description=description, level=const.BRONZE_BADGE, multiple=False) @@ -196,7 +196,7 @@ class FirstVote(Badge): key = 'first-vote' def __init__(self): - super(FirstVote, self).__init__( + super().__init__( name=self.name, description=self.description, level=const.BRONZE_BADGE, multiple=False) @@ -211,7 +211,7 @@ class Supporter(FirstVote): key = 'supporter' def __new__(cls): - self = super(Supporter, cls).__new__(cls) + self = super().__new__(cls) self.name = _('Supporter') self.description = _('First upvote') return self @@ -222,7 +222,7 @@ class Critic(FirstVote): key = 'critic' def __new__(cls): - self = super(Critic, cls).__new__(cls) + self = super().__new__(cls) self.name = _('Critic') self.description = _('First downvote') return self @@ -234,7 +234,7 @@ class CivicDuty(Badge): def __init__(self): min_votes = askbot_settings.CIVIC_DUTY_BADGE_MIN_VOTES - super(CivicDuty, self).__init__( + super().__init__( name=_('Civic Duty'), description=_('Voted %(num)s times') % {'num': min_votes}, level=const.SILVER_BADGE, multiple=False) @@ -256,7 +256,7 @@ def __init__(self): 'num': askbot_settings.SELF_LEARNER_BADGE_MIN_UPVOTES, 'answered_own_question': askbot_settings.WORDS_ANSWERED_OWN_QUESTION } - super(SelfLearner, self).__init__( + super().__init__( name=_('Self-Learner'), description=description, level=const.BRONZE_BADGE, multiple=True) @@ -285,7 +285,7 @@ class QualityPost(Badge): key = 'quality-post' def __init__(self): - super(QualityPost, self).__init__( + super().__init__( name=self.name, description=self.description, level=self.level, multiple=self.multiple) @@ -301,7 +301,7 @@ class NiceAnswer(QualityPost): key = 'nice-answer' def __new__(cls): - self = super(NiceAnswer, cls).__new__(cls) + self = super().__new__(cls) self.name = askbot_settings.WORDS_NICE_ANSWER self.level = const.BRONZE_BADGE self.multiple = True @@ -318,7 +318,7 @@ class GoodAnswer(QualityPost): key = 'good-answer' def __new__(cls): - self = super(GoodAnswer, cls).__new__(cls) + self = super().__new__(cls) self.name = askbot_settings.WORDS_GOOD_ANSWER self.level = const.SILVER_BADGE self.multiple = True @@ -335,7 +335,7 @@ class GreatAnswer(QualityPost): key = 'great-answer' def __new__(cls): - self = super(GreatAnswer, cls).__new__(cls) + self = super().__new__(cls) self.name = askbot_settings.WORDS_GREAT_ANSWER self.level = const.GOLD_BADGE self.multiple = True @@ -352,7 +352,7 @@ class NiceQuestion(QualityPost): key = 'nice-question' def __new__(cls): - self = super(NiceQuestion, cls).__new__(cls) + self = super().__new__(cls) self.name = askbot_settings.WORDS_NICE_QUESTION self.level = const.BRONZE_BADGE self.multiple = True @@ -369,7 +369,7 @@ class GoodQuestion(QualityPost): key = 'good-question' def __new__(cls): - self = super(GoodQuestion, cls).__new__(cls) + self = super().__new__(cls) self.name = askbot_settings.WORDS_GOOD_QUESTION self.level = const.SILVER_BADGE self.multiple = True @@ -386,7 +386,7 @@ class GreatQuestion(QualityPost): key = 'great-question' def __new__(cls): - self = super(GreatQuestion, cls).__new__(cls) + self = super().__new__(cls) self.name = askbot_settings.WORDS_GREAT_QUESTION self.level = const.GOLD_BADGE self.multiple = True @@ -403,7 +403,7 @@ class Student(QualityPost): key = 'student' def __new__(cls): - self = super(Student, cls).__new__(cls) + self = super().__new__(cls) self.name = _('Student') self.level = const.BRONZE_BADGE self.multiple = False @@ -427,7 +427,7 @@ class FrequentedQuestion(Badge): key = 'frequented-question' def __init__(self): - super(FrequentedQuestion, self).__init__( + super().__init__( name=self.name, description=self.description, level=self.level, multiple=True) @@ -443,7 +443,7 @@ class PopularQuestion(FrequentedQuestion): key = 'popular-question' def __new__(cls): - self = super(PopularQuestion, cls).__new__(cls) + self = super().__new__(cls) self.name = askbot_settings.WORDS_POPULAR_QUESTION self.level = const.BRONZE_BADGE self.min_views = askbot_settings.POPULAR_QUESTION_BADGE_MIN_VIEWS @@ -458,7 +458,7 @@ class NotableQuestion(FrequentedQuestion): key = 'notable-question' def __new__(cls): - self = super(NotableQuestion, cls).__new__(cls) + self = super().__new__(cls) self.name = askbot_settings.WORDS_NOTABLE_QUESTION self.level = const.SILVER_BADGE self.min_views = askbot_settings.NOTABLE_QUESTION_BADGE_MIN_VIEWS @@ -473,7 +473,7 @@ class FamousQuestion(FrequentedQuestion): key = 'famous-question' def __new__(cls): - self = super(FamousQuestion, cls).__new__(cls) + self = super().__new__(cls) self.name = askbot_settings.WORDS_FAMOUS_QUESTION self.level = const.GOLD_BADGE self.multiple = True @@ -496,7 +496,7 @@ def __init__(self): 'asked_a_question': askbot_settings.WORDS_ASKED_A_QUESTION, 'accepted_an_answer': askbot_settings.WORDS_ACCEPTED_AN_ANSWER } - super(Scholar, self).__init__( + super().__init__( name=_('Scholar'), level=const.BRONZE_BADGE, multiple=False, description=description) @@ -518,7 +518,7 @@ class VotedAcceptedAnswer(Badge): key = 'voted-accepted-answer' def __init__(self): - super(VotedAcceptedAnswer, self).__init__( + super().__init__( name=self.name, level=self.level, multiple=self.multiple, description=self.description) @@ -534,7 +534,7 @@ class Enlightened(VotedAcceptedAnswer): key = 'enlightened' def __new__(cls): - self = super(Enlightened, cls).__new__(cls) + self = super().__new__(cls) self.name = _('Enlightened') self.level = const.SILVER_BADGE self.multiple = False @@ -551,7 +551,7 @@ class Guru(VotedAcceptedAnswer): key = 'guru' def __new__(cls): - self = super(Guru, cls).__new__(cls) + self = super().__new__(cls) self.name = _('Guru') self.level = const.GOLD_BADGE self.multiple = True @@ -578,7 +578,7 @@ def __init__(self): 'votes': votes, 'answered_a_question': askbot_settings.WORDS_ANSWERED_A_QUESTION } - super(Necromancer, self).__init__( + super().__init__( name=_('Necromancer'), level=const.SILVER_BADGE, description=description, multiple=True) @@ -599,7 +599,7 @@ class CitizenPatrol(Badge): key = 'citizen-patrol' def __init__(self): - super(CitizenPatrol, self).__init__( + super().__init__( name=_('Citizen Patrol'), level=const.BRONZE_BADGE, multiple=False, description=_('First flagged post')) @@ -613,7 +613,7 @@ class Cleanup(Badge): key = 'cleanup' def __init__(self): - super(Cleanup, self).__init__( + super().__init__( name=_('Cleanup'), level=const.BRONZE_BADGE, multiple=False, description=_('First rollback')) @@ -626,7 +626,7 @@ class Pundit(Badge): key = 'pundit' def __init__(self): - super(Pundit, self).__init__( + super().__init__( name=_('Pundit'), level=const.SILVER_BADGE, multiple=False, description=_('Left 10 comments with score of 10 or more')) @@ -639,7 +639,7 @@ class EditorTypeBadge(Badge): key = 'editor-type-badge' def __init__(self): - super(EditorTypeBadge, self).__init__( + super().__init__( name=self.name, level=self.level, multiple=False, description=self.description ) @@ -659,7 +659,7 @@ class Editor(EditorTypeBadge): key = 'editor' def __new__(cls): - self = super(Editor, cls).__new__(cls) + self = super().__new__(cls) self.name = _('Editor') self.level = const.BRONZE_BADGE self.multiple = False @@ -672,7 +672,7 @@ class AssociateEditor(EditorTypeBadge): key = 'associate-editor' # legacy copycat name from stackoverflow def __new__(cls): - self = super(AssociateEditor, cls).__new__(cls) + self = super().__new__(cls) self.name = _('Associate Editor') self.level = const.SILVER_BADGE self.multiple = False @@ -685,7 +685,7 @@ class Organizer(Badge): key = 'organizer' def __init__(self): - super(Organizer, self).__init__( + super().__init__( name=_('Organizer'), level=const.BRONZE_BADGE, multiple=False, description=_('First retag')) @@ -694,7 +694,7 @@ class Autobiographer(Badge): key = 'autobiographer' def __init__(self): - super(Autobiographer, self).__init__( + super().__init__( name=_('Autobiographer'), level=const.BRONZE_BADGE, multiple=False, description=_('Completed all user profile fields')) @@ -719,7 +719,7 @@ def __init__(self): 'num': self.min_stars, 'asked_a_question': askbot_settings.WORDS_ASKED_A_QUESTION } - super(FavoriteTypeBadge, self).__init__( + super().__init__( name=self.name, level=self.level, multiple=True, description=description) @@ -739,7 +739,7 @@ class StellarQuestion(FavoriteTypeBadge): key = 'stellar-question' def __new__(cls): - self = super(StellarQuestion, cls).__new__(cls) + self = super().__new__(cls) self.name = askbot_settings.WORDS_STELLAR_QUESTION self.level = const.GOLD_BADGE self.min_stars = askbot_settings.STELLAR_QUESTION_BADGE_MIN_STARS @@ -750,7 +750,7 @@ class FavoriteQuestion(FavoriteTypeBadge): key = 'favorite-question' def __new__(cls): - self = super(FavoriteQuestion, cls).__new__(cls) + self = super().__new__(cls) self.name = askbot_settings.WORDS_FAVORITE_QUESTION self.level = const.SILVER_BADGE self.min_stars = askbot_settings.FAVORITE_QUESTION_BADGE_MIN_STARS @@ -764,7 +764,7 @@ class Enthusiast(Badge): key = 'enthusiast' def __init__(self): - super(Enthusiast, self).__init__( + super().__init__( name = _('Enthusiast'), level = const.SILVER_BADGE, multiple = False, @@ -787,7 +787,7 @@ class Commentator(Badge): key = 'commentator' def __init__(self): - super(Commentator, self).__init__( + super().__init__( name=_('Commentator'), level=const.BRONZE_BADGE, multiple=False, description=_( 'Posted %(num_comments)s comments' @@ -806,7 +806,7 @@ class Taxonomist(Badge): key = 'taxonomist' def __init__(self): - super(Taxonomist, self).__init__( + super().__init__( name=_('Taxonomist'), level=const.SILVER_BADGE, multiple=False, description=ngettext( 'Created a tag used %(num)s time', @@ -829,7 +829,7 @@ def __init__(self): description = _('Responded to question within %(max_delay)s hours') % { 'max_delay': askbot_settings.RAPID_RESPONDER_BADGE_MAX_DELAY, } - super(RapidResponder, self).__init__( + super().__init__( name=_('Rapid Responder'), level=const.SILVER_BADGE, description=description, multiple=True) @@ -859,7 +859,7 @@ class Expert(Badge): key = 'expert' def __init__(self): - super(Expert, self).__init__( + super().__init__( name=_('Expert'), level=const.SILVER_BADGE, multiple=False, description=_('Very active in one tag')) diff --git a/askbot/models/fields.py b/askbot/models/fields.py index 0ea1908a84..46dbc0ea28 100644 --- a/askbot/models/fields.py +++ b/askbot/models/fields.py @@ -6,4 +6,4 @@ def __init__(self, *args, **kwargs): kwargs['choices'] = django_settings.LANGUAGES kwargs['default'] = django_settings.LANGUAGE_CODE kwargs['max_length'] = 16 - super(LanguageCodeField, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) diff --git a/askbot/models/post.py b/askbot/models/post.py index 2b36bf6c83..396d8d6f8f 100644 --- a/askbot/models/post.py +++ b/askbot/models/post.py @@ -336,7 +336,7 @@ def precache_comments(self, for_posts, visitor): # return comments -class MockPost(object): +class MockPost: """Used for special purposes, e.g. to fill out the js templates for the posts made via ajax """ @@ -598,7 +598,7 @@ def parse_and_save(self, author=None, **kwargs): #this save must precede saving the mention activity #as well as assigning groups to the post #because generic relation needs primary key of the related object - super(Post, self).save(**kwargs) + super().save(**kwargs) # TODO: move this group stuff out of this function if self.is_comment(): @@ -1108,7 +1108,7 @@ def delete(self, **kwargs): for user in recipients: user.update_response_counts() - super(Post, self).delete(**kwargs) + super().delete(**kwargs) def __str__(self): if self.is_question(): @@ -1117,7 +1117,7 @@ def __str__(self): return self.html def save(self, *args, **kwargs): - super(Post, self).save(*args, **kwargs) + super().save(*args, **kwargs) if self.is_answer() and 'postgres' in askbot.get_database_engine_name(): # hit the database to trigger update of full text search vector self.thread._question_post().save() @@ -1136,7 +1136,7 @@ def get_text_content(self, title=None, body_text=None, tags=None): title = title or self.thread.title tags = tags or self.thread.tagnames body_text = body_text or self.text - return '{}\n\n{}\n\n{}'.format(title, tags, body_text) + return f'{title}\n\n{tags}\n\n{body_text}' return body_text or self.text def get_snippet(self, max_length=None): @@ -2085,7 +2085,7 @@ def get_question_title(self): else: attr = None if attr is not None: - return '%s %s' % (self.thread.title, str(attr)) + return f'{self.thread.title} {str(attr)}' else: return self.thread.title raise NotImplementedError @@ -2175,10 +2175,10 @@ def create(self, *args, **kwargs): pending_revs.update(**kwargs) revision = pending_revs[0] except AssertionError: - revision = super(PostRevisionManager, self).create(*args, **kwargs) + revision = super().create(*args, **kwargs) else: kwargs['revision'] = post.get_latest_revision_number() + 1 - revision = super(PostRevisionManager, self).create(*args, **kwargs) + revision = super().create(*args, **kwargs) # set default summary if revision.summary == '': @@ -2355,8 +2355,7 @@ def should_notify_author_about_publishing(self, was_approved=False): raise ValueError() def __str__(self): - return '%s - revision %s of %s' % (self.post.post_type, self.revision, - self.title) + return f'{self.post.post_type} - revision {self.revision} of {self.title}' def parent(self): return self.post @@ -2370,7 +2369,7 @@ def save(self, **kwargs): if not self.ip_addr: self.ip_addr = '0.0.0.0' self.full_clean() - super(PostRevision, self).save(**kwargs) + super().save(**kwargs) def get_absolute_url(self): diff --git a/askbot/models/question.py b/askbot/models/question.py index 084e223911..f20129a29d 100644 --- a/askbot/models/question.py +++ b/askbot/models/question.py @@ -75,7 +75,7 @@ def default_title_renderer(thread): else: attr = None if attr is not None: - return '%s %s' % (thread.title, str(attr)) + return f'{thread.title} {str(attr)}' else: return thread.title @@ -174,7 +174,7 @@ def create_new(self, title, author, added_at, wiki, text, tagnames=None, language = language or get_language() tagnames = clean_tagnames(tagnames) - thread = super(ThreadManager, self).create( + thread = super().create( title=title, tagnames=tagnames, last_activity_at=added_at, last_activity_by=author, language_code=language) @@ -1784,7 +1784,7 @@ class Meta: verbose_name_plural = _("favorite questions") def __str__(self): - return '[%s] favorited at %s' % (self.user, self.added_at) + return f'[{self.user}] favorited at {self.added_at}' class DraftQuestion(DraftContent): diff --git a/askbot/models/recent_contributors.py b/askbot/models/recent_contributors.py index 36ab31555f..61ec46b375 100644 --- a/askbot/models/recent_contributors.py +++ b/askbot/models/recent_contributors.py @@ -8,7 +8,7 @@ from askbot.utils.translation import get_language -class AvatarsBlockData(object): +class AvatarsBlockData: """Class managing data for the avatars block, displayed on the main page""" CACHE_KEY = 'askbot-avatar-block-data' diff --git a/askbot/models/reply_by_email.py b/askbot/models/reply_by_email.py index faa2c2e872..7eb7f6d928 100644 --- a/askbot/models/reply_by_email.py +++ b/askbot/models/reply_by_email.py @@ -87,11 +87,7 @@ def was_used(self): def as_email_address(self, prefix='reply-'): """returns email address, prefix is added in front of the code""" - return '%s%s@%s' % ( - prefix, - self.address, - askbot_settings.REPLY_BY_EMAIL_HOSTNAME - ) + return f'{prefix}{self.address}@{askbot_settings.REPLY_BY_EMAIL_HOSTNAME}' def edit_post(self, body_text, title=None, edit_response=False): """edits the created post upon repeated response diff --git a/askbot/models/repute.py b/askbot/models/repute.py index adef027400..16e51c1fe6 100644 --- a/askbot/models/repute.py +++ b/askbot/models/repute.py @@ -59,7 +59,7 @@ class Meta: verbose_name_plural = _("votes") def __str__(self): - return '[%s] voted at %s: %s' % (self.user, self.voted_at, self.vote) + return f'[{self.user}] voted at {self.voted_at}: {self.vote}' def __int__(self): """1 if upvote -1 if downvote""" @@ -142,10 +142,10 @@ class Meta: verbose_name_plural = _("badge data") def __str__(self): - return '%s: %s' % (self.get_type_display(), self.slug) + return f'{self.get_type_display()}: {self.slug}' def get_absolute_url(self): - return '%s%s/' % (reverse('badge', args=[self.id]), self.slug) + return '{}{}/'.format(reverse('badge', args=[self.id]), self.slug) class Award(models.Model): @@ -159,7 +159,7 @@ class Award(models.Model): notified = models.BooleanField(default=False) def __str__(self): - return '[%s] is awarded a badge [%s] at %s' % (self.user.username, + return '[{}] is awarded a badge [{}] at {}'.format(self.user.username, self.badge.get_name(), self.awarded_at) def __lt__(self, other): @@ -222,8 +222,7 @@ class Repute(models.Model): objects = ReputeManager() def __str__(self): - return '[%s]\' reputation changed at %s' % (self.user.username, - self.reputed_at) + return f'[{self.user.username}]\' reputation changed at {self.reputed_at}' class Meta: app_label = 'askbot' @@ -236,7 +235,7 @@ def save(self, *args, **kwargs): self.language_code = self.question.language_code else: self.language_code = get_language() - super(Repute, self).save(*args, **kwargs) + super().save(*args, **kwargs) def get_explanation_snippet(self): """returns HTML snippet with a link to related question @@ -258,7 +257,7 @@ def get_explanation_snippet(self): 'question_title': self.question.thread.title } - return '%(question_title)s' % { - 'url': self.question.get_absolute_url(), - 'question_title': escape(self.question.thread.title), - } + return '{question_title}'.format( + url=self.question.get_absolute_url(), + question_title=escape(self.question.thread.title), + ) diff --git a/askbot/models/tag.py b/askbot/models/tag.py index 62814e6763..86b0b933c8 100644 --- a/askbot/models/tag.py +++ b/askbot/models/tag.py @@ -193,7 +193,7 @@ def create(self, name=None, created_by=None, auto_approve=False, **kwargs): kwargs['name'] = name kwargs['status'] = status - return super(TagManager, self).create(**kwargs) + return super().create(**kwargs) def create_in_bulk(self, tag_names=None, user=None, language_code=None, auto_approve=False): """creates tags by names. If user can create tags, @@ -324,4 +324,4 @@ class Meta: app_label = 'askbot' def __str__(self): - return '%s -> %s' % (self.source_tag_name, self.target_tag_name) + return f'{self.source_tag_name} -> {self.target_tag_name}' diff --git a/askbot/models/user.py b/askbot/models/user.py index 2ca057c6ae..10bd2b2593 100644 --- a/askbot/models/user.py +++ b/askbot/models/user.py @@ -22,7 +22,7 @@ PERSONAL_GROUP_NAME_PREFIX = '_personal_' -class InvitedModerator(object): +class InvitedModerator: """Mock user class to represent invited moderators""" def __init__(self, username, email): self.username = username @@ -93,7 +93,7 @@ def remove_email_from_invited_moderators(email): askbot_settings.update('INVITED_MODERATORS', value) -class MockUser(object): +class MockUser: def __init__(self): self.username = '' @@ -314,7 +314,7 @@ class Activity(models.Model): objects = ActivityManager() def __str__(self): - return '[%s] was active at %s' % (self.user.username, self.active_at) + return f'[{self.user.username}] was active at {self.active_at}' class Meta: app_label = 'askbot' @@ -447,7 +447,7 @@ def __str__(self): reported_at = "'not yet'" else: reported_at = '%s' % self.reported_at.strftime('%d/%m/%y %H:%M') - return 'Email feed for %s type=%s, frequency=%s, reported_at=%s' % ( + return 'Email feed for {} type={}, frequency={}, reported_at={}'.format( self.subscriber, self.feed_type, self.frequency, @@ -462,7 +462,7 @@ def save(self, *args, **kwargs): .exclude(pk=self.id) if similar.exists(): raise IntegrityError('email feed setting already exists') - super(EmailFeedSetting, self).save(*args, **kwargs) + super().save(*args, **kwargs) def get_previous_report_cutoff_time(self): now = timezone.now() @@ -564,7 +564,7 @@ def create(self, **kwargs): kwargs['group_ptr'] = group_ptr except AuthGroup.DoesNotExist: pass - return super(GroupManager, self).create(**kwargs) + return super().create(**kwargs) def get_or_create(self, name=None, user=None, openness=None): """creates a group tag or finds one, if exists""" @@ -705,7 +705,7 @@ def clean(self): def save(self, *args, **kwargs): self.clean() - super(Group, self).save(*args, **kwargs) + super().save(*args, **kwargs) class BulkTagSubscriptionManager(BaseQuerySetManager): @@ -724,7 +724,7 @@ def create( user_list = user_list or [] group_list = group_list or [] - new_object = super(BulkTagSubscriptionManager, self).create(**kwargs) + new_object = super().create(**kwargs) tag_name_list = [] if tag_names: diff --git a/askbot/models/user_profile.py b/askbot/models/user_profile.py index 9dd2be85c3..be0e907130 100644 --- a/askbot/models/user_profile.py +++ b/askbot/models/user_profile.py @@ -13,7 +13,7 @@ # that the parameter is called "user" ... def get_profile_cache_key(user): if user.pk: - return 'askbot-profile-{}'.format(user.pk) + return f'askbot-profile-{user.pk}' raise ValueError('auth.models.User is not saved, cant make cache key') @@ -230,7 +230,7 @@ def update_cache(self): def save(self, *args, **kwargs): self.update_cache() - super(UserProfile, self).save(*args, **kwargs) + super().save(*args, **kwargs) class LocalizedUserProfile(models.Model): @@ -265,7 +265,7 @@ def update_cache(self): def save(self, *args, **kwargs): self.update_cache() - super(LocalizedUserProfile, self).save(*args, **kwargs) + super().save(*args, **kwargs) def update_user_profile(instance, **kwargs): diff --git a/askbot/search/haystack/base.py b/askbot/search/haystack/base.py index 49c49182f8..a564e1cb6c 100644 --- a/askbot/search/haystack/base.py +++ b/askbot/search/haystack/base.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- import askbot from django.conf import settings from django.utils.translation import override @@ -19,7 +18,7 @@ def _get_backend(self, using): We set the backend alias to be able to determine language in multilanguage setup. """ self._backend_alias = using - return super(BaseIndex, self)._get_backend(using) + return super()._get_backend(using) def get_language(self, obj): return None @@ -57,6 +56,6 @@ def prepare(self, obj): current_language = self.get_current_language(using=self._backend_alias, obj=obj) with override(current_language): - self.prepared_data = super(BaseIndex, self).prepare(obj) + self.prepared_data = super().prepare(obj) self.prepared_data['text'] = ' '.join(self.prepared_data['text'].split()) return self.prepared_data diff --git a/askbot/search/haystack/helpers.py b/askbot/search/haystack/helpers.py index 4f4d4141a1..3ca8fad3a7 100644 --- a/askbot/search/haystack/helpers.py +++ b/askbot/search/haystack/helpers.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from haystack import connections from haystack.exceptions import NotHandled from haystack.query import SearchQuerySet diff --git a/askbot/search/haystack/indexes.py b/askbot/search/haystack/indexes.py index f4d2571756..c9ad704fa9 100644 --- a/askbot/search/haystack/indexes.py +++ b/askbot/search/haystack/indexes.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.conf import settings from django.apps import apps diff --git a/askbot/search/haystack/signals.py b/askbot/search/haystack/signals.py index e96d6e5f06..86426f3087 100644 --- a/askbot/search/haystack/signals.py +++ b/askbot/search/haystack/signals.py @@ -22,10 +22,10 @@ def handle_delete(self, sender, instance, **kwargs): # but still need to update/remove thread when post is removed. instance, sender = (instance.thread, Thread) - super(AskbotRealtimeSignalProcessor, self).handle_delete(sender, instance, **kwargs) + super().handle_delete(sender, instance, **kwargs) def setup(self): - super(AskbotRealtimeSignalProcessor, self).setup() + super().setup() try: askbot_signals.after_post_removed.connect(self.handle_delete) @@ -33,7 +33,7 @@ def setup(self): pass def teardown(self): - super(AskbotRealtimeSignalProcessor, self).setup() + super().setup() #askbot signals try: askbot_signals.after_post_removed.disconnect(self.handle_delete) diff --git a/askbot/search/haystack/utils.py b/askbot/search/haystack/utils.py index 3223042dad..0b3091ecab 100644 --- a/askbot/search/haystack/utils.py +++ b/askbot/search/haystack/utils.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.core.exceptions import ImproperlyConfigured from django.conf import settings try: @@ -24,7 +23,7 @@ def get_base_index(): required_fields = ['text'] if not all(field in BaseClass.fields for field in required_fields): - raise ImproperlyConfigured('ASKBOT_HAYSTACK_INDEX_BASE_CLASS: %s must contain at least these fields: %s' % (index_string, required_fields)) + raise ImproperlyConfigured(f'ASKBOT_HAYSTACK_INDEX_BASE_CLASS: {index_string} must contain at least these fields: {required_fields}') return BaseClass @@ -57,7 +56,7 @@ def alias_from_language(language): connection_prefix = get_connection_prefix() if connection_prefix: - connection = '{0}_{1}'.format(connection_prefix, language) + connection = f'{connection_prefix}_{language}' else: connection = language return connection diff --git a/askbot/search/state_manager.py b/askbot/search/state_manager.py index 1c0f37bab5..53f618a0d7 100644 --- a/askbot/search/state_manager.py +++ b/askbot/search/state_manager.py @@ -82,7 +82,7 @@ def parse_query(query): 'query_users': query_users } -class SearchState(object): +class SearchState: @classmethod def get_empty(cls): @@ -275,7 +275,7 @@ def change_page(self, new_page): return ss -class DummySearchState(object): # Used for caching question/thread summaries +class DummySearchState: # Used for caching question/thread summaries def add_tag(self, tag): self.tag = tag diff --git a/askbot/setup_templates/celery_app.py b/askbot/setup_templates/celery_app.py index 87645a0720..9003a158d2 100644 --- a/askbot/setup_templates/celery_app.py +++ b/askbot/setup_templates/celery_app.py @@ -18,4 +18,4 @@ @app.task(bind=True) def debug_task(self): - print('Request: {0!r}'.format(self.request)) + print(f'Request: {self.request!r}') diff --git a/askbot/skins/askbot_environments.py b/askbot/skins/askbot_environments.py index 7b2c96dfa9..b54a7c5c79 100644 --- a/askbot/skins/askbot_environments.py +++ b/askbot/skins/askbot_environments.py @@ -21,7 +21,7 @@ class MultilingualEnvironment(Environment): def __init__(self, *args, **kwargs): lang_code = kwargs.pop('language_code', None) # atm I don't see this ever becoming None - super(MultilingualEnvironment, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) # The following caused problems before. Reverting to call set_language() explicitly # if lang_code is not None: # self.set_language(lang_code) @@ -57,7 +57,7 @@ def __init__(self, *args, **kwargs): key = self.build_sibling_key(this_sibling_key) self.__class__.siblings[key] = self - super(SkinEnvironment, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) @classmethod def build_sibling_key(cls, parts): diff --git a/askbot/skins/template_backends.py b/askbot/skins/template_backends.py index 0172685ed6..6f602bb45a 100644 --- a/askbot/skins/template_backends.py +++ b/askbot/skins/template_backends.py @@ -6,7 +6,7 @@ class Template(OriginalJinja2Template): # backend parameter was added with Django 1.11 def __init__(self, template, backend=None): - super(Template,self).__init__(template, backend) + super().__init__(template, backend) def render(self, context=None, request=None): # dict from_context is from django_jinja and I am not sure if we still @@ -14,6 +14,6 @@ def render(self, context=None, request=None): if isinstance(context,BaseContext): context = dict_from_context(context) - return super(Template, self).render(context, request) + return super().render(context, request) django.template.backends.jinja2.Template = Template diff --git a/askbot/skins/utils.py b/askbot/skins/utils.py index dee934cab8..4bb3c1d7aa 100644 --- a/askbot/skins/utils.py +++ b/askbot/skins/utils.py @@ -156,8 +156,7 @@ def get_media_url(url, ignore_missing = False): use_skin = resolve_skin_for_media(media=url, preferred_skin = use_skin) except MediaNotFound: if ignore_missing == False: - log_message = 'missing media resource %s in skin %s' \ - % (url, use_skin) + log_message = f'missing media resource {url} in skin {use_skin}' logging.critical(log_message) return None diff --git a/askbot/spam_checker/akismet_spam_checker.py b/askbot/spam_checker/akismet_spam_checker.py index 3963353c9d..5812ed97df 100644 --- a/askbot/spam_checker/akismet_spam_checker.py +++ b/askbot/spam_checker/akismet_spam_checker.py @@ -68,7 +68,7 @@ def call_akismet(text, elif command == 'submit_ham': return api.submit_ham(ip_addr, user_agent, **data) else: - raise RuntimeError('unknown akismet method: "{}"'.format(command)) + raise RuntimeError(f'unknown akismet method: "{command}"') except APIKeyError: logging.critical('Akismet Key is missing') except AkismetError: diff --git a/askbot/startup_procedures.py b/askbot/startup_procedures.py index 17900ed459..da6a511ffa 100644 --- a/askbot/startup_procedures.py +++ b/askbot/startup_procedures.py @@ -46,7 +46,7 @@ def __init__(self, error_message): if sys.__stdin__.isatty(): #print footer only when askbot is run from the shell msg += FOOTER - super(AskbotConfigError, self).__init__(msg) + super().__init__(msg) def domain_is_bad(): @@ -222,7 +222,7 @@ def try_import(module_name, pypi_package_name, show_requirements_message=True, def unparse_requirement(req): line = req.name if req.specs: - specs = ['%s%s' % spec for spec in req.specs] + specs = ['{}{}'.format(*spec) for spec in req.specs] line += ','.join(specs) if req.extras: line += ' [%s]' % ','.join(req.extras) @@ -402,7 +402,7 @@ def test_media_url(): ) -class SettingsTester(object): +class SettingsTester: """class to test contents of the settings.py file""" def __init__(self, requirements=None): diff --git a/askbot/templatetags/extra_filters_jinja.py b/askbot/templatetags/extra_filters_jinja.py index 56121f0e25..638c069c17 100644 --- a/askbot/templatetags/extra_filters_jinja.py +++ b/askbot/templatetags/extra_filters_jinja.py @@ -435,8 +435,8 @@ def convert_text(text): '=': '\\u003D', '-': '\\u002D', ';': '\\u003B', - u'\u2028': '\\u2028', - u'\u2029': '\\u2029' + '\u2028': '\\u2028', + '\u2029': '\\u2029' } # Escape every ASCII character with a value less than 32. _js_escapes.update(('%c' % z, '\\u%04X' % z) for z in range(32)) diff --git a/askbot/tests/skip_test_reply_by_email.py b/askbot/tests/skip_test_reply_by_email.py index 2bc6288bd5..0fc0cb8964 100644 --- a/askbot/tests/skip_test_reply_by_email.py +++ b/askbot/tests/skip_test_reply_by_email.py @@ -17,7 +17,7 @@ TEST_CONTENT = 'Test content' TEST_LONG_CONTENT = 'Test content' * 10 -class MockPart(object): +class MockPart: def __init__(self, body, content_type='text/plain'): self.body = body self.content_encoding = {'Content-Type':(content_type,)} diff --git a/askbot/tests/test_akismet.py b/askbot/tests/test_akismet.py index d9ef220928..de2ea53101 100644 --- a/askbot/tests/test_akismet.py +++ b/askbot/tests/test_akismet.py @@ -7,8 +7,8 @@ AKISMET_CLASSIFIER = 'askbot.spam_checker.akismet_spam_checker.is_spam' TEXT = 'hello foobar' API_KEY = 'foobar' -CHECK_SPAM_URL = 'https://{}.rest.akismet.com/1.1/comment-check'.format(API_KEY) -SUBMIT_SPAM_URL = 'https://{}.rest.akismet.com/1.1/submit-spam'.format(API_KEY) +CHECK_SPAM_URL = f'https://{API_KEY}.rest.akismet.com/1.1/comment-check' +SUBMIT_SPAM_URL = f'https://{API_KEY}.rest.akismet.com/1.1/submit-spam' VERIFY_KEY_URL = 'https://rest.akismet.com/1.1/verify-key' USER_AGENT = 'user_agent_string' USER_IP = '0.0.0.0' @@ -16,7 +16,7 @@ COMMENT_AUTHOR_EMAIL = 'bob@example.com' -class User(object): +class User: def __init__(self, anon=False, username=COMMENT_AUTHOR, email=COMMENT_AUTHOR_EMAIL): self.anon = anon if anon: @@ -34,7 +34,7 @@ def is_anonymous(self): return self.anon -class AuthRequest(object): +class AuthRequest: environ = {'HTTP_USER_AGENT': USER_AGENT} META = {'REMOTE_ADDR': USER_IP} def __init__(self, anon=False, username=COMMENT_AUTHOR, email=COMMENT_AUTHOR_EMAIL): diff --git a/askbot/tests/test_email_alerts.py b/askbot/tests/test_email_alerts.py index 8effc0839e..5d98e76ff8 100644 --- a/askbot/tests/test_email_alerts.py +++ b/askbot/tests/test_email_alerts.py @@ -299,8 +299,7 @@ def check_results(self, test_key = None): self.assertEqual(len(outbox), expected['message_count'], error_message) if expected['message_count'] > 0: if len(outbox) > 0: - error_message = 'expected recipient %s found %s' % \ - (self.target_user.email, outbox[0].recipients()[0]) + error_message = f'expected recipient {self.target_user.email} found {outbox[0].recipients()[0]}' #verify that target user receives the email self.assertEqual( outbox[0].recipients()[0], @@ -901,7 +900,7 @@ class AcceptAnswerReminderTests(EmailReminderTestCase): command_name = 'send_accept_answer_reminders' def do_post(self, timestamp): - super(AcceptAnswerReminderTests, self).do_post(timestamp) + super().do_post(timestamp) self.answer = self.post_answer( question = self.question, user = self.u2, diff --git a/askbot/tests/test_email_parsing.py b/askbot/tests/test_email_parsing.py index 56340e67c7..5a7724c6ef 100644 --- a/askbot/tests/test_email_parsing.py +++ b/askbot/tests/test_email_parsing.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.conf import settings as django_settings from django.template import Context from django.template.loader import get_template diff --git a/askbot/tests/test_management_commands.py b/askbot/tests/test_management_commands.py index 855c3ba32c..b05e8b641a 100644 --- a/askbot/tests/test_management_commands.py +++ b/askbot/tests/test_management_commands.py @@ -119,7 +119,7 @@ def test_command(self): # put three upfiles in place paths = list() for idx in range(1, 4): - path = self.put_upfile('file{}.txt'.format(idx)) + path = self.put_upfile(f'file{idx}.txt') paths.append(path) # post question with an image @@ -223,7 +223,7 @@ def test_askbot_add_user(self): subs = models.EmailFeedSetting.objects.filter( subscriber = user, ) - self.assertEquals(subs.count(), 6) + self.assertEqual(subs.count(), 6) #try to log in user = auth.authenticate(username=username, password=password) self.assertTrue(user is not None) diff --git a/askbot/tests/test_markup.py b/askbot/tests/test_markup.py index 6d38549727..1ef523a3a0 100644 --- a/askbot/tests/test_markup.py +++ b/askbot/tests/test_markup.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- from django.conf import settings as django_settings from django.test import TestCase from askbot.utils.markup import markdown_input_converter diff --git a/askbot/tests/test_page_load.py b/askbot/tests/test_page_load.py index 2f51ac29ec..b0ae433fd3 100644 --- a/askbot/tests/test_page_load.py +++ b/askbot/tests/test_page_load.py @@ -47,11 +47,11 @@ def setUpClass(cls): everyone.save() activate_language(settings.LANGUAGE_CODE) management.call_command('askbot_add_test_content', verbosity=0, interactive=False) - super(PageLoadTestCase, cls).setUpClass() + super().setUpClass() @classmethod def tearDownClass(cls): - super(PageLoadTestCase, cls).tearDownClass() + super().tearDownClass() management.call_command('flush', verbosity=0, interactive=False) def _fixture_setup(self): @@ -91,7 +91,7 @@ def try_url( else: url_info = 'getting url %s' % url if data: - url_info += '?' + '&'.join(['%s=%s' % (k, v) for k, v in data.items()]) + url_info += '?' + '&'.join([f'{k}={v}' for k, v in data.items()]) # print(url_info) # if redirect expected, but we wont' follow diff --git a/askbot/tests/test_permission_assertions.py b/askbot/tests/test_permission_assertions.py index cbb6fc9834..494612d351 100644 --- a/askbot/tests/test_permission_assertions.py +++ b/askbot/tests/test_permission_assertions.py @@ -56,7 +56,7 @@ def post_answer(self, question = None, author = None): class SeeOffensiveFlagsPermissionAssertionTests(utils.AskbotTestCase): def setUp(self): - super(SeeOffensiveFlagsPermissionAssertionTests, self).setUp() + super().setUp() self.create_user() self.create_user(username = 'other_user') self.min_rep = askbot_settings.MIN_REP_TO_VIEW_OFFENSIVE_FLAGS @@ -173,10 +173,7 @@ def setUp(self): def post_answer(self, user = None): if user is None: user = self.user - self.answer = super( - DeleteAnswerPermissionAssertionTests, - self - ).post_answer( + self.answer = super().post_answer( question = self.question, user = user ) @@ -313,7 +310,7 @@ def test_moderator_can_delete_question_with_upvoted_answer_by_other(self): class CloseQuestionPermissionAssertionTests(utils.AskbotTestCase): def setUp(self): - super(CloseQuestionPermissionAssertionTests, self).setUp() + super().setUp() self.create_user() self.create_user(username = 'other_user') self.question = self.post_question() @@ -609,10 +606,7 @@ class EditAnswerPermissionAssertionTests( EditQuestionPermissionAssertionTests ): def setUp(self): - super( - EditAnswerPermissionAssertionTests, - self, - ).setUp() + super().setUp() self.post = self.post_answer(question = self.post) def assert_user_can( @@ -649,10 +643,7 @@ class RetagQuestionPermissionAssertionTests( ): def setUp(self): - super( - RetagQuestionPermissionAssertionTests, - self, - ).setUp() + super().setUp() self.min_rep = askbot_settings.MIN_REP_TO_RETAG_OTHERS_QUESTIONS def assert_user_can( diff --git a/askbot/tests/test_user_views.py b/askbot/tests/test_user_views.py index c5eacea041..51ed29da21 100644 --- a/askbot/tests/test_user_views.py +++ b/askbot/tests/test_user_views.py @@ -4,7 +4,7 @@ from django.contrib.auth.models import AnonymousUser from django.urls import reverse from django.http import HttpResponseRedirect -from mock import Mock +from unittest.mock import Mock import urllib.request, urllib.parse, urllib.error import urllib.parse diff --git a/askbot/tests/utils.py b/askbot/tests/utils.py index a2b8945ed3..1572e070a0 100644 --- a/askbot/tests/utils.py +++ b/askbot/tests/utils.py @@ -109,7 +109,7 @@ class AskbotTestCase(TestCase): """ def _fixture_setup(self): - super(AskbotTestCase, self)._fixture_setup() + super()._fixture_setup() for app_config in apps.get_app_configs(): create_contenttypes(app_config) create_permissions(app_config) @@ -120,7 +120,7 @@ def _fixture_teardown(self): post_migrate.disconnect(create_contenttypes) post_migrate.disconnect(create_permissions, dispatch_uid="django.contrib.auth.management.create_permissions") - super(AskbotTestCase, self)._fixture_teardown() + super()._fixture_teardown() post_migrate.connect(create_contenttypes) post_migrate.connect(create_permissions, dispatch_uid="django.contrib.auth.management.create_permissions") @@ -130,7 +130,7 @@ def _fixture_teardown(self): @classmethod def setUpClass(cls): cache.clear() - super(AskbotTestCase, cls).setUpClass() + super().setUpClass() def create_user( self, @@ -170,7 +170,7 @@ def assertRaisesRegexp(self, *args, **kwargs): """a shim for python < 2.7""" try: #run assertRaisesRegex, if available - super(AskbotTestCase, self).assertRaisesRegex(*args, **kwargs) + super().assertRaisesRegex(*args, **kwargs) except AttributeError: #in this case lose testing for the error text #second argument is the regex that is supposed diff --git a/askbot/urls.py b/askbot/urls.py index de33b2fb70..cb9d48bd3c 100644 --- a/askbot/urls.py +++ b/askbot/urls.py @@ -40,13 +40,13 @@ re_path( # Note that all parameters, even if optional, are provided to the view. Non-present ones have None value. (r'^%s' % MAIN_PAGE_BASE_URL.strip('/') + - r'(%s)?' % r'/scope:(?P\w+)' + - r'(%s)?' % r'/sort:(?P[\w\-]+)' + - r'(%s)?' % r'/tags:(?P[\w+.#,-]+)' + # Should match: const.TAG_CHARS + ','; TODO: Is `#` char decoded by the time URLs are processed ?? - r'(%s)?' % r'/author:(?P\d+)' + - r'(%s)?' % r'/page:(?P\d+)' + - r'(%s)?' % r'/page-size:(?P\d+)' + - r'(%s)?' % r'/query:(?P.+)' + # INFO: query is last, b/c it can contain slash!!! + r'({})?'.format(r'/scope:(?P\w+)') + + r'({})?'.format(r'/sort:(?P[\w\-]+)') + + r'({})?'.format(r'/tags:(?P[\w+.#,-]+)') + # Should match: const.TAG_CHARS + ','; TODO: Is `#` char decoded by the time URLs are processed ?? + r'({})?'.format(r'/author:(?P\d+)') + + r'({})?'.format(r'/page:(?P\d+)') + + r'({})?'.format(r'/page-size:(?P\d+)') + + r'({})?'.format(r'/query:(?P.+)') + # INFO: query is last, b/c it can contain slash!!! r'/$'), views.readers.questions, name='questions' @@ -72,7 +72,7 @@ name='users' ), re_path( - r'^%s%s(?P\d+)/(?P.*)/$' % ( + r'^{}{}(?P\d+)/(?P.*)/$'.format( pgettext('urls', 'users/'), pgettext('urls', 'by-group/') ), @@ -82,17 +82,17 @@ ), # TODO: rename as user_edit, b/c that's how template is named re_path( - r'^%s(?P\d+)/%s$' % (pgettext('urls', 'users/'), pgettext('urls', 'edit/')), + r'^{}(?P\d+)/{}$'.format(pgettext('urls', 'users/'), pgettext('urls', 'edit/')), views.users.edit_user, name='edit_user' ), service_url( - r'^%s(?P\d+)/%s(?P.+)/$' % (pgettext('urls', 'users/'), pgettext('urls', 'download-data/')), + r'^{}(?P\d+)/{}(?P.+)/$'.format(pgettext('urls', 'users/'), pgettext('urls', 'download-data/')), views.users.download_user_data, name='download_user_data' ), service_url(#ajax get only - r'^%s(?P\d+)/%s$' % (pgettext('urls', 'users/'), pgettext('urls', 'get-todays-backup-file-name/')), + r'^{}(?P\d+)/{}$'.format(pgettext('urls', 'users/'), pgettext('urls', 'get-todays-backup-file-name/')), views.users.get_todays_backup_file_name, name='get_todays_backup_file_name' ), @@ -112,7 +112,7 @@ name='set_user_description', ), re_path( - r'^%s(?P\d+)/(?P.+)/%s$' % ( + r'^{}(?P\d+)/(?P.+)/{}$'.format( pgettext('urls', 'users/'), pgettext('urls', 'subscriptions/'), ), @@ -121,7 +121,7 @@ name='user_subscriptions' ), re_path( - r'^%s%s$' % ( + r'^{}{}$'.format( pgettext('urls', 'users/'), pgettext('urls', 'unsubscribe/'), ), @@ -129,7 +129,7 @@ name='user_unsubscribe' ), re_path( - r'^%s(?P\d+)/(?P.+)/%s$' % ( + r'^{}(?P\d+)/(?P.+)/{}$'.format( pgettext('urls', 'users/'), pgettext('urls', 'select_languages/'), ), @@ -198,12 +198,12 @@ ), re_path(r'^%s$' % pgettext('urls', 'help/'), views.meta.help_page, name='help'), service_url( - r'^%s(?P\d+)/%s$' % (pgettext('urls', 'answers/'), pgettext('urls', 'edit/')), + r'^{}(?P\d+)/{}$'.format(pgettext('urls', 'answers/'), pgettext('urls', 'edit/')), views.writers.edit_answer, name='edit_answer' ), re_path( - r'^%s(?P\d+)/%s$' % (pgettext('urls', 'answers/'), pgettext('urls', 'revisions/')), + r'^{}(?P\d+)/{}$'.format(pgettext('urls', 'answers/'), pgettext('urls', 'revisions/')), views.readers.revisions, kwargs={'post_type': 'answer'}, name='answer_revisions' @@ -300,27 +300,27 @@ name='get_post_html' ), re_path( - r'^%s%s$' % (MAIN_PAGE_BASE_URL, pgettext('urls', 'ask/')), + r'^{}{}$'.format(MAIN_PAGE_BASE_URL, pgettext('urls', 'ask/')), views.writers.ask, name='ask' ), service_url( # this url is both regular and ajax - r'^%s(?P\d+)/%s$' % (MAIN_PAGE_BASE_URL, pgettext('urls', 'retag/')), + r'^{}(?P\d+)/{}$'.format(MAIN_PAGE_BASE_URL, pgettext('urls', 'retag/')), views.writers.retag_question, name='retag_question' ), re_path( - r'^%s%s(?P\d+)$' % (MAIN_PAGE_BASE_URL, pgettext('urls', 'close/')), + r'^{}{}(?P\d+)$'.format(MAIN_PAGE_BASE_URL, pgettext('urls', 'close/')), views.commands.close, name='close' ), re_path( - r'^%s%s(?P\d+)$' % (MAIN_PAGE_BASE_URL, pgettext('urls', 'reopen/')), + r'^{}{}(?P\d+)$'.format(MAIN_PAGE_BASE_URL, pgettext('urls', 'reopen/')), views.commands.reopen, name='reopen' ), service_url( - r'^%s(?P\d+)/%s$' % (MAIN_PAGE_BASE_URL, pgettext('urls', 'answer/')), + r'^{}(?P\d+)/{}$'.format(MAIN_PAGE_BASE_URL, pgettext('urls', 'answer/')), views.writers.answer, name='answer' ), @@ -335,7 +335,7 @@ name='vote' ), re_path( - r'^%s(?P\d+)/%s$' % (MAIN_PAGE_BASE_URL, pgettext('urls', 'revisions/')), + r'^{}(?P\d+)/{}$'.format(MAIN_PAGE_BASE_URL, pgettext('urls', 'revisions/')), views.readers.revisions, kwargs={'post_type': 'question'}, name='question_revisions' @@ -393,12 +393,12 @@ name='publish_post' ), service_url( - r'^%s%s$' % (pgettext('urls', 'tags/'), pgettext('urls', 'subscriptions/')), + r'^{}{}$'.format(pgettext('urls', 'tags/'), pgettext('urls', 'subscriptions/')), views.commands.list_bulk_tag_subscription, name='list_bulk_tag_subscription' ), service_url( # post only - r'^%s%s%s$' % ( + r'^{}{}{}$'.format( pgettext('urls', 'tags/'), pgettext('urls', 'subscriptions/'), pgettext('urls', 'delete/') @@ -407,7 +407,7 @@ name='delete_bulk_tag_subscription' ), service_url( - r'^%s%s%s$' % ( + r'^{}{}{}$'.format( pgettext('urls', 'tags/'), pgettext('urls', 'subscriptions/'), pgettext('urls', 'create/') @@ -416,7 +416,7 @@ name='create_bulk_tag_subscription' ), service_url( - r'^%s%s%s(?P\d+)/$' % ( + r'^{}{}{}(?P\d+)/$'.format( pgettext('urls', 'tags/'), pgettext('urls', 'subscriptions/'), pgettext('urls', 'edit/') @@ -430,25 +430,25 @@ name='list_suggested_tags' ), service_url( # ajax only - r'^%s$' % 'moderate-suggested-tag', + r'^{}$'.format('moderate-suggested-tag'), views.commands.moderate_suggested_tag, name='moderate_suggested_tag' ), # TODO: collapse these three urls and use an extra json data var service_url( # ajax only - r'^%s%s$' % ('mark-tag/', 'interesting/'), + r'^{}{}$'.format('mark-tag/', 'interesting/'), views.commands.mark_tag, kwargs={'reason': 'good', 'action': 'add'}, name='mark_interesting_tag' ), service_url( # ajax only - r'^%s%s$' % ('mark-tag/', 'ignored/'), + r'^{}{}$'.format('mark-tag/', 'ignored/'), views.commands.mark_tag, kwargs={'reason': 'bad', 'action': 'add'}, name='mark_ignored_tag' ), service_url( # ajax only - r'^%s%s$' % ('mark-tag/', 'subscribed/'), + r'^{}{}$'.format('mark-tag/', 'subscribed/'), views.commands.mark_tag, kwargs={'reason': 'subscribed', 'action': 'add'}, name='mark_subscribed_tag' diff --git a/askbot/user_messages/context_processors.py b/askbot/user_messages/context_processors.py index 38e3880816..410a35c002 100644 --- a/askbot/user_messages/context_processors.py +++ b/askbot/user_messages/context_processors.py @@ -28,7 +28,7 @@ def user_messages(request): return { 'user_messages': messages } return {} -class LazyMessages(object): +class LazyMessages: """ Lazy message container, so messages aren't actually retrieved from session and deleted until the template asks for them. diff --git a/askbot/utils/classes.py b/askbot/utils/classes.py index d3585cb6a7..0173145625 100644 --- a/askbot/utils/classes.py +++ b/askbot/utils/classes.py @@ -3,7 +3,7 @@ from django.utils import timezone from django.conf import settings as django_settings -class ReminderSchedule(object): #pylint: disable=too-few-public-methods +class ReminderSchedule: #pylint: disable=too-few-public-methods """class that given the three settings: * days to wait before sending the reminders * frequency of reminders diff --git a/askbot/utils/console.py b/askbot/utils/console.py index 562e09cce1..fdc920fe89 100644 --- a/askbot/utils/console.py +++ b/askbot/utils/console.py @@ -42,10 +42,10 @@ def choice_dialog(prompt_phrase, choices=None, invalid_phrase=None, default=None choices = [str(ch) for ch in choices] if default is None: - prompt = '%s\ntype %s\n> ' % (prompt_phrase, '/'.join(choices)) + prompt = '{}\ntype {}\n> '.format(prompt_phrase, '/'.join(choices)) else: default = str(default) - prompt = '%s\nType %s, press ENTER to select %s\n> ' % (prompt_phrase, '/'.join(choices), default) + prompt = '{}\nType {}, press ENTER to select {}\n> '.format(prompt_phrase, '/'.join(choices), default) while 1: response = input(prompt).strip() @@ -77,9 +77,9 @@ def numeric_choice_dialog(prompt_phrase, choices, default=None): assert(not isinstance(choices, str)) choice_menu = "\n".join(["%d - %s" % (i,x) for i, x in enumerate(choices)]) if default: - prompt_phrase = '%s\n%s\nPress ENTER to select %s> ' % (choice_menu, prompt_phrase, default) + prompt_phrase = f'{choice_menu}\n{prompt_phrase}\nPress ENTER to select {default}> ' else: - prompt_phrase = '%s\n%s> ' % (choice_menu, prompt_phrase) + prompt_phrase = f'{choice_menu}\n{prompt_phrase}> ' while True: response = input(prompt_phrase).strip() @@ -122,7 +122,7 @@ def numeric_multiple_choice_dialog(prompt_phrase, choices, all_option=False): choice_indexes = [] index = False while True: - response = input('\n%s\n%s> ' % (choice_menu, prompt_phrase)) + response = input(f'\n{choice_menu}\n{prompt_phrase}> ') selections = response.split() print("selections: %s" % selections) for c in selections: @@ -246,7 +246,7 @@ def print_progress(elapsed, total, nowipe = False): output = '%6.2f%%' % (100 * float(elapsed)/float(total)) print_action(output, nowipe) -class ProgressBar(object): +class ProgressBar: """A wrapper for an iterator, that prints a progress bar along the way of iteration """ @@ -293,7 +293,7 @@ def print_progress_percent(self): def finish_progress_bar(self): """brint the last bars, to make all bars equal length""" self.backspace_progress_percent() - sys.stdout.write('-' * int(math.floor((self.max_barlen - self.curr_barlen)))) + sys.stdout.write('-' * int(math.floor(self.max_barlen - self.curr_barlen))) def __next__(self): diff --git a/askbot/utils/forms.py b/askbot/utils/forms.py index 3054cd3248..351359b952 100644 --- a/askbot/utils/forms.py +++ b/askbot/utils/forms.py @@ -94,10 +94,7 @@ def clean(self, value): class NextUrlField(forms.CharField): def __init__(self): - super( - NextUrlField, - self - ).__init__( + super().__init__( max_length = 255, widget = forms.HiddenInput(), required = False @@ -145,7 +142,7 @@ def __init__( widget_attrs = login_form_widget_attrs max_length = 30#todo: support custom length of user name MAX_USERNAME_LENGTH() - super(UserNameField,self).__init__( + super().__init__( max_length=max_length, widget=forms.TextInput(attrs=widget_attrs), label=label, @@ -168,7 +165,7 @@ def clean(self, username): raise TypeError('user instance must be of type User') try: - username = super(UserNameField, self).clean(username) + username = super().clean(username) except forms.ValidationError: raise forms.ValidationError(self.error_messages['required']) @@ -262,7 +259,7 @@ def __init__(self, skip_clean=False, **kw): else: widget_class = forms.TextInput - super(UserEmailField,self).__init__( + super().__init__( widget=widget_class( attrs=dict(login_form_widget_attrs, maxlength=200) ), @@ -285,7 +282,7 @@ def clean(self, email): moderated_email_validator(email) - email = super(UserEmailField,self).clean(email) + email = super().clean(email) if self.skip_clean: return email @@ -320,7 +317,7 @@ class SetPasswordForm(forms.Form): ) def __init__(self, data=None, user=None, *args, **kwargs): - super(SetPasswordForm, self).__init__(data, *args, **kwargs) + super().__init__(data, *args, **kwargs) def clean_password2(self): """ diff --git a/askbot/utils/jive.py b/askbot/utils/jive.py index ae03ee0851..e8e2ed975e 100755 --- a/askbot/utils/jive.py +++ b/askbot/utils/jive.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# -*- coding: utf-8 -*- # Copyright (c) Askbot S.p.A. 2013 # License: MIT (http://www.opensource.org/licenses/mit-license.php) r"""Converter of Jive markup to markdown, @@ -23,16 +22,8 @@ import codecs #---- Python version compat -if sys.version_info[:2] < (2,4): - from sets import Set as set - def reversed(sequence): - for i in sequence[::-1]: - yield i - def _unicode_decode(s, encoding, errors='xmlcharrefreplace'): - return str(s, encoding, errors) -else: - def _unicode_decode(s, encoding, errors='strict'): - return s.decode(encoding, errors) +def _unicode_decode(s, encoding, errors='strict'): + return s.decode(encoding, errors) #---- globals @@ -78,7 +69,7 @@ def _regularize_eols(text): text = re.sub(r'\n{2,}', '\n', text) return text.strip('\n') -class JiveConverter(object): +class JiveConverter: """converts Jive Markup into HTML""" def __init__(self): @@ -206,14 +197,14 @@ def _hypertext_link_sub1(self, match): elif num_bits == 1: link = link_bits[0] if self._url_re.match(link) or not self._email_re.match(link): - return '%s' % (link, link) + return f'{link}' elif num_bits in (2, 3): #if self._url_re.match(link_bits[1]): if num_bits == 2: - return '%s' % (link_bits[1], link_bits[0]) + return f'{link_bits[0]}' else: bits = link_bits - return '%s' % (bits[1], bits[2], bits[0]) + return f'{bits[0]}' return '[' + '|'.join(link_bits) + ']' _hypertext_link_re2 = re.compile(r'\[url\]%s\[/url\]' % _url_pattern) @@ -264,7 +255,7 @@ def _do_links(self, text): def _h_sub(self, match): n = match.group(1) text = self._run_span_gamut(match.group(2)) - html = '%s' % (n, text, n) + html = f'{text}' return self._hashed(html) def _do_headers(self, text): @@ -392,7 +383,7 @@ def _list_sub(self, match): text = self._list_item_re.sub(self._list_item_sub, text) text = self._nested_list_re.sub(self._nested_list_sub, text) tag = (match.group(2) == '*' and 'ul' or 'ol') - html = '<%s>\n%s' % (tag, text, tag) + html = f'<{tag}>\n{text}' return self._hashed(html) _list_re = re.compile( @@ -408,7 +399,7 @@ def _do_lists(self, text): def _leading_blanks_sub(self, match): spaces = match.group(1) text = match.group(2) - return '%s%s\n' % (' '*len(spaces), text) + return '{}{}\n'.format(' '*len(spaces), text) def _preserve_leading_blanks(self, text): """replace leading blanks with  """ @@ -437,7 +428,7 @@ def _form_paragraphs(self, text): def _auto_link_sub(self, match): """auto-links are just passed through""" link = match.group(1) - return '%s' % (link, link) + return f'{link}' _auto_email_link_re = re.compile(r""" \[ @@ -448,7 +439,7 @@ def _auto_link_sub(self, match): """ % _email_pattern, re.I | re.X | re.U) def _auto_email_link_sub(self, match): email = match.group(1) - return '%s' % (email, email) + return f'{email}' def _do_auto_links(self, text): text = self._auto_link_re.sub(self._auto_link_sub, text) diff --git a/askbot/utils/markup.py b/askbot/utils/markup.py index 70d704af69..3a379a3684 100644 --- a/askbot/utils/markup.py +++ b/askbot/utils/markup.py @@ -82,7 +82,7 @@ def format_mention_in_html(mentioned_user): try: url = mentioned_user.get_profile_url() username = mentioned_user.username - return '@%s' % (url, username) + return f'@{username}' except NoReverseMatch: return "" diff --git a/askbot/utils/mysql.py b/askbot/utils/mysql.py index 08e41b4428..161786b9af 100644 --- a/askbot/utils/mysql.py +++ b/askbot/utils/mysql.py @@ -16,7 +16,7 @@ def mysql_table_supports_full_text_search(table_name): def get_drop_index_sql(index_name, table_name): """returns sql for dropping index by name on table""" - return 'ALTER TABLE %s DROP INDEX %s' % (table_name, index_name) + return f'ALTER TABLE {table_name} DROP INDEX {index_name}' def get_create_full_text_index_sql(index_name, table_name, column_list): diff --git a/askbot/utils/transaction.py b/askbot/utils/transaction.py index 2921fc504b..0d62a2bfe9 100644 --- a/askbot/utils/transaction.py +++ b/askbot/utils/transaction.py @@ -2,7 +2,7 @@ from django.conf import settings as django_settings #from django.core.signals import request_finished -class DummyTransaction(object): +class DummyTransaction: """Dummy transaction class that can be imported instead of the django transaction management and debug issues diff --git a/askbot/utils/twitter.py b/askbot/utils/twitter.py index 2e7f701eeb..4431d464ec 100644 --- a/askbot/utils/twitter.py +++ b/askbot/utils/twitter.py @@ -4,10 +4,10 @@ class Twitter(OAuthConnection): def __new__(cls): - return super(Twitter, cls).__new__(cls, 'twitter') + return super().__new__(cls, 'twitter') def __init__(self): - super(Twitter, self).__init__('twitter') + super().__init__('twitter') self.tweet_url = 'https://api.twitter.com/1.1/statuses/update.json' def tweet(self, text, access_token=None): diff --git a/askbot/utils/unicode_detect.py b/askbot/utils/unicode_detect.py index b6004a12d7..12e6a15bb8 100644 --- a/askbot/utils/unicode_detect.py +++ b/askbot/utils/unicode_detect.py @@ -604,7 +604,7 @@ def _compile_scripts_txt(): idx.append((int(a, 16), int(b or a, 16), names.index(name), cats.index(cat))) idx.sort() - print('script_data = {\n"names":%s,\n"cats":%s,\n"idx":[\n%s\n]}' % ( + print('script_data = {{\n"names":{},\n"cats":{},\n"idx":[\n{}\n]}}'.format( '\n'.join(textwrap.wrap(repr(names), 80)), '\n'.join(textwrap.wrap(repr(cats), 80)), '\n'.join(textwrap.wrap(', '.join('(0x%x,0x%x,%d,%d)' % c for c in idx), 80)))) diff --git a/askbot/utils/views.py b/askbot/utils/views.py index de3c3f0f77..dc09796927 100644 --- a/askbot/utils/views.py +++ b/askbot/utils/views.py @@ -19,7 +19,7 @@ def is_askbot_view(view_func): return True return False -class PjaxView(object): +class PjaxView: """custom class-based view to be used for pjax use and for generation of content in the traditional way, where diff --git a/askbot/views/readers.py b/askbot/views/readers.py index d919109219..4e389d9b6e 100644 --- a/askbot/views/readers.py +++ b/askbot/views/readers.py @@ -1,4 +1,3 @@ -# encoding:utf-8 """ :synopsis: views "read-only" for main textual content diff --git a/askbot/views/users.py b/askbot/views/users.py index 832e37efd3..6f84e7e3ad 100644 --- a/askbot/views/users.py +++ b/askbot/views/users.py @@ -239,13 +239,13 @@ def users_list(request, by_group=False, group_id=None, group_slug=None): matching_users.order_by('-askbot_profile__reputation'), askbot_settings.USERS_PAGE_SIZE ) - base_url = request.path + '?query=%s&sort=%s&' % (search_query, sort_method) + base_url = request.path + f'?query={search_query}&sort={sort_method}&' elif search_query and not cleaned_search_query: objects_list = Paginator( models.User.objects.none(), askbot_settings.USERS_PAGE_SIZE ) - base_url = request.path + '?query=%s&sort=%s&' % (search_query, sort_method) + base_url = request.path + f'?query={search_query}&sort={sort_method}&' else: if sort_method == 'newest': order_by_parameter = '-date_joined' @@ -855,7 +855,7 @@ def get_type_name(type_id): if type_id in item: return item[1] - class Event(object): + class Event: is_badge = False def __init__(self, time, type, title, summary, url): self.time = time @@ -866,7 +866,7 @@ def __init__(self, time, type, title, summary, url): slug_title = slugify(title) self.title_link = url - class AwardEvent(object): + class AwardEvent: is_badge = True def __init__(self, time, type, content_object, badge): self.time = time @@ -1157,12 +1157,12 @@ def user_reputation(request, user, context): def format_graph_data(raw_data, user): # prepare data for the graph - last values go in first final_rep = user.get_localized_profile().reputation + const.MIN_REPUTATION - rep_list = ['[%s,%s]' % (calendar.timegm(datetime.datetime.now().timetuple()) * 1000, final_rep)] + rep_list = [f'[{calendar.timegm(datetime.datetime.now().timetuple()) * 1000},{final_rep}]'] for rep in raw_data: - rep_list.append('[%s,%s]' % (calendar.timegm(rep.reputed_at.timetuple()) * 1000, rep.reputation)) + rep_list.append(f'[{calendar.timegm(rep.reputed_at.timetuple()) * 1000},{rep.reputation}]') #add initial rep point - rep_list.append('[%s,%s]' % (calendar.timegm(user.date_joined.timetuple()) * 1000, const.MIN_REPUTATION)) + rep_list.append(f'[{calendar.timegm(user.date_joined.timetuple()) * 1000},{const.MIN_REPUTATION}]') reps = ','.join(rep_list) return '[%s]' % reps diff --git a/askbot/views/writers.py b/askbot/views/writers.py index 15cc820f16..ae1718ec60 100644 --- a/askbot/views/writers.py +++ b/askbot/views/writers.py @@ -1,4 +1,3 @@ -# encoding:utf-8 """ :synopsis: views diplaying and processing main content post forms @@ -144,7 +143,7 @@ def __import_se_data(dump_file): #run a loop where we'll be reading output of the #importer tread and yielding it to the caller - read_stdout = open(fake_stdout.name, 'r') + read_stdout = open(fake_stdout.name) file_pos = 0 fd = read_stdout.fileno() yield '

Importing your data. This may take a few minutes...

' @@ -228,7 +227,7 @@ def ask(request):#view used to ask a new question #group_id = form.cleaned_data.get('group_id', None) language = form.cleaned_data.get('language', None) - content = '{}\n\n{}\n\n{}'.format(title, tagnames, text) + content = f'{title}\n\n{tagnames}\n\n{text}' spam_checker_params = spam_checker.get_params_from_request(request) enabled = askbot_settings.SPAM_FILTER_ENABLED if enabled and spam_checker.is_spam(content, **spam_checker_params): diff --git a/ez_setup.py b/ez_setup.py index f46e986bc6..2313fe8543 100644 --- a/ez_setup.py +++ b/ez_setup.py @@ -66,7 +66,7 @@ def _build_egg(egg, archive_filename, to_dir): # returning the result log.warn(egg) if not os.path.exists(egg): - raise IOError('Could not build the egg.') + raise OSError('Could not build the egg.') class ContextualZipFile(zipfile.ZipFile): @@ -83,7 +83,7 @@ def __new__(cls, *args, **kwargs): """Construct a ZipFile or ContextualZipFile as appropriate.""" if hasattr(zipfile.ZipFile, '__exit__'): return zipfile.ZipFile(*args, **kwargs) - return super(ContextualZipFile, cls).__new__(cls) + return super().__new__(cls) @contextlib.contextmanager @@ -222,8 +222,7 @@ def download_file_powershell(url, target): ps_cmd = ( "[System.Net.WebRequest]::DefaultWebProxy.Credentials = " "[System.Net.CredentialCache]::DefaultCredentials; " - "(new-object System.Net.WebClient).DownloadFile(%(url)r, %(target)r)" - % vars() + "(new-object System.Net.WebClient).DownloadFile({url!r}, {target!r})".format(**vars()) ) cmd = [ 'powershell', diff --git a/pyproject.toml b/pyproject.toml index 8e2eb05307..a2a43e27b0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -59,7 +59,7 @@ select = [ # TODO: "SLF", # flake8-self # TODO: "SLOT", # flake8-slots # TODO: "TID", # flake8-tidy-imports - # ** TODO: "UP", # pyupgrade + "UP", # pyupgrade # ** TODO: "Q", # flake8-quotes # TODO: "TCH", # flake8-type-checking # TODO: "T10", # flake8-debugger diff --git a/setup.py b/setup.py index a829289311..a43957e6b2 100644 --- a/setup.py +++ b/setup.py @@ -1,4 +1,3 @@ -from __future__ import print_function from setuptools import setup, find_packages import sys import askbot diff --git a/testproject/testproject/celery.py b/testproject/testproject/celery.py index db2a1233fd..a25dcbf051 100644 --- a/testproject/testproject/celery.py +++ b/testproject/testproject/celery.py @@ -18,4 +18,4 @@ @app.task(bind=True) def debug_task(self): - print('Request: {0!r}'.format(self.request)) + print(f'Request: {self.request!r}') diff --git a/testproject/testproject/settings.py b/testproject/testproject/settings.py index 1d1af72cd6..27eedbeab5 100644 --- a/testproject/testproject/settings.py +++ b/testproject/testproject/settings.py @@ -240,7 +240,7 @@ ASKBOT_URL = '' #no leading slash, default = '' empty string ASKBOT_TRANSLATE_URL = True #translate specific URLs _ = lambda v:v #fake translation function for the login url -LOGIN_URL = '/%s%s%s' % (ASKBOT_URL, _('account/'), _('signin/')) +LOGIN_URL = '/{}{}{}'.format(ASKBOT_URL, _('account/'), _('signin/')) LOGIN_REDIRECT_URL = ASKBOT_URL #adjust, if needed #note - it is important that upload dir url is NOT translated!!! #also, this url must not have the leading slash @@ -343,7 +343,7 @@ message_level.ERROR: 'notification_error', } -class DisableMigrations(object): +class DisableMigrations: def __contains__(self, item): return True