New Upstream Release - flake8-comprehensions

Ready changes

Summary

Merged new upstream version: 3.12.0 (was: 3.10.1).

Resulting package

Built on 2023-06-06T04:15 (took 6m52s)

The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:

apt install -t fresh-releases python3-flake8-comprehensions

Lintian Result

Diff

diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 4afa269..046ab3a 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -36,7 +36,7 @@ jobs:
     - name: Install dependencies
       run: |
         python -m pip install --upgrade pip setuptools wheel
-        python -m pip install --upgrade tox tox-py
+        python -m pip install --upgrade 'tox>=4.0.0rc3'
 
     - name: Run tox targets for ${{ matrix.python-version }}
-      run: tox --py current
+      run: tox run -f py$(echo ${{ matrix.python-version }} | tr -d .)
diff --git a/.gitignore b/.gitignore
index 36994f8..93acb63 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,60 +1,7 @@
-# Byte-compiled / optimized / DLL files
-__pycache__/
-*.py[cod]
-*$py.class
-
-# C extensions
-*.so
-
-# Distribution / packaging
-.Python
-env/
-build/
-develop-eggs/
-dist/
-downloads/
-eggs/
-.eggs/
-lib/
-lib64/
-parts/
-sdist/
-var/
 *.egg-info/
-.installed.cfg
-*.egg
-
-# PyInstaller
-#  Usually these files are written by a python script from a template
-#  before PyInstaller builds the exe, so as to inject date/other infos into it.
-*.manifest
-*.spec
-
-# Installer logs
-pip-log.txt
-pip-delete-this-directory.txt
-
-# Unit test / coverage reports
-htmlcov/
-.tox/
-.coverage
-.coverage.*
-.cache
-nosetests.xml
-coverage.xml
-*,cover
-.hypothesis/
-.pytest_cache
-
-# Translations
-*.mo
-*.pot
-
-# Django stuff:
-*.log
-
-# Sphinx documentation
-docs/_build/
-
-# PyBuilder
-target/
+*.pyc
+/.coverage
+/.coverage.*
+/.tox
+/build/
+/dist/
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index fbf0fc3..51a9121 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,9 +1,9 @@
 default_language_version:
-  python: python3.10
+  python: python3.11
 
 repos:
 - repo: https://github.com/pre-commit/pre-commit-hooks
-  rev: v4.3.0
+  rev: v4.4.0
   hooks:
   - id: check-added-large-files
   - id: check-case-conflict
@@ -13,27 +13,53 @@ repos:
   - id: check-toml
   - id: end-of-file-fixer
   - id: trailing-whitespace
+- repo: https://github.com/tox-dev/pyproject-fmt
+  rev: 0.9.2
+  hooks:
+  - id: pyproject-fmt
+- repo: https://github.com/asottile/setup-cfg-fmt
+  rev: v2.2.0
+  hooks:
+  - id: setup-cfg-fmt
+    args:
+    - --include-version-classifiers
+- repo: https://github.com/tox-dev/tox-ini-fmt
+  rev: 1.3.0
+  hooks:
+  - id: tox-ini-fmt
+- repo: https://github.com/rstcheck/rstcheck
+  rev: v6.1.2
+  hooks:
+  - id: rstcheck
+    additional_dependencies:
+    - tomli==2.0.1
 - repo: https://github.com/asottile/pyupgrade
-  rev: v3.1.0
+  rev: v3.3.1
   hooks:
   - id: pyupgrade
     args: [--py37-plus]
 - repo: https://github.com/psf/black
-  rev: 22.10.0
+  rev: 23.3.0
   hooks:
   - id: black
-- repo: https://github.com/asottile/blacken-docs
-  rev: v1.12.1
+- repo: https://github.com/adamchainz/blacken-docs
+  rev: 1.13.0
   hooks:
   - id: blacken-docs
     additional_dependencies:
-    - black==22.1.0
-- repo: https://github.com/pycqa/isort
-  rev: 5.10.1
+    - black==23.1.0
+- repo: https://github.com/asottile/reorder_python_imports
+  rev: v3.9.0
   hooks:
-  - id: isort
+  - id: reorder-python-imports
+    args:
+    - --py37-plus
+    - --application-directories
+    - .:example:src
+    - --add-import
+    - 'from __future__ import annotations'
 - repo: https://github.com/PyCQA/flake8
-  rev: 5.0.4
+  rev: 6.0.0
   hooks:
   - id: flake8
     additional_dependencies:
@@ -42,6 +68,6 @@ repos:
     - flake8-tidy-imports
     - flake8-typing-imports
 - repo: https://github.com/pre-commit/mirrors-mypy
