TicketQuery Wiki Macro

The TicketQuery macro lets you display ticket information anywhere that accepts WikiFormatting. The query language used by the [[TicketQuery]] macro is described in the TracQuery page.

Usage

[[TicketQuery]]

Wiki macro listing tickets that match certain criteria.

This macro accepts a comma-separated list of keyed parameters, in the form "key=value".

If the key is the name of a field, the value must use the syntax of a filter specifier as defined in TracQuery#QueryLanguage. Note that this is not the same as the simplified URL syntax used for query: links starting with a ? character. Commas (,) can be included in field values by escaping them with a backslash (\).

Groups of field constraints to be OR-ed together can be separated by a literal or argument.

In addition to filters, several other named parameters can be used to control how the results are presented. All of them are optional.

The format parameter determines how the list of tickets is presented:

  • list -- the default presentation is to list the ticket ID next to the summary, with each ticket on a separate line.
  • compact -- the tickets are presented as a comma-separated list of ticket IDs.
  • count -- only the count of matching tickets is displayed
  • rawcount -- only the count of matching tickets is displayed, not even with a link to the corresponding query (since 1.1.1)
  • table -- a view similar to the custom query view (but without the controls)
  • progress -- a view similar to the milestone progress bars

The max parameter can be used to limit the number of tickets shown (defaults to 0, i.e. no maximum).

The order parameter sets the field used for ordering tickets (defaults to id).

The desc parameter indicates whether the order of the tickets should be reversed (defaults to false).

The group parameter sets the field used for grouping tickets (defaults to not being set).

The groupdesc parameter indicates whether the natural display order of the groups should be reversed (defaults to false).

The verbose parameter can be set to a true value in order to get the description for the listed tickets. For table format only. deprecated in favor of the rows parameter

The rows parameter can be used to specify which field(s) should be viewed as a row, e.g. rows=description|summary

The col parameter can be used to specify which fields should be viewed as columns. For table format only.

For compatibility with Trac 0.10, if there's a last positional parameter given to the macro, it will be used to specify the format. Also, using "&" as a field separator still works (except for order) but is deprecated.

Examples

Example Result Macro
Number of Triage tickets: 606 [[TicketQuery(status=new&milestone=,count)]]
Number of new tickets: 606 [[TicketQuery(status=new,count)]]
Number of reopened tickets: 0 [[TicketQuery(status=reopened,count)]]
Number of assigned tickets: 459 [[TicketQuery(status=assigned,count)]]
Number of invalid tickets: 5268 [[TicketQuery(status=closed,resolution=invalid,count)]]
Number of worksforme tickets: 1085 [[TicketQuery(status=closed,resolution=worksforme,count)]]
Number of duplicate tickets: 4390 [[TicketQuery(status=closed,resolution=duplicate,count)]]
Number of wontfix tickets: 4218 [[TicketQuery(status=closed,resolution=wontfix,count)]]
Number of fixed tickets: 18949 [[TicketQuery(status=closed,resolution=fixed,count)]]
Number of untriaged tickets (milestone unset): 1065 [[TicketQuery(status!=closed,milestone=,count)]]
Total number of tickets: 35964 [[TicketQuery(count)]]
Number of tickets reported or owned by current user: 1488 [[TicketQuery(reporter=$USER,or,owner=$USER,count)]]
Number of tickets created this month: 50 [[TicketQuery(created=thismonth..,count)]]
Number of closed Firefox tickets: 8 [[TicketQuery(status=closed,keywords~=firefox,count)]]
Number of closed Opera tickets: 25 [[TicketQuery(status=closed,keywords~=opera,count)]]
Number of closed tickets affecting Firefox and Opera: 0 [[TicketQuery(status=closed,keywords~=firefox opera,count)]]
Number of closed tickets affecting Firefox or Opera: 33 [[TicketQuery(status=closed,keywords~=firefox|opera,count)]]
Number of tickets that affect Firefox or are closed and affect Opera: 33 [[TicketQuery(status=closed,keywords~=opera,or,keywords~=firefox,count)]]
Number of closed Firefox tickets that don't affect Opera: 0 [[TicketQuery(status=closed,keywords~=firefox -opera,count)]]
Last 3 modified tickets: #36727, #36145, #36750 [[TicketQuery(max=3,order=modified,desc=1,compact)]]

