Use f-strings

This commit is contained in:
Andrew-Chen-Wang 2021-05-13 02:44:58 -04:00
parent 70e970e46f
commit 431be11fc8
10 changed files with 46 additions and 79 deletions

View file

@ -45,7 +45,7 @@ def _get_tables(tables_or_models):
else table_or_model._meta.db_table)
def invalidate(*tables_or_models, **kwargs):
def invalidate(*tables_or_models, cache_alias=None, db_alias=None) -> None:
"""
Clears what was cached by django-cachalot implying one or more SQL tables
or models from ``tables_or_models``.
@ -68,13 +68,6 @@ def invalidate(*tables_or_models, **kwargs):
:returns: Nothing
:rtype: NoneType
"""
# TODO: Replace with positional arguments when we drop Python 2 support.
cache_alias = kwargs.pop('cache_alias', None)
db_alias = kwargs.pop('db_alias', None)
for k in kwargs:
raise TypeError(
"invalidate() got an unexpected keyword argument '%s'" % k)
send_signal = False
invalidated = set()
for cache_alias, db_alias, tables in _cache_db_tables_iterator(
@ -90,7 +83,7 @@ def invalidate(*tables_or_models, **kwargs):
post_invalidation.send(table, db_alias=db_alias)
def get_last_invalidation(*tables_or_models, **kwargs):
def get_last_invalidation(*tables_or_models, cache_alias=None, db_alias=None):
"""
Returns the timestamp of the most recent invalidation of the given
``tables_or_models``. If ``tables_or_models`` is not specified,
@ -112,13 +105,6 @@ def get_last_invalidation(*tables_or_models, **kwargs):
:returns: The timestamp of the most recent invalidation
:rtype: float
"""
# TODO: Replace with positional arguments when we drop Python 2 support.
cache_alias = kwargs.pop('cache_alias', None)
db_alias = kwargs.pop('db_alias', None)
for k in kwargs:
raise TypeError("get_last_invalidation() got an unexpected "
"keyword argument '%s'" % k)
last_invalidation = 0.0
for cache_alias, db_alias, tables in _cache_db_tables_iterator(
list(_get_tables(tables_or_models)), cache_alias, db_alias):
@ -160,7 +146,9 @@ def cachalot_disabled(all_queries=False):
:arg all_queries: Any query, including already evaluated queries, are re-evaluated.
:type all_queries: bool
"""
was_enabled = getattr(LOCAL_STORAGE, "cachalot_enabled", cachalot_settings.CACHALOT_ENABLED)
was_enabled = getattr(
LOCAL_STORAGE, "cachalot_enabled", cachalot_settings.CACHALOT_ENABLED
)
LOCAL_STORAGE.cachalot_enabled = False
LOCAL_STORAGE.disable_on_all = all_queries
yield

View file

@ -15,10 +15,8 @@ def check_cache_compatibility(app_configs, **kwargs):
cache_backend = cache['BACKEND']
if cache_backend not in SUPPORTED_CACHE_BACKENDS:
return [Warning(
'Cache backend %r is not supported by django-cachalot.'
% cache_backend,
hint='Switch to a supported cache backend '
'like Redis or Memcached.',
f'Cache backend {cache_backend} is not supported by django-cachalot.',
hint='Switch to a supported cache backend like Redis or Memcached.',
id='cachalot.W001')]
return []
@ -27,14 +25,12 @@ def check_cache_compatibility(app_configs, **kwargs):
def check_databases_compatibility(app_configs, **kwargs):
errors = []
databases = settings.DATABASES
original_enabled_databases = getattr(settings, 'CACHALOT_DATABASES',
SUPPORTED_ONLY)
original_enabled_databases = getattr(settings, 'CACHALOT_DATABASES', SUPPORTED_ONLY)
enabled_databases = cachalot_settings.CACHALOT_DATABASES
if original_enabled_databases == SUPPORTED_ONLY:
if not cachalot_settings.CACHALOT_DATABASES:
errors.append(Warning(
'None of the configured databases are supported '
'by django-cachalot.',
'None of the configured databases are supported by django-cachalot.',
hint='Use a supported database, or remove django-cachalot, or '
'put at least one database alias in `CACHALOT_DATABASES` '
'to force django-cachalot to use it.',
@ -46,15 +42,15 @@ def check_databases_compatibility(app_configs, **kwargs):
engine = databases[db_alias]['ENGINE']
if engine not in SUPPORTED_DATABASE_ENGINES:
errors.append(Warning(
'Database engine %r is not supported '
'by django-cachalot.' % engine,
f'Database engine {engine} is not supported '
'by django-cachalot.',
hint='Switch to a supported database engine.',
id='cachalot.W003'
id='cachalot.W003',
))
else:
errors.append(Error(
'Database alias %r from `CACHALOT_DATABASES` '
'is not defined in `DATABASES`.' % db_alias,
f'Database alias {db_alias} from `CACHALOT_DATABASES` '
'is not defined in `DATABASES`.',
hint='Change `CACHALOT_DATABASES` to be compliant with'
'`CACHALOT_DATABASES`',
id='cachalot.E001',
@ -69,8 +65,8 @@ def check_databases_compatibility(app_configs, **kwargs):
))
else:
errors.append(Error(
"`CACHALOT_DATABASES` must be either %r or a list, tuple, "
"frozenset or set of database aliases." % SUPPORTED_ONLY,
f"`CACHALOT_DATABASES` must be either {SUPPORTED_ONLY} or a list, tuple, "
"frozenset or set of database aliases.",
hint='Remove `CACHALOT_DATABASES` or change it.',
id='cachalot.E002',
))

View file

@ -12,9 +12,7 @@ class CachalotExtension(Extension):
def __init__(self, environment):
super(CachalotExtension, self).__init__(environment)
self.environment.globals.update(
get_last_invalidation=get_last_invalidation)
self.environment.globals.update(get_last_invalidation=get_last_invalidation)
def parse_args(self, parser):
args = []
@ -23,14 +21,11 @@ class CachalotExtension(Extension):
stream = parser.stream
while stream.current.type != 'block_end':
if stream.current.type == 'name' \
and stream.look().type == 'assign':
if stream.current.type == 'name' and stream.look().type == 'assign':
key = stream.current.value
if key not in self.allowed_kwargs:
parser.fail(
"'%s' is not a valid keyword argument "
"for {%% cache %%}" % key,
stream.current.lineno)
parser.fail(f"'{key}' is not a valid keyword argument "
"for {%% cache %%}", stream.current.lineno)
stream.skip(2)
value = parser.parse_expression()
kwargs.append(Keyword(key, value, lineno=value.lineno))
@ -49,7 +44,7 @@ class CachalotExtension(Extension):
lineno = next(parser.stream).lineno
args, kwargs = self.parse_args(parser)
default_cache_key = (None if parser.filename is None
else '%s:%d' % (parser.filename, lineno))
else f'{parser.filename}:{lineno}')
kwargs.append(Keyword('default_cache_key', Const(default_cache_key),
lineno=lineno))
body = parser.parse_statements(['name:end' + tag], drop_needle=True)

View file

@ -34,9 +34,9 @@ class Command(BaseCommand):
model_name = label.split('.')[-1]
models.append(apps.get_model(app_label, model_name))
cache_str = '' if cache_alias is None else "on cache '%s'" % cache_alias
db_str = '' if db_alias is None else "for database '%s'" % db_alias
keys_str = 'keys for %s models' % len(models) if labels else 'all keys'
cache_str = '' if cache_alias is None else f"on cache '{cache_alias}'"
db_str = '' if db_alias is None else f"for database '{db_alias}'"
keys_str = f'keys for {len(models)} models' if labels else 'all keys'
if verbosity > 0:
self.stdout.write(' '.join(filter(bool, ['Invalidating', keys_str,

View file

@ -49,8 +49,7 @@ class CachalotPanel(Panel):
model_cache_keys = {
get_table_cache_key(db_alias, model._meta.db_table): model
for model in models}
for cache_key, timestamp in cache.get_many(
model_cache_keys.keys()).items():
for cache_key, timestamp in cache.get_many(model_cache_keys.keys()).items():
invalidation = datetime.fromtimestamp(timestamp)
model = model_cache_keys[cache_key]
data[db_alias].append(
@ -64,6 +63,5 @@ class CachalotPanel(Panel):
@property
def nav_subtitle(self):
if self.enabled and self.last_invalidation is not None:
return (_('Last invalidation: %s')
% timesince(self.last_invalidation))
return _('Last invalidation: %s') % timesince(self.last_invalidation)
return ''

View file

@ -22,8 +22,7 @@ class DebugToolbarTestCase(LiveServerTestCase):
UUID(store_id)
render_panel_url = toolbar.attrs['data-render-panel-url']
panel_id = soup.find(title='Cachalot')['class'][0]
panel_url = ('%s?store_id=%s&panel_id=%s'
% (render_panel_url, store_id, panel_id))
panel_url = f'{render_panel_url}?store_id={store_id}&panel_id={panel_id}'
#
# Rendering panel

View file

@ -697,24 +697,22 @@ class ReadTestCase(TestUtilsMixin, TransactionTestCase):
r'(?:None )?ALL None None None None 2 100\.0 Using filesort')
else:
expected = (
r'-> Sort row IDs: cachalot_test.`name` \(cost=[\d\.]+ rows=\d\)\n '
r'-> Table scan on cachalot_test \(cost=[\d\.]+ rows=\d\)\n'
r'-> Sort row IDs: cachalot_test.`name` \(cost=[\d\.]+ rows=\d\)\n'
r' -> Table scan on cachalot_test \(cost=[\d\.]+ rows=\d\)\n'
)
else:
explain_kwargs.update(
analyze=True,
costs=False,
)
operation_detail = (r'\(actual time=[\d\.]+..[\d\.]+\ '
r'rows=\d+ loops=\d+\)')
operation_detail = r'\(actual time=[\d\.]+..[\d\.]+\ rows=\d+ loops=\d+\)'
expected = (
r'^Sort %s\n'
rf'^Sort {operation_detail}\n'
r' Sort Key: name\n'
r' Sort Method: quicksort Memory: \d+kB\n'
r' -> Seq Scan on cachalot_test %s\n'
rf' -> Seq Scan on cachalot_test {operation_detail}\n'
r'Planning Time: [\d\.]+ ms\n'
r'Execution Time: [\d\.]+ ms$') % (operation_detail,
operation_detail)
r'Execution Time: [\d\.]+ ms$')
with self.assertNumQueries(
2 if self.is_mysql and django_version[0] < 3
else 1):
@ -729,7 +727,7 @@ class ReadTestCase(TestUtilsMixin, TransactionTestCase):
Tests if ``Model.objects.raw`` queries are not cached.
"""
sql = 'SELECT * FROM %s;' % Test._meta.db_table
sql = f'SELECT * FROM {Test._meta.db_table};'
with self.assertNumQueries(1):
data1 = list(Test.objects.raw(sql))
@ -752,13 +750,10 @@ class ReadTestCase(TestUtilsMixin, TransactionTestCase):
"""
Tests if queries executed from a DB cursor are not cached.
"""
attname_column_list = [f.get_attname_column()
for f in Test._meta.fields]
attname_column_list = [f.get_attname_column() for f in Test._meta.fields]
attnames = [t[0] for t in attname_column_list]
columns = [t[1] for t in attname_column_list]
sql = "SELECT CAST('é' AS CHAR), %s FROM %s;" % (', '.join(columns),
Test._meta.db_table)
sql = f"SELECT CAST('é' AS CHAR), {', '.join(columns)} FROM {Test._meta.db_table};"
with self.assertNumQueries(1):
with connection.cursor() as cursor:
@ -780,9 +775,8 @@ class ReadTestCase(TestUtilsMixin, TransactionTestCase):
for f in Test._meta.fields]
attnames = [t[0] for t in attname_column_list]
columns = [t[1] for t in attname_column_list]
sql = "SELECT CAST('é' AS CHAR), %s FROM %s;" % (', '.join(columns),
Test._meta.db_table)
sql = sql.encode('utf-8')
sql = f"SELECT CAST('é' AS CHAR), {', '.join(columns)} " \
f"FROM {Test._meta.db_table};".encode('utf-8')
with self.assertNumQueries(1):
with connection.cursor() as cursor:
@ -855,18 +849,18 @@ class ReadTestCase(TestUtilsMixin, TransactionTestCase):
"""
table_name = 'Clémentine'
if self.is_postgresql:
table_name = '"%s"' % table_name
table_name = f'"{table_name}"'
with connection.cursor() as cursor:
cursor.execute('CREATE TABLE %s (taste VARCHAR(20));' % table_name)
cursor.execute(f'CREATE TABLE {table_name} (taste VARCHAR(20));')
qs = Test.objects.extra(tables=['Clémentine'],
select={'taste': '%s.taste' % table_name})
select={'taste': f'{table_name}.taste'})
# Here the table `Clémentine` is not detected because it is not
# registered by Django, and we only check for registered tables
# to avoid creating an extra SQL query fetching table names.
self.assert_tables(qs, Test)
self.assert_query_cached(qs)
with connection.cursor() as cursor:
cursor.execute('DROP TABLE %s;' % table_name)
cursor.execute(f'DROP TABLE {table_name};')
def test_unmanaged_model(self):
qs = UnmanagedModel.objects.all()

View file

@ -125,8 +125,7 @@ class SettingsTestCase(TestUtilsMixin, TransactionTestCase):
with self.settings(CACHALOT_INVALIDATE_RAW=False):
with self.assertNumQueries(1):
with connection.cursor() as cursor:
cursor.execute("UPDATE %s SET name = 'new name';"
% Test._meta.db_table)
cursor.execute(f"UPDATE {Test._meta.db_table} SET name = 'new name';")
with self.assertNumQueries(0):
list(Test.objects.all())

View file

@ -161,8 +161,7 @@ class WriteTestCase(TestUtilsMixin, TransactionTestCase):
self.assertListEqual(data2, [t1.name])
with self.assertNumQueries(2 if self.is_sqlite else 1):
Test.objects.bulk_create([Test(name='test%s' % i)
for i in range(2, 11)])
Test.objects.bulk_create([Test(name=f'test{i}') for i in range(2, 11)])
with self.assertNumQueries(1):
self.assertEqual(Test.objects.count(), 10)
with self.assertNumQueries(2 if self.is_sqlite else 1):

View file

@ -75,8 +75,7 @@ def get_query_cache_key(compiler):
"""
sql, params = compiler.as_sql()
check_parameter_types(params)
cache_key = '%s:%s:%s' % (compiler.using, sql,
[str(p) for p in params])
cache_key = f'{compiler.using}:{sql}:{[str(p) for p in params]}'
return sha1(cache_key.encode('utf-8')).hexdigest()
@ -91,7 +90,7 @@ def get_table_cache_key(db_alias, table):
:return: A cache key
:rtype: int
"""
cache_key = '%s:%s' % (db_alias, table)
cache_key = f'{db_alias}:{table}'
return sha1(cache_key.encode('utf-8')).hexdigest()