-  rev: v0.982
+  rev: v1.2.0
   hooks:
   - id: mypy
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
new file mode 100644
index 0000000..52f0a20
--- /dev/null
+++ b/CHANGELOG.rst
@@ -0,0 +1,268 @@
+=========
+Changelog
+=========
+
+3.12.0 (2023-04-13)
+-------------------
+
+* Add rule C418 to check for calls passing a dict literal or dict comprehension to ``dict()``.
+
+* Add rule C419 to check for calls passing a list comprehension to ``any()``/``all()``.
+
+3.11.1 (2023-03-21)
+-------------------
+
+* Fix false positives in C406 “unnecessary dict literal”.
+
+  Fixes `Issue #260 <https://github.com/adamchainz/flake8-comprehensions/issues/260>`__.
+
+3.11.0 (2023-03-18)
+-------------------
+
+* Expand C416 to ``dict`` comprehensions.
+
+  Thanks to Aaron Gokaslan in `PR #490 <https://github.com/adamchainz/flake8-comprehensions/pull/490>`__.
+
+3.10.1 (2022-10-29)
+-------------------
+
+* Fix false positive in rules C402 and C404 for ``dict()`` calls with keyword arguments.
+
+  Thanks to Anders Kaseorg for the report in `Issue #457 <https://github.com/adamchainz/flake8-comprehensions/issues/457>`__.
+
+3.10.0 (2022-05-19)
+-------------------
+
+* Add rule C417 which recommends rewriting use of ``map()`` with ``lambda`` to an equivalent generator expression or comprehension.
+
+  Thanks to Tushar Sadhwani in `PR #409 <https://github.com/adamchainz/flake8-comprehensions/pull/409>`__.
+
+3.9.0 (2022-05-11)
+------------------
+
+* Support Python 3.11.
+
+3.8.0 (2022-01-10)
+------------------
+
+* Drop Python 3.6 support.
+
+* Remove upper bound on Flake8 version.
+
+3.7.0 (2021-10-11)
+------------------
+
+* Support Flake8 4.
+
+3.6.1 (2021-08-16)
+------------------
+
+* Fix type hint for ``tree`` argument.
+
+  Thanks to kasium for the report in `Issue #352
+  <https://github.com/adamchainz/flake8-comprehensions/issues/352>`__.
+
+3.6.0 (2021-08-13)
+------------------
+
+* Add type hints.
+
+3.5.0 (2021-05-10)
+------------------
+
+* Support Python 3.10.
+
+* Stop distributing tests to reduce package size. Tests are not intended to be
+  run outside of the tox setup in the repository. Repackagers can use GitHub's
+  tarballs per tag.
+
+3.4.0 (2021-03-18)
+------------------
+
+* Remove rules C407 (Unnecessary ``<dict/list>`` comprehension - ``<builtin>``
+  can take a generator) and C412 (Unnecessary ``<dict/list/set>`` comprehension
+  - 'in' can take a generator). Both rules recommended increasing laziness,
+  which is not always desirable and can lead to subtle bugs. Also, a fully
+  exhausted generator is slower than an equivalent comprehension, so the advice
+  did not always improve performance.
+
+  Thanks to David Smith, Dylan Young, and Leonidas Loucas for the report in
+  `Issue #247
+  <https://github.com/adamchainz/flake8-comprehensions/issues/247>`__.
+
+3.3.1 (2020-12-19)
+------------------
+
+* Drop Python 3.5 support.
+* Improved installation instructions in README.
+
+3.3.0 (2020-10-23)
+------------------
+
+* Support Python 3.9.
+* Move license from ISC to MIT License.
+* Partially reverted the change to ``C408`` to make it apply again to when
+  ``dict`` is called with keyword arguments, e.g. ``dict(a=1, b=2)`` will be
+  flagged to be rewritten in the literal form ``{"a": 1, "b": 2}``
+
+3.2.3 (2020-06-06)
+------------------
+
+* Made ``C408`` only apply when no arguments are passed to
+  ``dict``/``list``/``tuple``.
+
+3.2.2 (2020-01-20)
+------------------
+
+* Remove check for dict comprehensions in rule C407 as it would also change the
+  results for certain builtins such as ``sum()``.
+
+3.2.1 (2020-01-20)
+------------------
+
+* Remove check for set comprehensions in rule C407 as it would change the
+  results for certain builtins such as ``sum()``.
+
+3.2.0 (2020-01-20)
+------------------
+
+* Add ``filter`` and ``map`` to rule C407.
+* Check for dict and set comprehensions in rules C407 and C412.
+
+3.1.4 (2019-11-20)
+------------------
+
+* Remove the tuple/unpacking check from C416 to prevent false positives where
+  the type of the iterable is changed from some iterable to a tuple.
+
+3.1.3 (2019-11-19)
+------------------
+
+* Ensure the fix for false positives in ``C416`` rule for asynchronous
+  comprehensions runs on Python 3.6 too.
+
+3.1.2 (2019-11-18)
+------------------
+
+* Fix false positives in ``C416`` rule for list comprehensions returning
+  tuples.
+
+3.1.1 (2019-11-16)
+------------------
+
+* Fix false positives in ``C416`` rule for asynchronous comprehensions.
+
+3.1.0 (2019-11-15)
+------------------
+
+* Update Python support to 3.5-3.8.
+* Fix false positives for C404 for list comprehensions not directly creating
+  tuples.
+* Add ``C413`` rule that checks for unnecessary use of ``list()`` or
+  ``reversed()`` around ``sorted()``.
+* Add ``C414`` rule that checks for unnecessary use of the following:
+    * ``list()``, ``reversed()``, ``sorted()``, or ``tuple()``  within ``set``
+      or ``sorted()``
+    * ``list()`` or ``tuple()``  within ``list()`` or ``tuple()``
+    * ``set()``  within ``set``
+* Add ``C415`` rule that checks for unnecessary reversal of an iterable via
+  subscript within ``reversed()``, ``set()``, or ``sorted()``.
+* Add ``C416`` rule that checks for unnecessary list or set comprehensions that
+  can be rewritten using ``list()`` or ``set()``.
+
+3.0.1 (2019-10-28)
+------------------
+
+* Fix version display on ``flake8 --version`` (removing dependency on
+  ``cached-property``). Thanks to Jon Dufresne.
+
+3.0.0 (2019-10-25)
+------------------
+
+* Update Flake8 support to 3.0+ only. 3.0.0 was released in 2016 and the plugin
+  hasn't been tested with it since.
+
+2.3.0 (2019-10-25)
+------------------
+
+* Converted setuptools metadata to configuration file. This meant removing the
+  ``__version__`` attribute from the package. If you want to inspect the
+  installed version, use
+  ``importlib.metadata.version("flake8-comprehensions")``
+  (`docs <https://docs.python.org/3.8/library/importlib.metadata.html#distribution-versions>`__ /
+  `backport <https://pypi.org/project/importlib-metadata/>`__).
+* Add dependencies on ``cached-property`` and ``importlib-metadata``.
+* Fix false negatives in ``C407`` for cases when ``enumerate`` and ``sum()``
+  are passed more than one argument.
+
+2.2.0 (2019-08-12)
+------------------
+
+* Update Python support to 3.5-3.7, as 3.4 has reached its end of life.
+* ``C412`` rule that complains about using list comprehension with ``in``.
+
+2.1.0 (2019-03-01)
+------------------
+
+* Add missing builtin ``enumerate`` to ``C407``.
+
+2.0.0 (2019-02-02)
+------------------
+
+* Drop Python 2 support, only Python 3.4+ is supported now.
+
+1.4.1 (2017-05-17)
+------------------
+
+* Fix false positives in ``C408`` for calls using ``*args`` or ``**kwargs``.
+
+1.4.0 (2017-05-14)
+------------------
+
+* Plugin now reserves the full ``C4XX`` code space rather than just ``C40X``
+* ``C408`` rule that complains about using ``tuple()``, ``list()``, or
+  ``dict()`` instead of a literal.
+* ``C409`` and ``C410`` rules that complain about an unnecessary list or tuple
+  that could be rewritten as a literal.
+* ``C411`` rule that complains about using list comprehension inside a
+  ``list()`` call.
+
+1.3.0 (2017-05-01)
+------------------
+
+* Don't allow installation with Flake8 3.2.0 which doesn't enable the plugin.
+  This bug was fixed in Flake8 3.2.1.
+* Prevent false positives of ``C402`` from generators of expressions that
+  aren't two-tuples.
+* ``C405`` and ``C406`` now also complain about unnecessary tuple literals.
+
+1.2.1 (2016-06-27)
+------------------
+
+* ``C407`` rule that complains about unnecessary list comprehensions inside
+  builtins that can work on generators.
+
+1.2.0 (2016-07-11)
+------------------
+
+* Split all rule codes by type. This allows granular selection of the rules in
+  flake8 configuration.
+
+1.1.1 (2016-04-06)
+------------------
+
+* Fix crash on method calls
+
+1.1.0 (2016-04-06)
+------------------
+
+* ``C401`` rule that complains about unnecessary list comprehensions inside
+  calls to ``set()`` or ``dict()``.
+* ``C402`` rule that complains about unnecessary list literals inside calls to
+  ``set()`` or ``dict()``.
+
+1.0.0 (2016-04-05)
+------------------
+
+* ``C400`` rule that complains about an unnecessary usage of a generator when a
+  list/set/dict comprehension would do.
diff --git a/HISTORY.rst b/HISTORY.rst
index 509740b..27beaea 100644
--- a/HISTORY.rst
+++ b/HISTORY.rst
@@ -1,247 +1 @@
-=======
-History
-=======
-
-3.10.1 (2022-10-29)
--------------------
-
-* Fix false positive in rules C402 and C404 for ``dict()`` calls with keyword arguments.
-
-  Thanks to Anders Kaseorg for the report in `Issue #457 <https://github.com/adamchainz/flake8-comprehensions/issues/457>`__.
-
-3.10.0 (2022-05-19)
--------------------
-
-* Add rule C417 which recommends rewriting use of ``map()`` with ``lambda`` to an equivalent generator expression or comprehension.
-
-  Thanks to Tushar Sadhwani in `PR #409 <https://github.com/adamchainz/flake8-comprehensions/pull/409>`__.
-
-3.9.0 (2022-05-11)
-------------------
-
-* Support Python 3.11.
-
-3.8.0 (2022-01-10)
-------------------
-
-* Drop Python 3.6 support.
-
-* Remove upper bound on Flake8 version.
-
-3.7.0 (2021-10-11)
-------------------
-
-* Support Flake8 4.
-
-3.6.1 (2021-08-16)
-------------------
-
-* Fix type hint for ``tree`` argument.
-
-  Thanks to kasium for the report in `Issue #352
-  <https://github.com/adamchainz/flake8-comprehensions/issues/352>`__.
-
-3.6.0 (2021-08-13)
-------------------
-
-* Add type hints.
-
-3.5.0 (2021-05-10)
-------------------
-
-* Support Python 3.10.
-
-* Stop distributing tests to reduce package size. Tests are not intended to be
-  run outside of the tox setup in the repository. Repackagers can use GitHub's
-  tarballs per tag.
-
-3.4.0 (2021-03-18)
-------------------
-
-* Remove rules C407 (Unnecessary ``<dict/list>`` comprehension - ``<builtin>``
-  can take a generator) and C412 (Unnecessary ``<dict/list/set>`` comprehension
-  - 'in' can take a generator). Both rules recommended increasing laziness,
-  which is not always desirable and can lead to subtle bugs. Also, a fully
-  exhausted generator is slower than an equivalent comprehension, so the advice
-  did not always improve performance.
-
-  Thanks to David Smith, Dylan Young, and Leonidas Loucas for the report in
-  `Issue #247
-  <https://github.com/adamchainz/flake8-comprehensions/issues/247>`__.
-
-3.3.1 (2020-12-19)
-------------------
-
-* Drop Python 3.5 support.
-* Improved installation instructions in README.
-
-3.3.0 (2020-10-23)
-------------------
-
-* Support Python 3.9.
-* Move license from ISC to MIT License.
-* Partially reverted the change to ``C408`` to make it apply again to when
-  ``dict`` is called with keyword arguments, e.g. ``dict(a=1, b=2)`` will be
-  flagged to be rewritten in the literal form ``{"a": 1, "b": 2}``
-
-3.2.3 (2020-06-06)
-------------------
-
-* Made ``C408`` only apply when no arguments are passed to
-  ``dict``/``list``/``tuple``.
-
-3.2.2 (2020-01-20)
-------------------
-
-* Remove check for dict comprehensions in rule C407 as it would also change the
-  results for certain builtins such as ``sum()``.
-
-3.2.1 (2020-01-20)
-------------------
-
-* Remove check for set comprehensions in rule C407 as it would change the
-  results for certain builtins such as ``sum()``.
-
-3.2.0 (2020-01-20)
-------------------
-
-* Add ``filter`` and ``map`` to rule C407.
-* Check for dict and set comprehensions in rules C407 and C412.
-
-3.1.4 (2019-11-20)
-------------------
-
-* Remove the tuple/unpacking check from C416 to prevent false positives where
-  the type of the iterable is changed from some iterable to a tuple.
-
-3.1.3 (2019-11-19)
-------------------
-
-* Ensure the fix for false positives in ``C416`` rule for asynchronous
-  comprehensions runs on Python 3.6 too.
-
-3.1.2 (2019-11-18)
-------------------
-
-* Fix false positives in ``C416`` rule for list comprehensions returning
-  tuples.
-
-3.1.1 (2019-11-16)
-------------------
-
-* Fix false positives in ``C416`` rule for asynchronous comprehensions.
-
-3.1.0 (2019-11-15)
-------------------
-
-* Update Python support to 3.5-3.8.
-* Fix false positives for C404 for list comprehensions not directly creating
-  tuples.
-* Add ``C413`` rule that checks for unnecessary use of ``list()`` or
-  ``reversed()`` around ``sorted()``.
-* Add ``C414`` rule that checks for unnecessary use of the following:
-    * ``list()``, ``reversed()``, ``sorted()``, or ``tuple()``  within ``set``
-      or ``sorted()``
-    * ``list()`` or ``tuple()``  within ``list()`` or ``tuple()``
-    * ``set()``  within ``set``
-* Add ``C415`` rule that checks for unnecessary reversal of an iterable via
-  subscript within ``reversed()``, ``set()``, or ``sorted()``.
-* Add ``C416`` rule that checks for unnecessary list or set comprehensions that
-  can be rewritten using ``list()`` or ``set()``.
-
-3.0.1 (2019-10-28)
-------------------
-
-* Fix version display on ``flake8 --version`` (removing dependency on
-  ``cached-property``). Thanks to Jon Dufresne.
-
-3.0.0 (2019-10-25)
-------------------
-
-* Update Flake8 support to 3.0+ only. 3.0.0 was released in 2016 and the plugin
-  hasn't been tested with it since.
-
-2.3.0 (2019-10-25)
-------------------
-
-* Converted setuptools metadata to configuration file. This meant removing the
-  ``__version__`` attribute from the package. If you want to inspect the
-  installed version, use
-  ``importlib.metadata.version("flake8-comprehensions")``
-  (`docs <https://docs.python.org/3.8/library/importlib.metadata.html#distribution-versions>`__ /
-  `backport <https://pypi.org/project/importlib-metadata/>`__).
-* Add dependencies on ``cached-property`` and ``importlib-metadata``.
-* Fix false negatives in ``C407`` for cases when ``enumerate`` and ``sum()``
-  are passed more than one argument.
-
-2.2.0 (2019-08-12)
-------------------
-
-* Update Python support to 3.5-3.7, as 3.4 has reached its end of life.
-* ``C412`` rule that complains about using list comprehension with ``in``.
-
-2.1.0 (2019-03-01)
-------------------
-
-* Add missing builtin ``enumerate`` to ``C407``.
-
-2.0.0 (2019-02-02)
-------------------
-
-* Drop Python 2 support, only Python 3.4+ is supported now.
-
-1.4.1 (2017-05-17)
-------------------
-
-* Fix false positives in ``C408`` for calls using ``*args`` or ``**kwargs``.
-
-1.4.0 (2017-05-14)
-------------------
-
-* Plugin now reserves the full ``C4XX`` code space rather than just ``C40X``
-* ``C408`` rule that complains about using ``tuple()``, ``list()``, or
-  ``dict()`` instead of a literal.
-* ``C409`` and ``C410`` rules that complain about an unnecessary list or tuple
-  that could be rewritten as a literal.
-* ``C411`` rule that complains about using list comprehension inside a
-  ``list()`` call.
-
-1.3.0 (2017-05-01)
-------------------
-
-* Don't allow installation with Flake8 3.2.0 which doesn't enable the plugin.
-  This bug was fixed in Flake8 3.2.1.
-* Prevent false positives of ``C402`` from generators of expressions that
-  aren't two-tuples.
-* ``C405`` and ``C406`` now also complain about unnecessary tuple literals.
-
-1.2.1 (2016-06-27)
-------------------
-
-* ``C407`` rule that complains about unnecessary list comprehensions inside
-  builtins that can work on generators.
-
-1.2.0 (2016-07-11)
-------------------
-
-* Split all rule codes by type. This allows granular selection of the rules in
-  flake8 configuration.
-
-1.1.1 (2016-04-06)
-------------------
-
-* Fix crash on method calls
-
-1.1.0 (2016-04-06)
-------------------
-
-* ``C401`` rule that complains about unnecessary list comprehensions inside
-  calls to ``set()`` or ``dict()``.
-* ``C402`` rule that complains about unnecessary list literals inside calls to
-  ``set()`` or ``dict()``.
-
-1.0.0 (2016-04-05)
-------------------
-
-* ``C400`` rule that complains about an unnecessary usage of a generator when a
-  list/set/dict comprehension would do.
+See https://github.com/adamchainz/flake8-comprehensions/blob/main/CHANGELOG.rst
diff --git a/MANIFEST.in b/MANIFEST.in
index 4556868..f7ed108 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,4 +1,4 @@
-include HISTORY.rst
+include CHANGELOG.rst
 include LICENSE
 include pyproject.toml
 include README.rst