Details of ticket #1:

[[TicketQuery(id=1,col=id|owner|reporter,rows=summary,table)]]

Ticket Owner Reporter
#1 Jacob Adrian Holovaty
Summary Create architecture for anonymous sessions

Format: list

[[TicketQuery(version=0.6|0.7&resolution=duplicate)]]

This is displayed as:

No results

[[TicketQuery(id=123)]]

This is displayed as:

#123
Typo in the model_api/#field-types

Format: compact

[[TicketQuery(version=0.6|0.7&resolution=duplicate, compact)]]

This is displayed as:

No results

Format: count

[[TicketQuery(version=0.6|0.7&resolution=duplicate, count)]]

This is displayed as:

0

Format: progress

[[TicketQuery(milestone=0.12.8&group=type,format=progress)]]

This is displayed as:

Uncategorized

2028 / 2028

Bug

10427 / 10799

New feature

3822 / 4204

Cleanup/optimization

5407 / 5717

Format: table

You can choose the columns displayed in the table format (format=table) using col=<field>. You can specify multiple fields and the order they are displayed in by placing pipes (|) between the columns:

[[TicketQuery(max=3,status=closed,order=id,desc=1,format=table,col=resolution|summary|owner|reporter)]]

This is displayed as:

Full rows

In table format you can specify full rows using rows=<field>:

[[TicketQuery(max=3,status=closed,order=id,desc=1,format=table,col=resolution|summary|owner|reporter,rows=description)]]

This is displayed as:

Results (1 - 3 of 34899)

1 2 3 4 5 6 7 8 9 10 11
Ticket Resolution Summary Owner Reporter
#36749 wontfix No need of instructions to install requirements for tests Pravin Pravin
Description

https://docs.djangoproject.com/en/dev/intro/contributing/#running-django-s-test-suite-for-the-first-time Currently we have this: "Before running the test suite, enter the Django tests/ directory using the cd tests command, and install test dependencies by running" python -m pip install -r requirements/py3.txt

But this could be have been more clear and straightforward. instead telling user to enter into tests folder we could simply say: "Before running the test suite, install test dependencies by running:"" python -m pip install -r tests/requirements/py3.txt

This would be more clearer and straightforward.

#36748 fixed Postgres UNNEST optimisation of bulk_create cannot handle fields with `get_placeholder`. Chris Wesseling Chris Wesseling
Description

In order to allow fields to define a different placeholder than "%s" in https://github.com/django/django/blob/97acd4d2f92eef8c285bac070d437bf0fd52e071/django/db/models/sql/compiler.py#L1769 BaseSQLInsertCompiler.assemble_as_sql does:

        get_placeholders = [getattr(field, "get_placeholder", None) for field in fields]

and calls those functions with (value, compiler, connection) to generate the placeholders.

These alternative placeholders are not always UNNESTable. e.g. "%s::{}" for arrays and and ranges, which we tried to work-around by filtering

            # Fields that don't use standard internal types might not be
            # unnest'able (e.g. array and geometry types are known to be
            # problematic).
            or any(
                (field.target_field if field.is_relation else field).get_internal_type()
                not in self.connection.data_types
                for field in fields
            )

but more general since get_placeholder can be a function of value, we can't UNNEST forall fields, value_rows, as it breaks the "one placeholder fits all values" assumption.

Therefore if any field in fields has get_placeholder, we should fallback to the default, unoptimised implementation.

In fact the addition of

            # Field.get_placeholder takes value as an argument, therefore the
            # resulting placeholder might be dependent on the value.
            # in UNNEST requires a single placeholder to "fit all values" in 
            # the array.
            or any(hasattr(field, "get_placeholder") for field in fields)

before the mentioned internal_type filter that's already present, handles all cases in the test suite and never hits the internal_type case, because all test examples also have a get_placeholder. I don't know if this will always be the case, so I suggest keeping the present filter too.

I bumped into this regression when upgrading to 5.2 and the call to a Postgres extension function in such a placeholder, but which has a db_type that is present in self.connection.data_types, didn't happen anymore for bulk inserts.

NB This bug can go unnoticed: bulk_create might succeed, but with different data written to disk than what is expected. And subsequent reads and seeks will have the wrong results.

#36746 needsinfo IndexError in prep_address() when parsing invalid email addresses like 'to@' Mahdi Dehghan Mahdi Dehghan
Description

