diff --git a/pkg_resources/__init__.py b/pkg_resources/__init__.py index 630aaa9a42..8f5d1eefc8 100644 --- a/pkg_resources/__init__.py +++ b/pkg_resources/__init__.py @@ -3173,7 +3173,7 @@ def __getattr__(self, attr: str): def __dir__(self): return list( set(super().__dir__()) - | set(attr for attr in self._provider.__dir__() if not attr.startswith('_')) + | {attr for attr in self._provider.__dir__() if not attr.startswith('_')} ) @classmethod diff --git a/pkg_resources/tests/test_pkg_resources.py b/pkg_resources/tests/test_pkg_resources.py index cfc9b16c0f..5812736a41 100644 --- a/pkg_resources/tests/test_pkg_resources.py +++ b/pkg_resources/tests/test_pkg_resources.py @@ -348,7 +348,7 @@ class Environment(str): env = Environment(tmpdir) tmpdir.chmod(stat.S_IRWXU) subs = 'home', 'lib', 'scripts', 'data', 'egg-base' - env.paths = dict((dirname, str(tmpdir / dirname)) for dirname in subs) + env.paths = {dirname: str(tmpdir / dirname) for dirname in subs} list(map(os.mkdir, env.paths.values())) return env diff --git a/pkg_resources/tests/test_resources.py b/pkg_resources/tests/test_resources.py index 70436c0881..32b1c1b713 100644 --- a/pkg_resources/tests/test_resources.py +++ b/pkg_resources/tests/test_resources.py @@ -404,8 +404,7 @@ def test_resolve_conflicts_with_prior(self): with pytest.raises(VersionConflict) as vc: ws.resolve(parse_requirements("Foo\nBar\n")) - msg = "Baz 1.0 is installed but Baz==2.0 is required by " - msg += repr(set(['Bar'])) + msg = f"Baz 1.0 is installed but Baz==2.0 is required by { {'Bar'}!r}" assert vc.value.report() == msg @@ -561,8 +560,8 @@ def testOptionsAndHashing(self): r1 = Requirement.parse("Twisted[foo,bar]>=1.2") r2 = Requirement.parse("Twisted[bar,FOO]>=1.2") assert r1 == r2 - assert set(r1.extras) == set(("foo", "bar")) - assert set(r2.extras) == set(("foo", "bar")) + assert set(r1.extras) == {"foo", "bar"} + assert set(r2.extras) == {"foo", "bar"} assert hash(r1) == hash(r2) assert hash(r1) == hash(( "twisted", diff --git a/ruff.toml b/ruff.toml index 349d22cebd..d08926c6d7 100644 --- a/ruff.toml +++ b/ruff.toml @@ -26,6 +26,7 @@ extend-select = [ # local "ANN2", # missing-return-type-* + "C4", # flake8-comprehensions "PERF", # Perflint "PGH", # pygrep-hooks (blanket-* rules) "PT", # flake8-pytest-style @@ -86,6 +87,9 @@ sections.delayed = ["distutils"] [lint.flake8-annotations] ignore-fully-untyped = true +[lint.flake8-comprehensions] +allow-dict-calls-with-keyword-arguments = true + [format] # Enable preview to get hugged parenthesis unwrapping and other nice surprises # See https://github.com/jaraco/skeleton/pull/133#issuecomment-2239538373 diff --git a/setuptools/_discovery.py b/setuptools/_discovery.py index d1b4a0ee03..d48c870a56 100644 --- a/setuptools/_discovery.py +++ b/setuptools/_discovery.py @@ -10,11 +10,11 @@ def extras_from_dep(dep): markers = packaging.requirements.Requirement(dep).marker._markers except AttributeError: markers = () - return set( + return { marker[2].value for marker in markers if isinstance(marker, tuple) and marker[0].value == 'extra' - ) + } def extras_from_deps(deps): diff --git a/setuptools/command/_requirestxt.py b/setuptools/command/_requirestxt.py index 9029b12514..9e3619099b 100644 --- a/setuptools/command/_requirestxt.py +++ b/setuptools/command/_requirestxt.py @@ -77,11 +77,11 @@ def _move_install_requirements_markers( for r in complex_reqs: extras_require[':' + str(r.marker)].setdefault(r) - expanded_extras = dict( + expanded_extras = { # list(dict.fromkeys(...)) ensures a list of unique strings - (k, list(dict.fromkeys(str(r) for r in map(_clean_req, v)))) + k: list(dict.fromkeys(str(r) for r in map(_clean_req, v))) for k, v in extras_require.items() - ) + } return simple_install_requires, expanded_extras diff --git a/setuptools/command/build_clib.py b/setuptools/command/build_clib.py index f376f4ce4d..92a58f7828 100644 --- a/setuptools/command/build_clib.py +++ b/setuptools/command/build_clib.py @@ -33,14 +33,14 @@ def build_libraries(self, libraries) -> None: "'sources' must be present and must be " "a list of source filenames" ) - sources = sorted(list(sources)) + sources = sorted(sources) log.info("building '%s' library", lib_name) # Make sure everything is the correct type. # obj_deps should be a dictionary of keys as sources # and a list/tuple of files that are its dependencies. - obj_deps = build_info.get('obj_deps', dict()) + obj_deps = build_info.get('obj_deps', {}) if not isinstance(obj_deps, dict): raise DistutilsSetupError( f"in 'libraries' option (library '{lib_name}'), " @@ -51,7 +51,7 @@ def build_libraries(self, libraries) -> None: # Get the global dependencies that are specified by the '' key. # These will go into every source's dependency list. - global_deps = obj_deps.get('', list()) + global_deps = obj_deps.get('', []) if not isinstance(global_deps, (list, tuple)): raise DistutilsSetupError( f"in 'libraries' option (library '{lib_name}'), " @@ -64,7 +64,7 @@ def build_libraries(self, libraries) -> None: for source in sources: src_deps = [source] src_deps.extend(global_deps) - extra_deps = obj_deps.get(source, list()) + extra_deps = obj_deps.get(source, []) if not isinstance(extra_deps, (list, tuple)): raise DistutilsSetupError( f"in 'libraries' option (library '{lib_name}'), " diff --git a/setuptools/command/build_ext.py b/setuptools/command/build_ext.py index af73fff7a5..65bb2c57e2 100644 --- a/setuptools/command/build_ext.py +++ b/setuptools/command/build_ext.py @@ -334,7 +334,7 @@ def __get_stubs_outputs(self): ) # pair each base with the extension pairs = itertools.product(ns_ext_bases, self.__get_output_extensions()) - return list(base + fnext for base, fnext in pairs) + return [base + fnext for base, fnext in pairs] def __get_output_extensions(self): yield '.py' diff --git a/setuptools/dist.py b/setuptools/dist.py index f06298c868..ba648fe503 100644 --- a/setuptools/dist.py +++ b/setuptools/dist.py @@ -779,7 +779,7 @@ def by_order(hook): defined = metadata.entry_points(group=group) filtered = itertools.filterfalse(self._removed, defined) - loaded = map(lambda e: e.load(), filtered) + loaded = (e.load() for e in filtered) for ep in sorted(loaded, key=by_order): ep(self) diff --git a/setuptools/msvc.py b/setuptools/msvc.py index 313a781ae0..c094f778db 100644 --- a/setuptools/msvc.py +++ b/setuptools/msvc.py @@ -35,7 +35,7 @@ class winreg: HKEY_LOCAL_MACHINE = None HKEY_CLASSES_ROOT = None - environ: dict[str, str] = dict() + environ: dict[str, str] = {} class PlatformInfo: diff --git a/setuptools/tests/config/test_expand.py b/setuptools/tests/config/test_expand.py index c5710ec63d..71046d1c1f 100644 --- a/setuptools/tests/config/test_expand.py +++ b/setuptools/tests/config/test_expand.py @@ -29,7 +29,7 @@ def test_glob_relative(tmp_path, monkeypatch): "dir1/dir2/a.ini", } - write_files({k: "" for k in files}, tmp_path) + write_files(dict.fromkeys(files, ""), tmp_path) patterns = ["**/*.txt", "[ab].*", "**/[ac].ini"] monkeypatch.chdir(tmp_path) assert set(expand.glob_relative(patterns)) == files @@ -198,7 +198,7 @@ def test_find_packages(tmp_path, args, pkgs): "other/__init__.py", "dir1/dir2/__init__.py", } - write_files({k: "" for k in files}, tmp_path) + write_files(dict.fromkeys(files, ""), tmp_path) package_dir = {} kwargs = {"root_dir": tmp_path, "fill_package_dir": package_dir, **args} @@ -237,7 +237,7 @@ def test_find_packages(tmp_path, args, pkgs): ], ) def test_fill_package_dir(tmp_path, files, where, expected_package_dir): - write_files({k: "" for k in files}, tmp_path) + write_files(dict.fromkeys(files, ""), tmp_path) pkg_dir = {} kwargs = {"root_dir": tmp_path, "fill_package_dir": pkg_dir, "namespaces": False} pkgs = expand.find_packages(where=where, **kwargs) diff --git a/setuptools/tests/config/test_setupcfg.py b/setuptools/tests/config/test_setupcfg.py index 61af990447..13b065f844 100644 --- a/setuptools/tests/config/test_setupcfg.py +++ b/setuptools/tests/config/test_setupcfg.py @@ -354,11 +354,11 @@ def test_usupported_section(self, tmpdir): dist.parse_config_files() def test_classifiers(self, tmpdir): - expected = set([ + expected = { 'Framework :: Django', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.5', - ]) + } # From file. _, config = fake_env(tmpdir, '[metadata]\nclassifiers = file: classifiers\n') @@ -602,11 +602,11 @@ def test_find_directive(self, tmpdir): make_package_dir('sub_two', dir_package) with get_dist(tmpdir) as dist: - assert set(dist.packages) == set([ + assert set(dist.packages) == { 'fake_package', 'fake_package.sub_two', 'fake_package.sub_one', - ]) + } config.write( '[options]\n' @@ -630,7 +630,7 @@ def test_find_directive(self, tmpdir): ' fake_package.sub_one\n' ) with get_dist(tmpdir) as dist: - assert set(dist.packages) == set(['fake_package', 'fake_package.sub_two']) + assert set(dist.packages) == {'fake_package', 'fake_package.sub_two'} def test_find_namespace_directive(self, tmpdir): dir_package, config = fake_env( diff --git a/setuptools/tests/contexts.py b/setuptools/tests/contexts.py index 3c931bbd4f..6979b01eb0 100644 --- a/setuptools/tests/contexts.py +++ b/setuptools/tests/contexts.py @@ -27,7 +27,7 @@ def environment(**replacements): In a context, patch the environment with replacements. Pass None values to clear the values. """ - saved = dict((key, os.environ[key]) for key in replacements if key in os.environ) + saved = {key: os.environ[key] for key in replacements if key in os.environ} # remove values that are null remove = (key for (key, value) in replacements.items() if value is None) diff --git a/setuptools/tests/environment.py b/setuptools/tests/environment.py index ed5499ef7d..17e1e37a3f 100644 --- a/setuptools/tests/environment.py +++ b/setuptools/tests/environment.py @@ -49,7 +49,7 @@ def run_setup_py(cmd, pypath=None, path=None, data_stream=0, env=None): code directly to prevent accidental behavior issues """ if env is None: - env = dict() + env = {} for envname in os.environ: env[envname] = os.environ[envname] diff --git a/setuptools/tests/test_bdist_egg.py b/setuptools/tests/test_bdist_egg.py index 036167dd95..5a97c31831 100644 --- a/setuptools/tests/test_bdist_egg.py +++ b/setuptools/tests/test_bdist_egg.py @@ -68,6 +68,6 @@ def test_exclude_source_files(self): [dist_name] = os.listdir('dist') dist_filename = os.path.join('dist', dist_name) zip = zipfile.ZipFile(dist_filename) - names = list(zi.filename for zi in zip.filelist) + names = [zi.filename for zi in zip.filelist] assert 'hi.pyc' in names assert 'hi.py' not in names diff --git a/setuptools/tests/test_build_py.py b/setuptools/tests/test_build_py.py index 1e3a660833..cfec93775f 100644 --- a/setuptools/tests/test_build_py.py +++ b/setuptools/tests/test_build_py.py @@ -252,7 +252,7 @@ def test_existing_egg_info(tmpdir_cwd, monkeypatch): assert build_py.data_files # Make sure the list of outputs is actually OK - outputs = map(lambda x: x.replace(os.sep, "/"), build_py.get_outputs()) + outputs = (x.replace(os.sep, "/") for x in build_py.get_outputs()) assert outputs example = str(Path(build_py.build_lib, "mypkg/__init__.py")).replace(os.sep, "/") assert example in outputs diff --git a/setuptools/tests/test_egg_info.py b/setuptools/tests/test_egg_info.py index 3653be096f..1b57d493ba 100644 --- a/setuptools/tests/test_egg_info.py +++ b/setuptools/tests/test_egg_info.py @@ -31,7 +31,7 @@ def env(): env = Environment(env_dir) os.chmod(env_dir, stat.S_IRWXU) subs = 'home', 'lib', 'scripts', 'data', 'egg-base' - env.paths = dict((dirname, os.path.join(env_dir, dirname)) for dirname in subs) + env.paths = {dirname: os.path.join(env_dir, dirname) for dirname in subs} list(map(os.mkdir, env.paths.values())) path.build({ env.paths['home']: { diff --git a/setuptools/tests/test_glob.py b/setuptools/tests/test_glob.py index 8d225a4461..8805e2f663 100644 --- a/setuptools/tests/test_glob.py +++ b/setuptools/tests/test_glob.py @@ -41,5 +41,5 @@ ) def test_glob(monkeypatch, tmpdir, tree, pattern, matches): monkeypatch.chdir(tmpdir) - path.build({name: '' for name in tree.split()}) - assert list(sorted(glob(pattern))) == list(sorted(matches)) + path.build(dict.fromkeys(tree.split(), '')) + assert sorted(glob(pattern)) == sorted(matches) diff --git a/setuptools/tests/test_manifest.py b/setuptools/tests/test_manifest.py index 903a528db0..1fd8efda35 100644 --- a/setuptools/tests/test_manifest.py +++ b/setuptools/tests/test_manifest.py @@ -227,7 +227,7 @@ def get_files(self): def test_no_manifest(self): """Check a missing MANIFEST.in includes only the standard files.""" - assert (default_files - set(['MANIFEST.in'])) == self.get_files() + assert (default_files - {'MANIFEST.in'}) == self.get_files() def test_empty_files(self): """Check an empty MANIFEST.in includes only the standard files.""" @@ -237,7 +237,7 @@ def test_empty_files(self): def test_include(self): """Include extra rst files in the project root.""" self.make_manifest("include *.rst") - files = default_files | set(['testing.rst', '.hidden.rst']) + files = default_files | {'testing.rst', '.hidden.rst'} assert files == self.get_files() def test_exclude(self): @@ -249,45 +249,45 @@ def test_exclude(self): exclude app/*.txt """ ) - files = default_files | set([ml('app/c.rst')]) + files = default_files | {ml('app/c.rst')} assert files == self.get_files() def test_include_multiple(self): """Include with multiple patterns.""" ml = make_local_path self.make_manifest("include app/*.txt app/static/*") - files = default_files | set([ + files = default_files | { ml('app/a.txt'), ml('app/b.txt'), ml('app/static/app.js'), ml('app/static/app.js.map'), ml('app/static/app.css'), ml('app/static/app.css.map'), - ]) + } assert files == self.get_files() def test_graft(self): """Include the whole app/static/ directory.""" ml = make_local_path self.make_manifest("graft app/static") - files = default_files | set([ + files = default_files | { ml('app/static/app.js'), ml('app/static/app.js.map'), ml('app/static/app.css'), ml('app/static/app.css.map'), - ]) + } assert files == self.get_files() def test_graft_glob_syntax(self): """Include the whole app/static/ directory.""" ml = make_local_path self.make_manifest("graft */static") - files = default_files | set([ + files = default_files | { ml('app/static/app.js'), ml('app/static/app.js.map'), ml('app/static/app.css'), ml('app/static/app.css.map'), - ]) + } assert files == self.get_files() def test_graft_global_exclude(self): @@ -299,7 +299,7 @@ def test_graft_global_exclude(self): global-exclude *.map """ ) - files = default_files | set([ml('app/static/app.js'), ml('app/static/app.css')]) + files = default_files | {ml('app/static/app.js'), ml('app/static/app.css')} assert files == self.get_files() def test_global_include(self): @@ -310,13 +310,13 @@ def test_global_include(self): global-include *.rst *.js *.css """ ) - files = default_files | set([ + files = default_files | { '.hidden.rst', 'testing.rst', ml('app/c.rst'), ml('app/static/app.js'), ml('app/static/app.css'), - ]) + } assert files == self.get_files() def test_graft_prune(self): @@ -328,7 +328,7 @@ def test_graft_prune(self): prune app/static """ ) - files = default_files | set([ml('app/a.txt'), ml('app/b.txt'), ml('app/c.rst')]) + files = default_files | {ml('app/a.txt'), ml('app/b.txt'), ml('app/c.rst')} assert files == self.get_files() diff --git a/setuptools/tests/test_sdist.py b/setuptools/tests/test_sdist.py index 19d8ddf6da..cc99992f83 100644 --- a/setuptools/tests/test_sdist.py +++ b/setuptools/tests/test_sdist.py @@ -419,7 +419,7 @@ def test_defaults_case_sensitivity(self, source_dir): # lowercase all names so we can test in a # case-insensitive way to make sure the files # are not included. - manifest = map(lambda x: x.lower(), cmd.filelist.files) + manifest = (x.lower() for x in cmd.filelist.files) assert 'readme.rst' not in manifest, manifest assert 'setup.py' not in manifest, manifest assert 'setup.cfg' not in manifest, manifest diff --git a/setuptools/tests/test_wheel.py b/setuptools/tests/test_wheel.py index f91465084a..a7a71c8fc3 100644 --- a/setuptools/tests/test_wheel.py +++ b/setuptools/tests/test_wheel.py @@ -114,11 +114,11 @@ def build_wheel(extra_file_defs=None, **kwargs): def tree_set(root): - contents = set() - for dirpath, dirnames, filenames in os.walk(root): - for filename in filenames: - contents.add(os.path.join(os.path.relpath(dirpath, root), filename)) - return contents + return { + os.path.join(os.path.relpath(dirpath, root), filename) + for dirpath, dirnames, filenames in os.walk(root) + for filename in filenames + } def flatten_tree(tree): diff --git a/setuptools/wheel.py b/setuptools/wheel.py index 124e01ad2f..a28b1a8374 100644 --- a/setuptools/wheel.py +++ b/setuptools/wheel.py @@ -195,11 +195,11 @@ def for_extra(req): markers = req.marker._markers except AttributeError: markers = () - return set( + return { marker[2].value for marker in markers if isinstance(marker, tuple) and marker[0].value == 'extra' - ) + } install_requires = list( map(raw_req, filter(eval, itertools.filterfalse(for_extra, reqs)))