diff --git a/README.rst b/README.rst
index cb34478..51d1970 100644
--- a/README.rst
+++ b/README.rst
@@ -2,7 +2,7 @@
 flake8-comprehensions
 =====================
 
-.. image:: https://img.shields.io/github/workflow/status/adamchainz/flake8-comprehensions/CI/main?style=for-the-badge
+.. image:: https://img.shields.io/github/actions/workflow/status/adamchainz/flake8-comprehensions/main.yml?branch=main&style=for-the-badge
    :target: https://github.com/adamchainz/flake8-comprehensions/actions?workflow=CI
 
 .. image:: https://img.shields.io/pypi/v/flake8-comprehensions.svg?style=for-the-badge
@@ -47,6 +47,12 @@ Rules
 C400-402: Unnecessary generator - rewrite as a ``<list/set/dict>`` comprehension.
 ---------------------------------------------------------------------------------
 
+Rules:
+
+* C400 Unnecessary generator - rewrite as a list comprehension.
+* C401 Unnecessary generator - rewrite as a set comprehension.
+* C402 Unnecessary generator - rewrite as a dict comprehension.
+
 It's unnecessary to use ``list``, ``set``, or ``dict`` around a generator expression, since there are equivalent comprehensions for these types.
 For example:
 
@@ -57,6 +63,11 @@ For example:
 C403-404: Unnecessary list comprehension - rewrite as a ``<set/dict>`` comprehension.
 -------------------------------------------------------------------------------------
 
+Rules:
+
+* C403 Unnecessary list comprehension - rewrite as a set comprehension.
+* C404 Unnecessary list comprehension - rewrite as a dict comprehension.
+
 It's unnecessary to use a list comprehension inside a call to ``set`` or ``dict``, since there are equivalent comprehensions for these types.
 For example:
 
@@ -66,6 +77,9 @@ For example:
 C405-406: Unnecessary ``<list/tuple>`` literal - rewrite as a ``<set/dict>`` literal.
 -------------------------------------------------------------------------------------
 
+* C405 Unnecessary ``<list/tuple>`` literal - rewrite as a set literal.
+* C406 Unnecessary ``<list/tuple>`` literal - rewrite as a dict literal.
+
 It's unnecessary to use a list or tuple literal within a call to ``set`` or ``dict``.
 For example:
 
@@ -76,6 +90,11 @@ For example:
 * Rewrite ``dict(((1, 2),))`` as ``{1: 2}``
 * Rewrite ``dict([])`` as ``{}``
 
+C407: Unnecessary ``<dict/list>`` comprehension - ``<builtin>`` can take a generator
+------------------------------------------------------------------------------------
+
+This rule was dropped in version 3.4.0, because it promoted an increase in laziness which could lead to bugs.
+
 C408: Unnecessary ``<dict/list/tuple>`` call - rewrite as a literal.
 --------------------------------------------------------------------
 
@@ -88,8 +107,18 @@ For example:
 * Rewrite ``list()`` as ``[]``
 * Rewrite ``tuple()`` as ``()``
 