When parsing invalid email addresses (such as 'to@') in the SMTP backend's prep_address() method, Python's email parser raises an IndexError instead of the expected ValueError. This causes the test test_avoids_sending_to_invalid_addresses to fail.

Steps to reproduce:

  1. Run Django's test suite: ./runtests.py mail.tests.SMTPBackendTests.test_avoids_sending_to_invalid_addresses
  2. The test fails with IndexError when trying to parse 'to@'

Root cause: The prep_address() method at line 172 in django/core/mail/backends/smtp.py directly calls AddressHeader.value_parser(address) without exception handling. When parsing malformed addresses like 'to@', Python's email parser first raises HeaderParseError, then during exception handling attempts to parse the address differently, which leads to an IndexError when trying to access value[0] on an empty string.

Proposed solution: Wrap the AddressHeader.value_parser() call in a try-except block to catch HeaderParseError, IndexError, and ValueError exceptions, converting them to ValueError with an appropriate message. This matches the pattern already used in the deprecated sanitize_address() function in django/core/mail/message.py (line 115).

Expected behavior: The prep_address() method should catch parsing exceptions and raise ValueError with message "Invalid address" for invalid addresses, matching the test's expectation.

Actual behavior: IndexError: string index out of range is raised from Python's email._header_value_parser when parsing addresses like 'to@'.

Error traceback:

ERROR: test_avoids_sending_to_invalid_addresses (mail.tests.SMTPBackendTests.test_avoids_sending_to_invalid_addresses) [<object object at 0x12d0aff70>] (email_address='to@')
Verify invalid addresses can't sneak into SMTP commands through
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/email/_header_value_parser.py", line 1965, in get_address
    token, value = get_group(value)
    ^^^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/email/_header_value_parser.py", line 1923, in get_group
    raise errors.HeaderParseError("expected ':' at end of group "
    ^^^^^^^^^^^^^^^^^
email.errors.HeaderParseError: expected ':' at end of group display name but found '@'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/email/_header_value_parser.py", line 1791, in get_mailbox
    token, value = get_name_addr(value)
    ^^^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/email/_header_value_parser.py", line 1777, in get_name_addr
    token, value = get_angle_addr(value)
      ^^^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/email/_header_value_parser.py", line 1702, in get_angle_addr
    raise errors.HeaderParseError(
    ^^^^^^^^^^^^^^^^^
email.errors.HeaderParseError: expected angle-addr but found '@'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/unittest/case.py", line 58, in testPartExecutor
    yield
  File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/unittest/case.py", line 539, in subTest
    yield
  File "tests/mail/tests.py", line 3070, in test_avoids_sending_to_invalid_addresses
    backend.send_messages([email])
    ^^^^^^^^^^^^^^^^^
  File "django/core/mail/backends/smtp.py", line 138, in send_messages
    sent = self._send(message)
    ^^^^^^^^^^^^^^^^^
  File "django/core/mail/backends/smtp.py", line 151, in _send
    recipients = [self.prep_address(addr) for addr in email_message.recipients()]
    ^^^^^^^^^^^^^^^^^
  File "django/core/mail/backends/smtp.py", line 172, in prep_address
    parsed = AddressHeader.value_parser(address)
    ^^^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/email/headerregistry.py", line 333, in value_parser
    address_list, value = parser.get_address_list(value)
    ^^^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/email/_header_value_parser.py", line 1988, in get_address_list
    token, value = get_address(value)
    ^^^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/email/_header_value_parser.py", line 1968, in get_address
    token, value = get_mailbox(value)
    ^^^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/email/_header_value_parser.py", line 1794, in get_mailbox
    token, value = get_addr_spec(value)
    ^^^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/email/_header_value_parser.py", line 1647, in get_addr_spec
    token, value = get_domain(value[1:])
      ^^^^^^^^^^^^^^^^^
  File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/email/_header_value_parser.py", line 1604, in get_domain
    if value[0] in CFWS_LEADER:
      ^^^^^^^^^^^^^^^^^
IndexError: string index out of range
1 2 3 4 5 6 7 8 9 10 11


See also: TracQuery, TracTickets, TracReports

Last modified 22 months ago Last modified on Jan 24, 2024, 9:58:09 AM
Note: See TracWiki for help on using the wiki.
Back to Top