djblets.db.query_comparator¶
Utilities for comparing executed queries to expectations.
These are used internally for unit testing, but can also be useful when instrumenting code.
New in version 3.4.
- class QueryMismatchedAttr[source]¶
Bases:
TypedDict
An attribute for a query that failed to meet expectations.
New in version 3.4.
- __annotations__ = {'executed_value': ForwardRef('NotRequired[str]', module='djblets.db.query_comparator'), 'expected_value': ForwardRef('NotRequired[str]', module='djblets.db.query_comparator'), 'name': ForwardRef('str', module='djblets.db.query_comparator'), 'raw_executed_value': ForwardRef('NotRequired[Any]', module='djblets.db.query_comparator'), 'raw_expected_value': ForwardRef('NotRequired[Any]', module='djblets.db.query_comparator')}¶
- __closed__ = False¶
- __extra_items__ = None¶
- __mutable_keys__ = frozenset({'executed_value', 'expected_value', 'name', 'raw_executed_value', 'raw_expected_value'})¶
- __optional_keys__ = frozenset({})¶
- __orig_bases__ = (<function TypedDict>,)¶
- __readonly_keys__ = frozenset({})¶
- __required_keys__ = frozenset({'executed_value', 'expected_value', 'name', 'raw_executed_value', 'raw_expected_value'})¶
- __total__ = True¶
- class QueryMismatch[source]¶
Bases:
TypedDict
Information on a mismatched query.
New in version 3.4.
- executed_query: Query¶
The query that was executed.
- mismatched_attrs: List[QueryMismatchedAttr]¶
The list of mismatched attributes in this query.
- subqueries: Optional[CompareQueriesContext]¶
The results for any subquery matches.
- __annotations__ = {'executed_query': ForwardRef('SQLQuery', module='djblets.db.query_comparator'), 'index': ForwardRef('int', module='djblets.db.query_comparator'), 'mismatched_attrs': ForwardRef('List[QueryMismatchedAttr]', module='djblets.db.query_comparator'), 'note': ForwardRef('Optional[str]', module='djblets.db.query_comparator'), 'query_sql': ForwardRef('Optional[List[str]]', module='djblets.db.query_comparator'), 'subqueries': ForwardRef('Optional[CompareQueriesContext]', module='djblets.db.query_comparator'), 'traceback': ForwardRef('Optional[List[str]]', module='djblets.db.query_comparator')}¶
- __closed__ = False¶
- __extra_items__ = None¶
- __mutable_keys__ = frozenset({'executed_query', 'index', 'mismatched_attrs', 'note', 'query_sql', 'subqueries', 'traceback'})¶
- __optional_keys__ = frozenset({})¶
- __orig_bases__ = (<function TypedDict>,)¶
- __readonly_keys__ = frozenset({})¶
- __required_keys__ = frozenset({'executed_query', 'index', 'mismatched_attrs', 'note', 'query_sql', 'subqueries', 'traceback'})¶
- __total__ = True¶
- class ExpectedQuery[source]¶
Bases:
TypedDict
An expected query for a query assertion.
This is used for
TestCase.assertQueries()
.While this type is new, the documented keys (unless otherwise noted) were introduced in Djblets 2.3.1.
New in version 3.4.
- __note__: NotRequired[str]¶
A custom note for the query, to help with query inspection.
New in version 3.4.
- annotations: NotRequired[Dict[str, BaseExpression]]¶
A dictionary containing applied annotations.
Keys are destination attribute names, and values are the annotation instances.
The default is empty.
- distinct: NotRequired[bool]¶
Whether
django.db.models.query.QuerySet.distinct()
was used.The default is
False
.
- distinct_fields: NotRequired[Tuple[str, ...]]¶
A list of distinct fields.
These are field names passed to
django.db.models.query.QuerySet.distinct()
.The default is empty.
- extra: NotRequired[Dict[str, Any]]¶
Extra state passed in the queryset.
This is state passed in calls to
django.db.models.query.QuerySet.extra()
when usingselect
andselect_params
.Each key maps to a key in
select
, and each value is a tuple containing the value inselect
and the corresponding value (if any) inselect_params
.Values are normalized to collapse and strip whitespace, to help with comparison.
The default is empty.
- extra_order_by: NotRequired[Sequence[str]]¶
Extra order-by values.
This is state passed in calls to
django.db.models.query.QuerySet.extra()
when usingorder_by
.The default is empty.
- extra_tables: NotRequired[Sequence[str]]¶
Extra tables for the query.
This is state passed in calls to
django.db.models.query.QuerySet.extra()
when usingtables
.The default is empty.
- group_by: NotRequired[Optional[Union[bool, Tuple[str, ...]]]]¶
The grouping of results.
This determines whether no fields will be grouped (
None
), all fields will be grouped (True
), or specific expressions/field names are grouped (a tuple).This is influenced by using
django.db.models.query.QuerySet.annotate()
.The default is
None
.
- join_types: NotRequired[Dict[str, str]]¶
A mapping of joined table names to their join types.
New in version 3.4.
- limit: NotRequired[Optional[int]]¶
The value for a
LIMIT
in theSELECT
.This will generally only need to be supplied if testing a query using
QuerySet.exists()
or when slicing results.Django itself sometimes uses a default of
None
and sometimes a default currently of21
(this exact value, and when it’s used, is considered an implementation detail in Django). Both of these will match a caller-providedlimit
value ofNone
.The default is
None
.
- model: NotRequired[Type[Model]]¶
The model backing the queryset.
This represents the results that would be returned or altered by the query.
- only_fields: NotRequired[Set[str]]¶
The specific fields being fetched, or
None
if fetching all fields.The default is
None
.
- select_for_update: NotRequired[bool]¶
Whether this is a select-for-update operation.
The default is
False
.
The table names involved in a select-related operation.
These are the names passed to
django.db.models.query.QuerySet.select_related()
. If called without any parameters, this would beTrue
.
- subqueries: NotRequired[Optional[ExpectedQueries]]¶
Information on subqueries within this query.
New in version 3.4.
- subquery: NotRequired[bool]¶
Whether this is considered a subquery of another query.
The default is
False
.
- tables: NotRequired[Set[str]]¶
The tables involved in the query.
The default is the model’s table name.
- type: NotRequired[str]¶
The query type.
This would be one of
DELETE
,INSERT
,SELECT
, orUPDATE
.The default is
SELECT
.
- values_select: NotRequired[Tuple[str, ...]]¶
A list of specified fields to return as values.
These are values passed in
values()
orvalues_list()
.
- where: NotRequired[Q]¶
The query expression objects used to represent the filter on the query.
These are normalized to filter out empty or unnecessarily-nested queries, to ease comparison.
- __annotations__ = {'__note__': ForwardRef('NotRequired[str]', module='djblets.db.query_comparator'), 'annotations': ForwardRef('NotRequired[Dict[str, BaseExpression]]', module='djblets.db.query_comparator'), 'distinct': ForwardRef('NotRequired[bool]', module='djblets.db.query_comparator'), 'distinct_fields': ForwardRef('NotRequired[Tuple[str, ...]]', module='djblets.db.query_comparator'), 'extra': ForwardRef('NotRequired[Dict[str, Any]]', module='djblets.db.query_comparator'), 'extra_order_by': ForwardRef('NotRequired[Sequence[str]]', module='djblets.db.query_comparator'), 'extra_tables': ForwardRef('NotRequired[Sequence[str]]', module='djblets.db.query_comparator'), 'group_by': ForwardRef('NotRequired[Optional[Union[bool, Tuple[str, ...]]]]', module='djblets.db.query_comparator'), 'join_types': ForwardRef('NotRequired[Dict[str, str]]', module='djblets.db.query_comparator'), 'limit': ForwardRef('NotRequired[Optional[int]]', module='djblets.db.query_comparator'), 'model': ForwardRef('NotRequired[Type[Model]]', module='djblets.db.query_comparator'), 'num_joins': ForwardRef('NotRequired[int]', module='djblets.db.query_comparator'), 'offset': ForwardRef('NotRequired[int]', module='djblets.db.query_comparator'), 'only_fields': ForwardRef('NotRequired[Set[str]]', module='djblets.db.query_comparator'), 'order_by': ForwardRef('NotRequired[Tuple[str, ...]]', module='djblets.db.query_comparator'), 'select_for_update': ForwardRef('NotRequired[bool]', module='djblets.db.query_comparator'), 'select_related': ForwardRef('NotRequired[Union[Literal[True], Set[str]]]', module='djblets.db.query_comparator'), 'subqueries': ForwardRef('NotRequired[Optional[ExpectedQueries]]', module='djblets.db.query_comparator'), 'subquery': ForwardRef('NotRequired[bool]', module='djblets.db.query_comparator'), 'tables': ForwardRef('NotRequired[Set[str]]', module='djblets.db.query_comparator'), 'type': ForwardRef('NotRequired[str]', module='djblets.db.query_comparator'), 'values_select': ForwardRef('NotRequired[Tuple[str, ...]]', module='djblets.db.query_comparator'), 'where': ForwardRef('NotRequired[Q]', module='djblets.db.query_comparator')}¶
- __closed__ = False¶
- __extra_items__ = None¶
- __mutable_keys__ = frozenset({'__note__', 'annotations', 'distinct', 'distinct_fields', 'extra', 'extra_order_by', 'extra_tables', 'group_by', 'join_types', 'limit', 'model', 'num_joins', 'offset', 'only_fields', 'order_by', 'select_for_update', 'select_related', 'subqueries', 'subquery', 'tables', 'type', 'values_select', 'where'})¶
- __optional_keys__ = frozenset({})¶
- __orig_bases__ = (<function TypedDict>,)¶
- __readonly_keys__ = frozenset({})¶
- __required_keys__ = frozenset({'__note__', 'annotations', 'distinct', 'distinct_fields', 'extra', 'extra_order_by', 'extra_tables', 'group_by', 'join_types', 'limit', 'model', 'num_joins', 'offset', 'only_fields', 'order_by', 'select_for_update', 'select_related', 'subqueries', 'subquery', 'tables', 'type', 'values_select', 'where'})¶
- __total__ = True¶
- ExpectedQueries¶
A type representing list of expected queries.
Note
This type allows either a
ExpectedQuery()
or a plain dictionary of string-based keys. This is because with pyright (as of 1.1.332), the type of the right-hand-side of a+=
operation cannot be inferred. That makes it difficult to dynamically build expected queries.Until/unless the situation improves, we aim for an
ExpectedQuery()
but allow a plain dictionary.New in version 3.4.
- class CompareQueriesContext[source]¶
Bases:
TypedDict
Context for compared query results.
This is provided and populated when using
compare_queries()
.New in version 3.4.
- query_mismatches: List[QueryMismatch]¶
The list of query expectation failures.
- __annotations__ = {'_unchecked_mismatched_attrs': ForwardRef('Set[str]', module='djblets.db.query_comparator'), 'has_mismatches': ForwardRef('bool', module='djblets.db.query_comparator'), 'num_executed_queries': ForwardRef('int', module='djblets.db.query_comparator'), 'num_expected_queries': ForwardRef('int', module='djblets.db.query_comparator'), 'query_count_mismatch': ForwardRef('bool', module='djblets.db.query_comparator'), 'query_mismatches': ForwardRef('List[QueryMismatch]', module='djblets.db.query_comparator')}¶
- __closed__ = False¶
- __extra_items__ = None¶
- __mutable_keys__ = frozenset({'_unchecked_mismatched_attrs', 'has_mismatches', 'num_executed_queries', 'num_expected_queries', 'query_count_mismatch', 'query_mismatches'})¶
- __optional_keys__ = frozenset({})¶
- __orig_bases__ = (<function TypedDict>,)¶
- __readonly_keys__ = frozenset({})¶
- __required_keys__ = frozenset({'_unchecked_mismatched_attrs', 'has_mismatches', 'num_executed_queries', 'num_expected_queries', 'query_count_mismatch', 'query_mismatches'})¶
- __total__ = True¶
- compare_queries(queries: Sequence[Union[ExpectedQuery, Dict[str, Any]]], *, _check_join_types: bool = True, _check_subqueries: bool = True) Iterator[CompareQueriesContext] [source]¶
Assert the number and complexity of queries.
This provides advanced checking of queries, allowing the caller to match filtering, JOINs, ordering, selected fields, and more.
This takes a list of dictionaries with query information. Each contains the keys in
ExpectedQuery
.New in version 3.4.
- Parameters:
queries (
list
ofExpectedQuery
) – The list of query dictionaries to compare executed queries against._check_join_types (
bool
, optional) –Whether to check join types.
This is internal for compatibility with the old behavior for
TestCase.assertQueries()
and will be removed in a future release without a deprecation period._check_subqueries (
bool
, optional) –Whether to check subqueries.
This is internal for compatibility with the old behavior for
TestCase.assertQueries()
and will be removed in a future release without a deprecation period.
- Context:
dict
– The context for compared queries.This will only be populated after the context manager has finished. See
CompareQueriesContext
for details.