-C409-410: Unnecessary ``<list/tuple>`` passed to ``<list/tuple>``\() - (remove the outer call to ``<list/tuple>``()/rewrite as a ``<list/tuple>`` literal).
------------------------------------------------------------------------------------------------------------------------------------------------------------
+C409-410: Unnecessary ``<list/tuple>`` passed to ``<list/tuple>``\() - ``<advice>``.
+------------------------------------------------------------------------------------
+
+Rules:
+
+* C409 Unnecessary ``<list/tuple>`` passed to tuple() - ``<advice>``.
+* C410 Unnecessary list passed to list() - ``<advice>``.
+
+Where ``<advice>`` is either:
+
+* remove the outer call to ``<list/tuple>``\()
+* rewrite as a ``<list/tuple>`` literal
 
 It's unnecessary to use a list or tuple literal within a call to ``list`` or ``tuple``, since there is literal syntax for these types.
 For example:
@@ -109,6 +138,11 @@ For example:
 
 * Rewrite ``list([f(x) for x in foo])`` as ``[f(x) for x in foo]``
 
+C412: Unnecessary ``<dict/list/set>`` comprehension - 'in' can take a generator.
+--------------------------------------------------------------------------------
+
+This rule was dropped in version 3.4.0, because it promoted an increase in laziness which could lead to bugs.
+
 C413: Unnecessary ``<list/reversed>`` call around sorted().
 -----------------------------------------------------------
 
@@ -150,13 +184,14 @@ For example:
 * Rewrite ``sorted(iterable)[::-1]`` as ``sorted(iterable, reverse=True)``
 * Rewrite ``reversed(iterable[::-1])`` as ``iterable``
 
-C416: Unnecessary ``<list/set>`` comprehension - rewrite using ``<list/set>``\().
----------------------------------------------------------------------------------
+C416: Unnecessary ``<dict/list/set>`` comprehension - rewrite using ``<dict/list/set>``\().
+-------------------------------------------------------------------------------------------
 
-It's unnecessary to use a list comprehension if the elements are unchanged.
-The iterable should be wrapped in ``list()`` or ``set()`` instead.
+It's unnecessary to use a dict/list/set comprehension to build a data structure if the elements are unchanged.
+Wrap the iterable with ``dict()``, ``list()``, or ``set()`` instead.
 For example:
 
+* Rewrite ``{a: b for a, b in iterable}`` as ``dict(iterable)``
 * Rewrite ``[x for x in iterable]`` as ``list(iterable)``
 * Rewrite ``{x for x in iterable}`` as ``set(iterable)``
 
@@ -172,3 +207,23 @@ For example:
 * Rewrite ``list(map(lambda num: num * 2, nums))`` to ``[num * 2 for num in nums]``
 * Rewrite ``set(map(lambda num: num % 2 == 0, nums))`` to ``{num % 2 == 0 for num in nums}``
 * Rewrite ``dict(map(lambda v: (v, v ** 2), values))`` to ``{v : v ** 2 for v in values}``
+
+C418: Unnecessary ``<dict/dict comprehension>`` passed to dict() - remove the outer call to dict()
+--------------------------------------------------------------------------------------------------
+
+It's unnecessary to use a ``dict`` around a dict literal or dict comprehension, since either syntax already constructs a dict.
+For example:
+
+* Rewrite ``dict({})`` as ``{}``
+* Rewrite ``dict({"a": 1})`` as ``{"a": 1}``
+
+C419 Unnecessary list comprehension in ``<any/all>``\() prevents short-circuiting - rewrite as a generator.
+-----------------------------------------------------------------------------------------------------------
+
+Using a list comprehension inside a call to ``any()``/``all()`` prevents short-circuiting when a ``True`` / ``False`` value is found.
+The whole list will be constructed before calling ``any()``/``all()``, potentially wasting work.part-way.
+Rewrite to use a generator expression, which can stop part way.
+For example:
+
+* Rewrite ``all([condition(x) for x in iterable])`` as ``all(condition(x) for x in iterable)``
+* Rewrite ``any([condition(x) for x in iterable])`` as ``any(condition(x) for x in iterable)``
diff --git a/debian/changelog b/debian/changelog
index 80a6c16..eca5df6 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+flake8-comprehensions (3.12.0-1) UNRELEASED; urgency=low
+
+  * New upstream release.
+
+ -- Debian Janitor <janitor@jelmer.uk>  Tue, 06 Jun 2023 04:08:42 -0000
+
 flake8-comprehensions (3.10.1-2) unstable; urgency=medium
 
   * Team upload.
diff --git a/pyproject.toml b/pyproject.toml
index c9f9f88..f15f73a 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,16 +1,21 @@
 [build-system]
-requires = ["setuptools"]
 build-backend = "setuptools.build_meta"
+requires = [
+  "setuptools",
+]
 
 [tool.black]
 target-version = ['py37']
 
-[tool.isort]
-profile = "black"
-add_imports = "from __future__ import annotations"
+[tool.pytest.ini_options]
+addopts = """\
+    --strict-config
+    --strict-markers
+    """
 
 [tool.mypy]
 mypy_path = "src/"
+namespace_packages = false
 show_error_codes = true
 strict = true
 warn_unreachable = true
@@ -19,8 +24,5 @@ warn_unreachable = true
 module = "tests.*"
 allow_untyped_defs = true
 
-[tool.pytest.ini_options]
-addopts = """\
-    --strict-config
-    --strict-markers
-    """
+[tool.rstcheck]
+report_level = "ERROR"
diff --git a/requirements/py310.txt b/requirements/py310.txt
index 2373b34..bb7c4b1 100644
--- a/requirements/py310.txt
+++ b/requirements/py310.txt
@@ -1,52 +1,48 @@
 #
-# This file is autogenerated by pip-compile with python 3.10
-# To update, run:
+# This file is autogenerated by pip-compile with Python 3.10
+# by the following command:
 #
 #    requirements/compile.py
 #
-attrs==22.1.0 \
-    --hash=sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6 \
-    --hash=sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c
+attrs==22.2.0 \
+    --hash=sha256:29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836 \
+    --hash=sha256:c9227bfc2f01993c03f68db37d1d15c9690188323c067c641f1a35ca58185f99
     # via pytest
-flake8==5.0.4 \
-    --hash=sha256:6fbe320aad8d6b95cec8b8e47bc933004678dc63095be98528b7bdd2a9f510db \
-    --hash=sha256:7a1cf6b73744f5806ab95e526f6f0d8c01c66d7bbe349562d22dfca20610b248
+exceptiongroup==1.1.1 \
+    --hash=sha256:232c37c63e4f682982c8b6459f33a8981039e5fb8756b2074364e5055c498c9e \
+    --hash=sha256:d484c3090ba2889ae2928419117447a14daf3c1231d5e30d0aae34f354f01785
+    # via pytest
+flake8==6.0.0 \
+    --hash=sha256:3833794e27ff64ea4e9cf5d410082a8b97ff1a06c16aa3d2027339cd0f1195c7 \
+    --hash=sha256:c61007e76655af75e6785a931f452915b371dc48f56efd765247c8fe68f2b181
     # via pytest-flake8-path
-iniconfig==1.1.1 \
-    --hash=sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3 \
-    --hash=sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32
+iniconfig==2.0.0 \
+    --hash=sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3 \
+    --hash=sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374
     # via pytest
 mccabe==0.7.0 \
     --hash=sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325 \
     --hash=sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e
     # via flake8
-packaging==21.3 \
-    --hash=sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb \
-    --hash=sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522
+packaging==23.0 \
+    --hash=sha256:714ac14496c3e68c99c29b00845f7a2b85f3bb6f1078fd9f72fd20f0570002b2 \
+    --hash=sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97
     # via pytest
 pluggy==1.0.0 \
     --hash=sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159 \
     --hash=sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3
     # via pytest
-py==1.11.0 \
-    --hash=sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719 \
-    --hash=sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378
-    # via pytest
-pycodestyle==2.9.1 \
-    --hash=sha256:2c9607871d58c76354b697b42f5d57e1ada7d261c261efac224b664affdc5785 \
-    --hash=sha256:d1735fc58b418fd7c5f658d28d943854f8a849b01a5d0a1e6f3f3fdd0166804b
+pycodestyle==2.10.0 \
+    --hash=sha256:347187bdb476329d98f695c213d7295a846d1152ff4fe9bacb8a9590b8ee7053 \
+    --hash=sha256:8a4eaf0d0495c7395bdab3589ac2db602797d76207242c17d470186815706610
     # via flake8
-pyflakes==2.5.0 \
-    --hash=sha256:4579f67d887f804e67edb544428f264b7b24f435b263c4614f384135cea553d2 \
-    --hash=sha256:491feb020dca48ccc562a8c0cbe8df07ee13078df59813b83959cbdada312ea3
+pyflakes==3.0.1 \
+    --hash=sha256:ec55bf7fe21fff7f1ad2f7da62363d749e2a470500eab1b555334b67aa1ef8cf \
+    --hash=sha256:ec8b276a6b60bd80defed25add7e439881c19e64850afd9b346283d4165fd0fd
     # via flake8
-pyparsing==3.0.9 \
-    --hash=sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb \
-    --hash=sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc
-    # via packaging
-pytest==7.1.3 \
-    --hash=sha256:1377bda3466d70b55e3f5cecfa55bb7cfcf219c7964629b967c37cf0bda818b7 \
-    --hash=sha256:4f365fec2dff9c1162f834d9f18af1ba13062db0c708bf7b946f8a5c76180c39
+pytest==7.2.2 \
+    --hash=sha256:130328f552dcfac0b1cec75c12e3f005619dc5f874f0a06e8ff7263f0ee6225e \
+    --hash=sha256:c99ab0c73aceb050f68929bc93af19ab6db0558791c6a0715723abe9d0ade9d4
     # via
     #   -r requirements.in
     #   pytest-flake8-path
diff --git a/requirements/py311.txt b/requirements/py311.txt
index a707301..afc43ca 100644
--- a/requirements/py311.txt
+++ b/requirements/py311.txt
@@ -1,52 +1,44 @@
 #
-# This file is autogenerated by pip-compile with python 3.11
-# To update, run:
+# This file is autogenerated by pip-compile with Python 3.11
+# by the following command:
 #
 #    requirements/compile.py
 #
-attrs==22.1.0 \
-    --hash=sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6 \
-    --hash=sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c
+attrs==22.2.0 \
+    --hash=sha256:29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836 \
+    --hash=sha256:c9227bfc2f01993c03f68db37d1d15c9690188323c067c641f1a35ca58185f99
     # via pytest
-flake8==5.0.4 \
-    --hash=sha256:6fbe320aad8d6b95cec8b8e47bc933004678dc63095be98528b7bdd2a9f510db \
-    --hash=sha256:7a1cf6b73744f5806ab95e526f6f0d8c01c66d7bbe349562d22dfca20610b248
+flake8==6.0.0 \
+    --hash=sha256:3833794e27ff64ea4e9cf5d410082a8b97ff1a06c16aa3d2027339cd0f1195c7 \
+    --hash=sha256:c61007e76655af75e6785a931f452915b371dc48f56efd765247c8fe68f2b181
     # via pytest-flake8-path
-iniconfig==1.1.1 \
-    --hash=sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3 \
-    --hash=sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32
+iniconfig==2.0.0 \
+    --hash=sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3 \
+    --hash=sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374
     # via pytest
 mccabe==0.7.0 \
     --hash=sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325 \
     --hash=sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e
     # via flake8
-packaging==21.3 \
-    --hash=sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb \
-    --hash=sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522
+packaging==23.0 \
+    --hash=sha256:714ac14496c3e68c99c29b00845f7a2b85f3bb6f1078fd9f72fd20f0570002b2 \
+    --hash=sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97
     # via pytest
 pluggy==1.0.0 \
     --hash=sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159 \
     --hash=sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3
     # via pytest
-py==1.11.0 \
-    --hash=sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719 \
-    --hash=sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378
-    # via pytest
-pycodestyle==2.9.1 \
-    --hash=sha256:2c9607871d58c76354b697b42f5d57e1ada7d261c261efac224b664affdc5785 \
-    --hash=sha256:d1735fc58b418fd7c5f658d28d943854f8a849b01a5d0a1e6f3f3fdd0166804b
+pycodestyle==2.10.0 \
+    --hash=sha256:347187bdb476329d98f695c213d7295a846d1152ff4fe9bacb8a9590b8ee7053 \
+    --hash=sha256:8a4eaf0d0495c7395bdab3589ac2db602797d76207242c17d470186815706610
     # via flake8
-pyflakes==2.5.0 \
-    --hash=sha256:4579f67d887f804e67edb544428f264b7b24f435b263c4614f384135cea553d2 \
-    --hash=sha256:491feb020dca48ccc562a8c0cbe8df07ee13078df59813b83959cbdada312ea3
+pyflakes==3.0.1 \
+    --hash=sha256:ec55bf7fe21fff7f1ad2f7da62363d749e2a470500eab1b555334b67aa1ef8cf \
+    --hash=sha256:ec8b276a6b60bd80defed25add7e439881c19e64850afd9b346283d4165fd0fd
     # via flake8
-pyparsing==3.0.9 \
-    --hash=sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb \
-    --hash=sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc
-    # via packaging
-pytest==7.1.3 \
-    --hash=sha256:1377bda3466d70b55e3f5cecfa55bb7cfcf219c7964629b967c37cf0bda818b7 \
-    --hash=sha256:4f365fec2dff9c1162f834d9f18af1ba13062db0c708bf7b946f8a5c76180c39
+pytest==7.2.2 \
+    --hash=sha256:130328f552dcfac0b1cec75c12e3f005619dc5f874f0a06e8ff7263f0ee6225e \
+    --hash=sha256:c99ab0c73aceb050f68929bc93af19ab6db0558791c6a0715723abe9d0ade9d4
     # via
     #   -r requirements.in
     #   pytest-flake8-path
@@ -59,7 +51,3 @@ pytest-randomly==3.12.0 \
     --hash=sha256:d60c2db71ac319aee0fc6c4110a7597d611a8b94a5590918bfa8583f00caccb2 \
     --hash=sha256:f4f2e803daf5d1ba036cc22bf4fe9dbbf99389ec56b00e5cba732fb5c1d07fdd
     # via -r requirements.in
-tomli==2.0.1 \
-    --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \
-    --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f
-    # via pytest
diff --git a/requirements/py37.txt b/requirements/py37.txt
index a6084d2..1176245 100644
--- a/requirements/py37.txt
+++ b/requirements/py37.txt
@@ -1,12 +1,16 @@
 #
-# This file is autogenerated by pip-compile with python 3.7
-# To update, run:
+# This file is autogenerated by pip-compile with Python 3.7
+# by the following command:
 #
 #    requirements/compile.py
 #
-attrs==22.1.0 \
-    --hash=sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6 \
-    --hash=sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c
+attrs==22.2.0 \
+    --hash=sha256:29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836 \
+    --hash=sha256:c9227bfc2f01993c03f68db37d1d15c9690188323c067c641f1a35ca58185f99
+    # via pytest
+exceptiongroup==1.1.1 \
+    --hash=sha256:232c37c63e4f682982c8b6459f33a8981039e5fb8756b2074364e5055c498c9e \
+    --hash=sha256:d484c3090ba2889ae2928419117447a14daf3c1231d5e30d0aae34f354f01785
     # via pytest
 flake8==5.0.4 \
     --hash=sha256:6fbe320aad8d6b95cec8b8e47bc933004678dc63095be98528b7bdd2a9f510db \
@@ -21,26 +25,22 @@ importlib-metadata==4.2.0 ; python_version < "3.8" \
     #   pluggy
     #   pytest
     #   pytest-randomly
-iniconfig==1.1.1 \
-    --hash=sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3 \
-    --hash=sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32
+iniconfig==2.0.0 \
+    --hash=sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3 \
+    --hash=sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374
     # via pytest
 mccabe==0.7.0 \
     --hash=sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325 \
     --hash=sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e
     # via flake8
-packaging==21.3 \
-    --hash=sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb \
-    --hash=sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522
+packaging==23.0 \
+    --hash=sha256:714ac14496c3e68c99c29b00845f7a2b85f3bb6f1078fd9f72fd20f0570002b2 \
+    --hash=sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97
     # via pytest
 pluggy==1.0.0 \
     --hash=sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159 \
     --hash=sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3
     # via pytest
-py==1.11.0 \
-    --hash=sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719 \
-    --hash=sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378
-    # via pytest
 pycodestyle==2.9.1 \
     --hash=sha256:2c9607871d58c76354b697b42f5d57e1ada7d261c261efac224b664affdc5785 \
     --hash=sha256:d1735fc58b418fd7c5f658d28d943854f8a849b01a5d0a1e6f3f3fdd0166804b
@@ -49,13 +49,9 @@ pyflakes==2.5.0 \
     --hash=sha256:4579f67d887f804e67edb544428f264b7b24f435b263c4614f384135cea553d2 \
     --hash=sha256:491feb020dca48ccc562a8c0cbe8df07ee13078df59813b83959cbdada312ea3
     # via flake8
-pyparsing==3.0.9 \
-    --hash=sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb \
-    --hash=sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc
-    # via packaging
-pytest==7.1.3 \
-    --hash=sha256:1377bda3466d70b55e3f5cecfa55bb7cfcf219c7964629b967c37cf0bda818b7 \
-    --hash=sha256:4f365fec2dff9c1162f834d9f18af1ba13062db0c708bf7b946f8a5c76180c39
+pytest==7.2.2 \
+    --hash=sha256:130328f552dcfac0b1cec75c12e3f005619dc5f874f0a06e8ff7263f0ee6225e \
+    --hash=sha256:c99ab0c73aceb050f68929bc93af19ab6db0558791c6a0715723abe9d0ade9d4
     # via
     #   -r requirements.in
     #   pytest-flake8-path
@@ -72,11 +68,11 @@ tomli==2.0.1 \
     --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \
     --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f
     # via pytest
-typing-extensions==4.4.0 \
-    --hash=sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa \
-    --hash=sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e
+typing-extensions==4.5.0 \
+    --hash=sha256:5cb5f4a79139d699607b3ef622a1dedafa84e115ab0024e0d9c044a9479ca7cb \
+    --hash=sha256:fb33085c39dd998ac16d1431ebc293a8b3eedd00fd4a32de0ff79002c19511b4
     # via importlib-metadata
-zipp==3.9.0 \
-    --hash=sha256:3a7af91c3db40ec72dd9d154ae18e008c69efe8ca88dde4f9a731bb82fe2f9eb \
-    --hash=sha256:972cfa31bc2fedd3fa838a51e9bc7e64b7fb725a8c00e7431554311f180e9980
+zipp==3.15.0 \
+    --hash=sha256:112929ad649da941c23de50f356a2b5570c954b65150642bccdd66bf194d224b \
+    --hash=sha256:48904fc76a60e542af151aded95726c1a5c34ed43ab4134b597665c86d7ad556
     # via importlib-metadata
diff --git a/requirements/py38.txt b/requirements/py38.txt
index 8eb3715..a6e9891 100644
--- a/requirements/py38.txt
+++ b/requirements/py38.txt
@@ -1,56 +1,52 @@
 #
-# This file is autogenerated by pip-compile with python 3.8
-# To update, run:
+# This file is autogenerated by pip-compile with Python 3.8
+# by the following command:
 #
 #    requirements/compile.py
 #
-attrs==22.1.0 \
-    --hash=sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6 \
-    --hash=sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c
+attrs==22.2.0 \
+    --hash=sha256:29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836 \
+    --hash=sha256:c9227bfc2f01993c03f68db37d1d15c9690188323c067c641f1a35ca58185f99
     # via pytest
-flake8==5.0.4 \
-    --hash=sha256:6fbe320aad8d6b95cec8b8e47bc933004678dc63095be98528b7bdd2a9f510db \
-    --hash=sha256:7a1cf6b73744f5806ab95e526f6f0d8c01c66d7bbe349562d22dfca20610b248
+exceptiongroup==1.1.1 \
+    --hash=sha256:232c37c63e4f682982c8b6459f33a8981039e5fb8756b2074364e5055c498c9e \
+    --hash=sha256:d484c3090ba2889ae2928419117447a14daf3c1231d5e30d0aae34f354f01785
+    # via pytest
+flake8==6.0.0 \
+    --hash=sha256:3833794e27ff64ea4e9cf5d410082a8b97ff1a06c16aa3d2027339cd0f1195c7 \
+    --hash=sha256:c61007e76655af75e6785a931f452915b371dc48f56efd765247c8fe68f2b181
     # via pytest-flake8-path
-importlib-metadata==5.0.0 \
-    --hash=sha256:da31db32b304314d044d3c12c79bd59e307889b287ad12ff387b3500835fc2ab \
-    --hash=sha256:ddb0e35065e8938f867ed4928d0ae5bf2a53b7773871bfe6bcc7e4fcdc7dea43
+importlib-metadata==6.2.0 \
+    --hash=sha256:8388b74023a138c605fddd0d47cb81dd706232569f56c9aca7d9c7fdb54caeba \
+    --hash=sha256:9127aad2f49d7203e7112098c12b92e4fd1061ccd18548cdfdc49171a8c073cc
     # via pytest-randomly
-iniconfig==1.1.1 \
-    --hash=sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3 \
-    --hash=sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32
+iniconfig==2.0.0 \
+    --hash=sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3 \
+    --hash=sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374
     # via pytest
 mccabe==0.7.0 \
     --hash=sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325 \
     --hash=sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e
     # via flake8
-packaging==21.3 \
-    --hash=sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb \
-    --hash=sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522
+packaging==23.0 \
+    --hash=sha256:714ac14496c3e68c99c29b00845f7a2b85f3bb6f1078fd9f72fd20f0570002b2 \
+    --hash=sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97
     # via pytest
 pluggy==1.0.0 \
     --hash=sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159 \
     --hash=sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3
     # via pytest
-py==1.11.0 \
-    --hash=sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719 \
-    --hash=sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378
-    # via pytest
-pycodestyle==2.9.1 \
-    --hash=sha256:2c9607871d58c76354b697b42f5d57e1ada7d261c261efac224b664affdc5785 \
-    --hash=sha256:d1735fc58b418fd7c5f658d28d943854f8a849b01a5d0a1e6f3f3fdd0166804b
+pycodestyle==2.10.0 \
+    --hash=sha256:347187bdb476329d98f695c213d7295a846d1152ff4fe9bacb8a9590b8ee7053 \
+    --hash=sha256:8a4eaf0d0495c7395bdab3589ac2db602797d76207242c17d470186815706610
     # via flake8
-pyflakes==2.5.0 \
-    --hash=sha256:4579f67d887f804e67edb544428f264b7b24f435b263c4614f384135cea553d2 \
-    --hash=sha256:491feb020dca48ccc562a8c0cbe8df07ee13078df59813b83959cbdada312ea3
+pyflakes==3.0.1 \
+    --hash=sha256:ec55bf7fe21fff7f1ad2f7da62363d749e2a470500eab1b555334b67aa1ef8cf \
+    --hash=sha256:ec8b276a6b60bd80defed25add7e439881c19e64850afd9b346283d4165fd0fd
     # via flake8
-pyparsing==3.0.9 \
-    --hash=sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb \
-    --hash=sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc
-    # via packaging
-pytest==7.1.3 \
-    --hash=sha256:1377bda3466d70b55e3f5cecfa55bb7cfcf219c7964629b967c37cf0bda818b7 \
-    --hash=sha256:4f365fec2dff9c1162f834d9f18af1ba13062db0c708bf7b946f8a5c76180c39
+pytest==7.2.2 \
+    --hash=sha256:130328f552dcfac0b1cec75c12e3f005619dc5f874f0a06e8ff7263f0ee6225e \
+    --hash=sha256:c99ab0c73aceb050f68929bc93af19ab6db0558791c6a0715723abe9d0ade9d4
     # via
     #   -r requirements.in
     #   pytest-flake8-path
@@ -67,7 +63,7 @@ tomli==2.0.1 \
     --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \
     --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f
     # via pytest
-zipp==3.9.0 \
-    --hash=sha256:3a7af91c3db40ec72dd9d154ae18e008c69efe8ca88dde4f9a731bb82fe2f9eb \
-    --hash=sha256:972cfa31bc2fedd3fa838a51e9bc7e64b7fb725a8c00e7431554311f180e9980
+zipp==3.15.0 \
+    --hash=sha256:112929ad649da941c23de50f356a2b5570c954b65150642bccdd66bf194d224b \
+    --hash=sha256:48904fc76a60e542af151aded95726c1a5c34ed43ab4134b597665c86d7ad556
     # via importlib-metadata
diff --git a/requirements/py39.txt b/requirements/py39.txt
index 80f593b..f1f9f30 100644
--- a/requirements/py39.txt
+++ b/requirements/py39.txt
@@ -1,56 +1,52 @@
 #
-# This file is autogenerated by pip-compile with python 3.9
-# To update, run:
+# This file is autogenerated by pip-compile with Python 3.9
+# by the following command:
 #
 #    requirements/compile.py
 #
-attrs==22.1.0 \
-    --hash=sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6 \
-    --hash=sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c
+attrs==22.2.0 \
+    --hash=sha256:29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836 \
+    --hash=sha256:c9227bfc2f01993c03f68db37d1d15c9690188323c067c641f1a35ca58185f99
     # via pytest
-flake8==5.0.4 \
-    --hash=sha256:6fbe320aad8d6b95cec8b8e47bc933004678dc63095be98528b7bdd2a9f510db \
-    --hash=sha256:7a1cf6b73744f5806ab95e526f6f0d8c01c66d7bbe349562d22dfca20610b248
+exceptiongroup==1.1.1 \
+    --hash=sha256:232c37c63e4f682982c8b6459f33a8981039e5fb8756b2074364e5055c498c9e \
+    --hash=sha256:d484c3090ba2889ae2928419117447a14daf3c1231d5e30d0aae34f354f01785
+    # via pytest
+flake8==6.0.0 \
+    --hash=sha256:3833794e27ff64ea4e9cf5d410082a8b97ff1a06c16aa3d2027339cd0f1195c7 \
+    --hash=sha256:c61007e76655af75e6785a931f452915b371dc48f56efd765247c8fe68f2b181
     # via pytest-flake8-path
-importlib-metadata==5.0.0 \
-    --hash=sha256:da31db32b304314d044d3c12c79bd59e307889b287ad12ff387b3500835fc2ab \
-    --hash=sha256:ddb0e35065e8938f867ed4928d0ae5bf2a53b7773871bfe6bcc7e4fcdc7dea43
+importlib-metadata==6.2.0 \
+    --hash=sha256:8388b74023a138c605fddd0d47cb81dd706232569f56c9aca7d9c7fdb54caeba \
+    --hash=sha256:9127aad2f49d7203e7112098c12b92e4fd1061ccd18548cdfdc49171a8c073cc
     # via pytest-randomly
-iniconfig==1.1.1 \
-    --hash=sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3 \
-    --hash=sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32
+iniconfig==2.0.0 \
+    --hash=sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3 \
+    --hash=sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374
     # via pytest
 mccabe==0.7.0 \
     --hash=sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325 \
     --hash=sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e
     # via flake8
-packaging==21.3 \
-    --hash=sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb \
-    --hash=sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522
+packaging==23.0 \
+    --hash=sha256:714ac14496c3e68c99c29b00845f7a2b85f3bb6f1078fd9f72fd20f0570002b2 \
+    --hash=sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97
     # via pytest
 pluggy==1.0.0 \
     --hash=sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159 \
     --hash=sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3
     # via pytest
-py==1.11.0 \
-    --hash=sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719 \
-    --hash=sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378
-    # via pytest
-pycodestyle==2.9.1 \
-    --hash=sha256:2c9607871d58c76354b697b42f5d57e1ada7d261c261efac224b664affdc5785 \
-    --hash=sha256:d1735fc58b418fd7c5f658d28d943854f8a849b01a5d0a1e6f3f3fdd0166804b
+pycodestyle==2.10.0 \
+    --hash=sha256:347187bdb476329d98f695c213d7295a846d1152ff4fe9bacb8a9590b8ee7053 \
+    --hash=sha256:8a4eaf0d0495c7395bdab3589ac2db602797d76207242c17d470186815706610
     # via flake8
-pyflakes==2.5.0 \
-    --hash=sha256:4579f67d887f804e67edb544428f264b7b24f435b263c4614f384135cea553d2 \
-    --hash=sha256:491feb020dca48ccc562a8c0cbe8df07ee13078df59813b83959cbdada312ea3
+pyflakes==3.0.1 \
+    --hash=sha256:ec55bf7fe21fff7f1ad2f7da62363d749e2a470500eab1b555334b67aa1ef8cf \
+    --hash=sha256:ec8b276a6b60bd80defed25add7e439881c19e64850afd9b346283d4165fd0fd
     # via flake8
-pyparsing==3.0.9 \
-    --hash=sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb \
-    --hash=sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc
-    # via packaging
-pytest==7.1.3 \
-    --hash=sha256:1377bda3466d70b55e3f5cecfa55bb7cfcf219c7964629b967c37cf0bda818b7 \
-    --hash=sha256:4f365fec2dff9c1162f834d9f18af1ba13062db0c708bf7b946f8a5c76180c39
+pytest==7.2.2 \
+    --hash=sha256:130328f552dcfac0b1cec75c12e3f005619dc5f874f0a06e8ff7263f0ee6225e \
+    --hash=sha256:c99ab0c73aceb050f68929bc93af19ab6db0558791c6a0715723abe9d0ade9d4
     # via
     #   -r requirements.in
     #   pytest-flake8-path
@@ -67,7 +63,7 @@ tomli==2.0.1 \
     --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \
     --hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f
     # via pytest
-zipp==3.9.0 \
-    --hash=sha256:3a7af91c3db40ec72dd9d154ae18e008c69efe8ca88dde4f9a731bb82fe2f9eb \
-    --hash=sha256:972cfa31bc2fedd3fa838a51e9bc7e64b7fb725a8c00e7431554311f180e9980
+zipp==3.15.0 \
+    --hash=sha256:112929ad649da941c23de50f356a2b5570c954b65150642bccdd66bf194d224b \
+    --hash=sha256:48904fc76a60e542af151aded95726c1a5c34ed43ab4134b597665c86d7ad556
     # via importlib-metadata
diff --git a/setup.cfg b/setup.cfg
index 8a2bb8c..8d58990 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,41 +1,43 @@
 [metadata]
-name = flake8-comprehensions
-version = 3.10.1
+name = flake8_comprehensions
+version = 3.12.0
 description = A flake8 plugin to help you write better list/set/dict comprehensions.
 long_description = file: README.rst
 long_description_content_type = text/x-rst
+url = https://github.com/adamchainz/flake8-comprehensions
 author = Adam Johnson
 author_email = me@adamj.eu
-url = https://github.com/adamchainz/flake8-comprehensions
-project_urls =
-    Changelog = https://github.com/adamchainz/flake8-comprehensions/blob/main/HISTORY.rst
-    Twitter = https://twitter.com/adamchainz
 license = MIT
-keywords = flake8, comprehensions, list comprehension, set comprehension, dict comprehension
+license_file = LICENSE
 classifiers =
     Development Status :: 5 - Production/Stable
     Framework :: Flake8
     Intended Audience :: Developers
     License :: OSI Approved :: MIT License
     Natural Language :: English
-    Programming Language :: Python :: 3 :: Only
     Programming Language :: Python :: 3
+    Programming Language :: Python :: 3 :: Only
     Programming Language :: Python :: 3.7
     Programming Language :: Python :: 3.8
     Programming Language :: Python :: 3.9
     Programming Language :: Python :: 3.10
     Programming Language :: Python :: 3.11
     Typing :: Typed
+keywords = flake8, comprehensions, list comprehension, set comprehension, dict comprehension
+project_urls =
+    Changelog = https://github.com/adamchainz/flake8-comprehensions/blob/main/CHANGELOG.rst
+    Mastodon = https://fosstodon.org/@adamchainz
+    Twitter = https://twitter.com/adamchainz
 
 [options]
-package_dir=
-    =src
 packages = find:
-include_package_data = True
 install_requires =
-    flake8>=3.0,!=3.2.0
-    importlib-metadata ; python_version < "3.8"
+    flake8!=3.2.0,>=3.0
+    importlib-metadata;python_version < "3.8"
 python_requires = >=3.7
+include_package_data = True
+package_dir =
+    =src
 zip_safe = False
 
 [options.packages.find]
diff --git a/src/flake8_comprehensions/__init__.py b/src/flake8_comprehensions/__init__.py
index 27f519b..b18a8ba 100644
--- a/src/flake8_comprehensions/__init__.py
+++ b/src/flake8_comprehensions/__init__.py
@@ -2,7 +2,8 @@ from __future__ import annotations
 
 import ast
 import sys
-from typing import Any, Generator
+from typing import Any
+from typing import Generator
 
 if sys.version_info >= (3, 8):
     from importlib.metadata import version
@@ -42,6 +43,14 @@ class ComprehensionChecker:
         "C415": "C415 Unnecessary subscript reversal of iterable within {func}().",
         "C416": "C416 Unnecessary {type} comprehension - rewrite using {type}().",
         "C417": "C417 Unnecessary use of map - use a {comp} instead.",
+        "C418": (
+            "C418 Unnecessary {type} passed to dict() - "
+            + "remove the outer call to dict()."
+        ),
+        "C419": (
+            "C419 Unnecessary list comprehension passed to {func}() prevents "
+            + "short-circuiting - rewrite as a generator."
+        ),
     }
 
     def run(self) -> Generator[tuple[int, int, str, type[Any]], None, None]:
@@ -88,13 +97,19 @@ class ComprehensionChecker:
                 elif (
                     num_positional_args == 1
                     and isinstance(node.args[0], ast.ListComp)
-                    and node.func.id in ("list", "set")
+                    and node.func.id in ("list", "set", "any", "all")
                 ):
-                    msg_key = {"list": "C411", "set": "C403"}[node.func.id]
+                    msg_key = {
+                        "list": "C411",
+                        "set": "C403",
+                        "any": "C419",
+                        "all": "C419",
+                    }[node.func.id]
+                    msg = self.messages[msg_key].format(func=node.func.id)
                     yield (
                         node.lineno,
                         node.col_offset,
-                        self.messages[msg_key],
+                        msg,
                         type(self),
                     )
 
@@ -116,10 +131,36 @@ class ComprehensionChecker:
                         type(self),
                     )
 
+                elif (
+                    num_positional_args == 1
+                    and num_keyword_args == 0
+                    and isinstance(node.args[0], (ast.Dict, ast.DictComp))
+                    and node.func.id == "dict"
+                ):
+                    if isinstance(node.args[0], ast.Dict):
+                        type_ = "dict"
+                    else:
+                        type_ = "dict comprehension"
+                    yield (
+                        node.lineno,
+                        node.col_offset,
+                        self.messages["C418"].format(type=type_),
+                        type(self),
+                    )
+
                 elif (
                     num_positional_args == 1
                     and isinstance(node.args[0], (ast.Tuple, ast.List))
-                    and node.func.id in ("tuple", "list", "set", "dict")
+                    and (
+                        node.func.id in ("tuple", "list", "set")
+                        or (
+                            node.func.id == "dict"
+                            and all(
+                                isinstance(i, ast.Tuple) and len(i.elts) == 2
+                                for i in node.args[0].elts
+                            )
+                        )
+                    )
                 ):
                     suffix = "rewrite as a {func} literal."
                     msg_key = {
@@ -294,18 +335,31 @@ class ComprehensionChecker:
                             type(self),
                         )
 
-            elif isinstance(node, (ast.ListComp, ast.SetComp)):
+            elif isinstance(node, (ast.DictComp, ast.ListComp, ast.SetComp)):
                 if (
                     len(node.generators) == 1
                     and not node.generators[0].ifs
                     and not node.generators[0].is_async
                     and (
-                        isinstance(node.elt, ast.Name)
-                        and isinstance(node.generators[0].target, ast.Name)
-                        and node.elt.id == node.generators[0].target.id
+                        (
+                            isinstance(node, (ast.ListComp, ast.SetComp))
+                            and isinstance(node.elt, ast.Name)
+                            and isinstance(node.generators[0].target, ast.Name)
+                            and node.elt.id == node.generators[0].target.id
+                        )
+                        or (
+                            isinstance(node, ast.DictComp)
+                            and isinstance(node.key, ast.Name)
+                            and isinstance(node.value, ast.Name)
+                            and isinstance(node.generators[0].target, ast.Tuple)
+                            and len(node.generators[0].target.elts) == 2
+                            and isinstance(node.generators[0].target.elts[0], ast.Name)
+                            and node.generators[0].target.elts[0].id == node.key.id
+                            and isinstance(node.generators[0].target.elts[1], ast.Name)
+                            and node.generators[0].target.elts[1].id == node.value.id
+                        )
                     )
                 ):
-
                     yield (
                         node.lineno,
                         node.col_offset,
diff --git a/tests/test_flake8_comprehensions.py b/tests/test_flake8_comprehensions.py
index 5e9626a..5537cb8 100644
--- a/tests/test_flake8_comprehensions.py
+++ b/tests/test_flake8_comprehensions.py
@@ -289,6 +289,8 @@ def test_C405_fail(code, failures, flake8_path):
     "code",
     [
         "foo = dict(range)",
+        "something = (1, 2); dict([something])",
+        "dict([(1,)])",
     ],
 )
 def test_C406_pass(code, flake8_path):
@@ -757,6 +759,10 @@ def test_C415_fail(code, failures, flake8_path):
 @pytest.mark.parametrize(
     "code",
     [
+        "{x, y for x, y, z in zip('abc', '123', 'def')}",
+        "{y: x for x, y in zip('abc', '123')}",
+        "{x: y for x, (y,) in zip('a', ('1',))}",
+        "{x: z for x, (y,), z in zip('a', ('1',), 'b')}",
         "[str(x) for x in range(5)]",
         "[x + 1 for x in range(5)]",
         "[x for x in range(5) if x % 2]",
@@ -796,6 +802,20 @@ else:
 @pytest.mark.parametrize(
     "code,failures",
     [
+        (
+            "{x: y for x, y in zip(range(5), range(5))}",
+            [
+                "./example.py:1:1: C416 Unnecessary dict comprehension - "
+                + "rewrite using dict().",
+            ],
+        ),
+        (
+            "{x: y for (x, y) in zip(range(5), range(5))}",
+            [
+                "./example.py:1:1: C416 Unnecessary dict comprehension - "
+                + "rewrite using dict().",
+            ],
+        ),
         (
             "[x for x in range(5)]",
             [
@@ -873,3 +893,86 @@ def test_C417_fail(code, failures, flake8_path):
     (flake8_path / "example.py").write_text(dedent(code))
     result = flake8_path.run_flake8()
     assert result.out_lines == failures
+
+
+@pytest.mark.parametrize(
+    "code",
+    [
+        "dict({}, a=1)",
+        "dict({x: 1 for x in range(1)}, a=1)",
+    ],
+)
+def test_C418_pass(code, flake8_path):
+    (flake8_path / "example.py").write_text(dedent(code))
+    result = flake8_path.run_flake8()
+    assert result.out_lines == []
+
+
+@pytest.mark.parametrize(
+    "code,failures",
+    [
+        (
+            "dict({})",
+            [
+                "./example.py:1:1: C418 Unnecessary dict passed to dict() - "
+                + "remove the outer call to dict()."
+            ],
+        ),
+        (
+            "dict({'a': 1})",
+            [
+                "./example.py:1:1: C418 Unnecessary dict passed to dict() - "
+                + "remove the outer call to dict()."
+            ],
+        ),
+        (
+            "dict({'x': 1 for x in range(10)})",
+            [
+                "./example.py:1:1: C418 Unnecessary dict comprehension passed "
+                + "to dict() - remove the outer call to dict()."
+            ],
+        ),
+    ],
+)
+def test_C418_fail(code, failures, flake8_path):
+    (flake8_path / "example.py").write_text(dedent(code))
+    result = flake8_path.run_flake8()
+    assert result.out_lines == failures
+
+
+@pytest.mark.parametrize(
+    "code",
+    [
+        "any(num == 3 for num in range(5))",
+        "all(num == 3 for num in range(5))",
+    ],
+)
+def test_C419_pass(code, flake8_path):
+    (flake8_path / "example.py").write_text(dedent(code))
+    result = flake8_path.run_flake8()
+    assert result.out_lines == []
+
+
+@pytest.mark.parametrize(
+    "code,failures",
+    [
+        (
+            "any([num == 3 for num in range(5)])",
+            [
+                "./example.py:1:1: C419 Unnecessary list comprehension passed "
+                + "to any() prevents short-circuiting - rewrite as a generator."
+            ],
+        ),
+        (
+            "all([num == 3 for num in range(5)])",
+            [
+                "./example.py:1:1: C419 Unnecessary list comprehension passed "
+                + "to all() prevents short-circuiting - rewrite as a generator."
+            ],
+        ),
+    ],
+)
+def test_C419_fail(code, failures, flake8_path):
+    (flake8_path / "example.py").write_text(dedent(code))
+    result = flake8_path.run_flake8()
+    assert result.out_lines == failures
diff --git a/tox.ini b/tox.ini
index 1d2ebc3..bb88516 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,15 +1,17 @@
 [tox]
-isolated_build = True
-envlist =
-    py{37,38,39,310,311}
+requires =
+    tox>=4.2
+env_list =
+    py{311, 310, 39, 38, 37}
 
 [testenv]
+deps =
+    -r requirements/{envname}.txt
+set_env =
+    PYTHONDEVMODE = 1
 commands =
-  python \
-    -W error::ResourceWarning \
-    -W error::DeprecationWarning \
-    -W error::PendingDeprecationWarning \
-    -m pytest {posargs:tests}
-deps = -r requirements/{envname}.txt
-setenv =
-    PYTHONDEVMODE=1
+    python \
+      -W error::ResourceWarning \
+      -W error::DeprecationWarning \
+      -W error::PendingDeprecationWarning \
+      -m pytest {posargs:tests}

Debdiff

[The following lists of changes regard files as different if they have different names, permissions or owners.]

Files in second set of .debs but not in first

-rw-r--r--  root/root   /usr/lib/python3/dist-packages/flake8_comprehensions-3.12.0.dist-info/METADATA
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/flake8_comprehensions-3.12.0.dist-info/RECORD
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/flake8_comprehensions-3.12.0.dist-info/WHEEL
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/flake8_comprehensions-3.12.0.dist-info/entry_points.txt
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/flake8_comprehensions-3.12.0.dist-info/top_level.txt

Files in first set of .debs but not in second

-rw-r--r--  root/root   /usr/lib/python3/dist-packages/flake8_comprehensions-3.10.1.dist-info/METADATA
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/flake8_comprehensions-3.10.1.dist-info/RECORD
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/flake8_comprehensions-3.10.1.dist-info/WHEEL
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/flake8_comprehensions-3.10.1.dist-info/entry_points.txt
-rw-r--r--  root/root   /usr/lib/python3/dist-packages/flake8_comprehensions-3.10.1.dist-info/top_level.txt

No differences were encountered in the control files

More details

Full run details